<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package features

import (
	"k8s.io/apimachinery/pkg/util/runtime"

	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/component-base/featuregate"
)

const (
	// Every feature gate should add method here following this template:
	//
	// // owner: @username
	// // alpha: v1.4
	// MyFeature() bool

	// owner: @tallclair
	// alpha: v1.5
	// beta: v1.6
	// deprecated: v1.18
	//
	// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
	// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
	//
	// This feature is deprecated, and will be removed in v1.22.
	StreamingProxyRedirects featuregate.Feature = "StreamingProxyRedirects"

	// owner: @tallclair
	// alpha: v1.12
	// beta: v1.14
	//
	// ValidateProxyRedirects controls whether the apiserver should validate that redirects are only
	// followed to the same host. Only used if StreamingProxyRedirects is enabled.
	ValidateProxyRedirects featuregate.Feature = "ValidateProxyRedirects"

	// owner: @tallclair
	// alpha: v1.7
	// beta: v1.8
	// GA: v1.12
	//
	// AdvancedAuditing enables a much more general API auditing pipeline, which includes support for
	// pluggable output backends and an audit policy specifying how different requests should be
	// audited.
	AdvancedAuditing featuregate.Feature = "AdvancedAuditing"

	// owner: @ilackams
	// alpha: v1.7
	// beta: v1.16
	//
	// Enables compression of REST responses (GET and LIST only)
	APIResponseCompression featuregate.Feature = "APIResponseCompression"

	// owner: @smarterclayton
	// alpha: v1.8
	// beta: v1.9
	//
	// Allow API clients to retrieve resource lists in chunks rather than
	// all at once.
	APIListChunking featuregate.Feature = "APIListChunking"

	// owner: @apelisse
	// alpha: v1.12
	// beta: v1.13
	// stable: v1.18
	//
	// Allow requests to be processed but not stored, so that
	// validation, merging, mutation can be tested without
	// committing.
	DryRun featuregate.Feature = "DryRun"

	// owner: @caesarxuchao
	// alpha: v1.15
	// beta: v1.16
	//
	// Allow apiservers to show a count of remaining items in the response
	// to a chunking list request.
	RemainingItemCount featuregate.Feature = "RemainingItemCount"

	// owner: @apelisse, @lavalamp
	// alpha: v1.14
	// beta: v1.16
	//
	// Server-side apply. Merging happens on the server.
	ServerSideApply featuregate.Feature = "ServerSideApply"

	// owner: @caesarxuchao
	// alpha: v1.14
	// beta: v1.15
	//
	// Allow apiservers to expose the storage version hash in the discovery
	// document.
	StorageVersionHash featuregate.Feature = "StorageVersionHash"

	// owner: @caesarxuchao @roycaihw
	// alpha: v1.20
	//
	// Enable the storage version API.
	StorageVersionAPI featuregate.Feature = "StorageVersionAPI"

	// owner: @wojtek-t
	// alpha: v1.15
	// beta: v1.16
	// GA: v1.17
	//
	// Enables support for watch bookmark events.
	WatchBookmark featuregate.Feature = "WatchBookmark"

	// owner: @MikeSpreitzer @yue9944882
	// alpha: v1.15
	//
	//
	// Enables managing request concurrency with prioritization and fairness at each server
	APIPriorityAndFairness featuregate.Feature = "APIPriorityAndFairness"

	// owner: @wojtek-t
	// alpha: v1.16
	// beta: v1.20
	//
	// Deprecates and removes SelfLink from ObjectMeta and ListMeta.
	RemoveSelfLink featuregate.Feature = "RemoveSelfLink"

	// owner: @shaloulcy, @wojtek-t
	// alpha: v1.18
	// beta: v1.19
	// GA: v1.20
	//
	// Allows label and field based indexes in apiserver watch cache to accelerate list operations.
	SelectorIndex featuregate.Feature = "SelectorIndex"

	// owner: @liggitt
	// beta: v1.19
	//
	// Allows sending warning headers in API responses.
	WarningHeaders featuregate.Feature = "WarningHeaders"

	// owner: @wojtek-t
	// alpha: v1.20
	//
	// Allows for updating watchcache resource version with progress notify events.
	EfficientWatchResumption featuregate.Feature = "EfficientWatchResumption"

	// owner: @roycaihw
	// alpha: v1.20
	//
	// Assigns each kube-apiserver an ID in a cluster.
	APIServerIdentity featuregate.Feature = "APIServerIdentity"
)

func init() {
	runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates))
}

// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
// To add a new feature, define a key for it above and add it here. The features will be
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
	StreamingProxyRedirects:  {Default: true, PreRelease: featuregate.Deprecated},
	ValidateProxyRedirects:   {Default: true, PreRelease: featuregate.Beta},
	AdvancedAuditing:         {Default: true, PreRelease: featuregate.GA},
	APIResponseCompression:   {Default: true, PreRelease: featuregate.Beta},
	APIListChunking:          {Default: true, PreRelease: featuregate.Beta},
	DryRun:                   {Default: true, PreRelease: featuregate.GA},
	RemainingItemCount:       {Default: true, PreRelease: featuregate.Beta},
	ServerSideApply:          {Default: true, PreRelease: featuregate.Beta},
	StorageVersionHash:       {Default: true, PreRelease: featuregate.Beta},
	StorageVersionAPI:        {Default: false, PreRelease: featuregate.Alpha},
	WatchBookmark:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	APIPriorityAndFairness:   {Default: true, PreRelease: featuregate.Beta},
	RemoveSelfLink:           {Default: true, PreRelease: featuregate.Beta},
	SelectorIndex:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	WarningHeaders:           {Default: true, PreRelease: featuregate.Beta},
	EfficientWatchResumption: {Default: false, PreRelease: featuregate.Alpha},
	APIServerIdentity:        {Default: false, PreRelease: featuregate.Alpha},
}
<commit_msg>Promote efficient watch resumption to beta<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package features

import (
	"k8s.io/apimachinery/pkg/util/runtime"

	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/component-base/featuregate"
)

const (
	// Every feature gate should add method here following this template:
	//
	// // owner: @username
	// // alpha: v1.4
	// MyFeature() bool

	// owner: @tallclair
	// alpha: v1.5
	// beta: v1.6
	// deprecated: v1.18
	//
	// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
	// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
	//
	// This feature is deprecated, and will be removed in v1.22.
	StreamingProxyRedirects featuregate.Feature = "StreamingProxyRedirects"

	// owner: @tallclair
	// alpha: v1.12
	// beta: v1.14
	//
	// ValidateProxyRedirects controls whether the apiserver should validate that redirects are only
	// followed to the same host. Only used if StreamingProxyRedirects is enabled.
	ValidateProxyRedirects featuregate.Feature = "ValidateProxyRedirects"

	// owner: @tallclair
	// alpha: v1.7
	// beta: v1.8
	// GA: v1.12
	//
	// AdvancedAuditing enables a much more general API auditing pipeline, which includes support for
	// pluggable output backends and an audit policy specifying how different requests should be
	// audited.
	AdvancedAuditing featuregate.Feature = "AdvancedAuditing"

	// owner: @ilackams
	// alpha: v1.7
	// beta: v1.16
	//
	// Enables compression of REST responses (GET and LIST only)
	APIResponseCompression featuregate.Feature = "APIResponseCompression"

	// owner: @smarterclayton
	// alpha: v1.8
	// beta: v1.9
	//
	// Allow API clients to retrieve resource lists in chunks rather than
	// all at once.
	APIListChunking featuregate.Feature = "APIListChunking"

	// owner: @apelisse
	// alpha: v1.12
	// beta: v1.13
	// stable: v1.18
	//
	// Allow requests to be processed but not stored, so that
	// validation, merging, mutation can be tested without
	// committing.
	DryRun featuregate.Feature = "DryRun"

	// owner: @caesarxuchao
	// alpha: v1.15
	// beta: v1.16
	//
	// Allow apiservers to show a count of remaining items in the response
	// to a chunking list request.
	RemainingItemCount featuregate.Feature = "RemainingItemCount"

	// owner: @apelisse, @lavalamp
	// alpha: v1.14
	// beta: v1.16
	//
	// Server-side apply. Merging happens on the server.
	ServerSideApply featuregate.Feature = "ServerSideApply"

	// owner: @caesarxuchao
	// alpha: v1.14
	// beta: v1.15
	//
	// Allow apiservers to expose the storage version hash in the discovery
	// document.
	StorageVersionHash featuregate.Feature = "StorageVersionHash"

	// owner: @caesarxuchao @roycaihw
	// alpha: v1.20
	//
	// Enable the storage version API.
	StorageVersionAPI featuregate.Feature = "StorageVersionAPI"

	// owner: @wojtek-t
	// alpha: v1.15
	// beta: v1.16
	// GA: v1.17
	//
	// Enables support for watch bookmark events.
	WatchBookmark featuregate.Feature = "WatchBookmark"

	// owner: @MikeSpreitzer @yue9944882
	// alpha: v1.15
	//
	//
	// Enables managing request concurrency with prioritization and fairness at each server
	APIPriorityAndFairness featuregate.Feature = "APIPriorityAndFairness"

	// owner: @wojtek-t
	// alpha: v1.16
	// beta: v1.20
	//
	// Deprecates and removes SelfLink from ObjectMeta and ListMeta.
	RemoveSelfLink featuregate.Feature = "RemoveSelfLink"

	// owner: @shaloulcy, @wojtek-t
	// alpha: v1.18
	// beta: v1.19
	// GA: v1.20
	//
	// Allows label and field based indexes in apiserver watch cache to accelerate list operations.
	SelectorIndex featuregate.Feature = "SelectorIndex"

	// owner: @liggitt
	// beta: v1.19
	//
	// Allows sending warning headers in API responses.
	WarningHeaders featuregate.Feature = "WarningHeaders"

	// owner: @wojtek-t
	// alpha: v1.20
	// beta: v1.21
	//
	// Allows for updating watchcache resource version with progress notify events.
	EfficientWatchResumption featuregate.Feature = "EfficientWatchResumption"

	// owner: @roycaihw
	// alpha: v1.20
	//
	// Assigns each kube-apiserver an ID in a cluster.
	APIServerIdentity featuregate.Feature = "APIServerIdentity"
)

func init() {
	runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates))
}

// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
// To add a new feature, define a key for it above and add it here. The features will be
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
	StreamingProxyRedirects:  {Default: true, PreRelease: featuregate.Deprecated},
	ValidateProxyRedirects:   {Default: true, PreRelease: featuregate.Beta},
	AdvancedAuditing:         {Default: true, PreRelease: featuregate.GA},
	APIResponseCompression:   {Default: true, PreRelease: featuregate.Beta},
	APIListChunking:          {Default: true, PreRelease: featuregate.Beta},
	DryRun:                   {Default: true, PreRelease: featuregate.GA},
	RemainingItemCount:       {Default: true, PreRelease: featuregate.Beta},
	ServerSideApply:          {Default: true, PreRelease: featuregate.Beta},
	StorageVersionHash:       {Default: true, PreRelease: featuregate.Beta},
	StorageVersionAPI:        {Default: false, PreRelease: featuregate.Alpha},
	WatchBookmark:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	APIPriorityAndFairness:   {Default: true, PreRelease: featuregate.Beta},
	RemoveSelfLink:           {Default: true, PreRelease: featuregate.Beta},
	SelectorIndex:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	WarningHeaders:           {Default: true, PreRelease: featuregate.Beta},
	EfficientWatchResumption: {Default: true, PreRelease: featuregate.Beta},
	APIServerIdentity:        {Default: false, PreRelease: featuregate.Alpha},
}
<|endoftext|>


<commit_before>package signprocessor

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"time"

	"github.com/google/go-github/github"
	"github.com/mrjones/oauth"
	"github.com/zabawaba99/fireauth"
	"github.com/zabawaba99/firego"

	"golang.org/x/oauth2"
)

func EventLoop() {
	data := make(fireauth.Data)
	options := fireauth.Option{
		Admin: true,
	}
	token, _ := fireauth.New(Secrets.FireBaseSecret).CreateToken(data, &options)
	f := firego.New(Config.FireBaseDB, nil)
	f.Auth(token)

	t := oauth.NewConsumer(Secrets.TwitterKey, Secrets.TwitterSecret, oauth.ServiceProvider{
		RequestTokenUrl:   "https://api.twitter.com/oauth/request_token",
		AuthorizeTokenUrl: "https://api.twitter.com/oauth/authorize",
		AccessTokenUrl:    "https://api.twitter.com/oauth/access_token",
	})

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: Secrets.GithubToken},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	gh := github.NewClient(tc)

	notifications := make(chan firego.Event)
	if err := f.Watch(notifications); err != nil {
		log.Fatalf("Error setting up watch: %v", err)
	}

	defer f.StopWatching()
	for event := range notifications {
		if event.Path == "/" && event.Data != nil {
			if users, ok := event.Data.(map[string]interface{})["users"]; ok {
				for uid, d := range users.(map[string]interface{}) {
					details := d.(map[string]interface{})
					if process(uid, details, t, gh) {
						f.Child("users").Child(uid).Remove()
					}
				}
			}
		} else if event.Type == "put" && strings.HasPrefix(event.Path, "/users/") {
			uid := strings.TrimPrefix(event.Path, "/users/")
			if details, ok := event.Data.(map[string]interface{}); ok {
				if process(uid, details, t, gh) {
					f.Child("users").Child(uid).Remove()
				}
			}
		}
	}
	fmt.Printf("Notifications have stopped\n")
}

func process(uid string, details map[string]interface{}, t *oauth.Consumer, gh *github.Client) bool {
	linkProfile := details["linkProfile"].(bool)
	link := details["link"].(string)
	personalPage := details["personalPage"].(string)
	name := details["name"].(string)
	title := details["title"].(string)
	affiliation := details["affiliation"].(string)

	secret := details["twitterSecret"].(string)
	token := details["twitterToken"].(string)
	tclient, err := t.MakeHttpClient(&oauth.AccessToken{Token: token, Secret: secret})
	resp, err := tclient.Get("https://api.twitter.com/1.1/account/verify_credentials.json?skip_status=true&include_entities=false")
	if err != nil {
		log.Printf("Twitter API error: %v processing %s", err, uid)
		return false
	}
	defer resp.Body.Close()

	bits, _ := ioutil.ReadAll(resp.Body)

	var user map[string]interface{}
	json.Unmarshal(bits, &user)
	egg := user["default_profile_image"].(bool)
	created, _ := time.Parse(time.RubyDate, user["created_at"].(string))
	description := user["description"].(string)
	followers := int(user["followers_count"].(float64))
	following := int(user["friends_count"].(float64))
	displayName := user["name"].(string)
	handle := user["screen_name"].(string)
	tweets := int(user["statuses_count"].(float64))
	var url string
	switch user["url"].(type) {
	case string:
		url = user["url"].(string)
	}

	if name == "" {
		log.Printf("No signatory name specified for %s (%s)", uid, handle)
		return false
	}

	if score := Score(handle, displayName, url, created, followers, following, tweets, egg, description, personalPage); score < 0 {
		log.Printf("Not creating pull for %s (%s) due to score %d", uid, handle, score)
		return false
	}

	var linkMd, affiliationMd, titleMd string
	if linkProfile {
		linkMd = fmt.Sprintf("  link: https://twitter.com/%s\n", handle)
	} else if link != "" {
		linkMd = fmt.Sprintf("  link: %s\n", link)
	}
	if affiliation != "" {
		affiliationMd = fmt.Sprintf("  affiliation: \"%s\"\n", affiliation)
	}
	if title != "" {
		titleMd = fmt.Sprintf("  occupation_title: \"%s\"\n", title)
	}
	contents := fmt.Sprintf("---\n  name: \"%s\"\n%s%s%s---", name, linkMd, affiliationMd, titleMd)

	body := fmt.Sprintf(
		"Twitter user: https://twitter.com/%s\n" +
		"Created: %v, Followers: %d, Following: %d, Tweets: %d, Egg: %v\n" +
		"\n" +
		"Twitter profile fields:\n" +
		"Name: %s\n" +
		"Website: %s\n" +
		"Tagline: %s\n" +
		"\n" +
		"Personal page: %s\n" +
		"\n" +
		"Signature file contents:\n" +
		"%s",
		handle,
		created, followers, following, tweets, egg,
		displayName,
		url,
		description,
		personalPage,
		"    " + String.Replace(contents, "\n", "\n    ")
	)

	// Ensure we are forking from a clean state.
	g := gh.Git
	ref, _, err := g.GetRef("neveragaindottech", "neveragaindottech.github.io", "heads/master")
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	refStr := fmt.Sprintf("heads/%s", uid)
	ref.Ref = &refStr
	if _, _, err = g.UpdateRef(Config.GithubUser, "neveragaindottech.github.io", ref, true); err != nil {
		if _, _, err = g.CreateRef(Config.GithubUser, "neveragaindottech.github.io", ref); err != nil {
			log.Printf("Error: %v processing %s", err, uid)
			return false
		}
	}
	baseC, _, err := g.GetCommit(Config.GithubUser, "neveragaindottech.github.io", *ref.Object.SHA)
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	path := fmt.Sprintf("_signatures/%s.md", uid)
	mode := "100644"
	kind := "blob"
	newT, _, err := g.CreateTree(Config.GithubUser, "neveragaindottech.github.io", *baseC.Tree.SHA, []github.TreeEntry{
		{Path: &path, Mode: &mode, Type: &kind, Content: &contents},
	})
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	desc := fmt.Sprintf("SignBot: Add signatory '%s' (%s)", name, handle)
	newC, _, err := g.CreateCommit(Config.GithubUser, "neveragaindottech.github.io", &github.Commit{
		Message: &desc,
		Tree:    newT,
		Parents: []github.Commit{*baseC},
	})
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	if _, _, err = g.UpdateRef(Config.GithubUser, "neveragaindottech.github.io", &github.Reference{
		Ref: &refStr,
		Object: &github.GitObject{
			SHA: newC.SHA,
		},
	}, false); err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	p := gh.PullRequests
	branchName := fmt.Sprintf("%s:%s", Config.GithubUser, uid)
	master := "master"
	_, _, err = p.Create("neveragaindottech", "neveragaindottech.github.io", &github.NewPullRequest{
		Title: &desc,
		Head:  &branchName,
		Base:  &master,
		Body:  &body,
	})
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	fmt.Printf("Processed %s (https://twitter.com/%s)\n", uid, handle)
	return true
}
<commit_msg>use multiline string<commit_after>package signprocessor

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"time"

	"github.com/google/go-github/github"
	"github.com/mrjones/oauth"
	"github.com/zabawaba99/fireauth"
	"github.com/zabawaba99/firego"

	"golang.org/x/oauth2"
)

func EventLoop() {
	data := make(fireauth.Data)
	options := fireauth.Option{
		Admin: true,
	}
	token, _ := fireauth.New(Secrets.FireBaseSecret).CreateToken(data, &options)
	f := firego.New(Config.FireBaseDB, nil)
	f.Auth(token)

	t := oauth.NewConsumer(Secrets.TwitterKey, Secrets.TwitterSecret, oauth.ServiceProvider{
		RequestTokenUrl:   "https://api.twitter.com/oauth/request_token",
		AuthorizeTokenUrl: "https://api.twitter.com/oauth/authorize",
		AccessTokenUrl:    "https://api.twitter.com/oauth/access_token",
	})

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: Secrets.GithubToken},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	gh := github.NewClient(tc)

	notifications := make(chan firego.Event)
	if err := f.Watch(notifications); err != nil {
		log.Fatalf("Error setting up watch: %v", err)
	}

	defer f.StopWatching()
	for event := range notifications {
		if event.Path == "/" && event.Data != nil {
			if users, ok := event.Data.(map[string]interface{})["users"]; ok {
				for uid, d := range users.(map[string]interface{}) {
					details := d.(map[string]interface{})
					if process(uid, details, t, gh) {
						f.Child("users").Child(uid).Remove()
					}
				}
			}
		} else if event.Type == "put" && strings.HasPrefix(event.Path, "/users/") {
			uid := strings.TrimPrefix(event.Path, "/users/")
			if details, ok := event.Data.(map[string]interface{}); ok {
				if process(uid, details, t, gh) {
					f.Child("users").Child(uid).Remove()
				}
			}
		}
	}
	fmt.Printf("Notifications have stopped\n")
}

func process(uid string, details map[string]interface{}, t *oauth.Consumer, gh *github.Client) bool {
	linkProfile := details["linkProfile"].(bool)
	link := details["link"].(string)
	personalPage := details["personalPage"].(string)
	name := details["name"].(string)
	title := details["title"].(string)
	affiliation := details["affiliation"].(string)

	secret := details["twitterSecret"].(string)
	token := details["twitterToken"].(string)
	tclient, err := t.MakeHttpClient(&oauth.AccessToken{Token: token, Secret: secret})
	resp, err := tclient.Get("https://api.twitter.com/1.1/account/verify_credentials.json?skip_status=true&include_entities=false")
	if err != nil {
		log.Printf("Twitter API error: %v processing %s", err, uid)
		return false
	}
	defer resp.Body.Close()

	bits, _ := ioutil.ReadAll(resp.Body)

	var user map[string]interface{}
	json.Unmarshal(bits, &user)
	egg := user["default_profile_image"].(bool)
	created, _ := time.Parse(time.RubyDate, user["created_at"].(string))
	description := user["description"].(string)
	followers := int(user["followers_count"].(float64))
	following := int(user["friends_count"].(float64))
	displayName := user["name"].(string)
	handle := user["screen_name"].(string)
	tweets := int(user["statuses_count"].(float64))
	var url string
	switch user["url"].(type) {
	case string:
		url = user["url"].(string)
	}

	if name == "" {
		log.Printf("No signatory name specified for %s (%s)", uid, handle)
		return false
	}

	if score := Score(handle, displayName, url, created, followers, following, tweets, egg, description, personalPage); score < 0 {
		log.Printf("Not creating pull for %s (%s) due to score %d", uid, handle, score)
		return false
	}

	var linkMd, affiliationMd, titleMd string
	if linkProfile {
		linkMd = fmt.Sprintf("  link: https://twitter.com/%s\n", handle)
	} else if link != "" {
		linkMd = fmt.Sprintf("  link: %s\n", link)
	}
	if affiliation != "" {
		affiliationMd = fmt.Sprintf("  affiliation: \"%s\"\n", affiliation)
	}
	if title != "" {
		titleMd = fmt.Sprintf("  occupation_title: \"%s\"\n", title)
	}
	contents := fmt.Sprintf("---\n  name: \"%s\"\n%s%s%s---", name, linkMd, affiliationMd, titleMd)

	body := fmt.Sprintf(`Twitter user: https://twitter.com/%s
Created: %v, Followers: %d, Following: %d, Tweets: %d, Egg: %v

Twitter profile fields:
Name: %s
Website: %s
Tagline: %s

Personal page: %s

Signature file contents:
%s`,
		handle,
		created, followers, following, tweets, egg,
		displayName,
		url,
		description,
		personalPage,
		"    " + String.Replace(contents, "\n", "\n    ")
	)

	// Ensure we are forking from a clean state.
	g := gh.Git
	ref, _, err := g.GetRef("neveragaindottech", "neveragaindottech.github.io", "heads/master")
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	refStr := fmt.Sprintf("heads/%s", uid)
	ref.Ref = &refStr
	if _, _, err = g.UpdateRef(Config.GithubUser, "neveragaindottech.github.io", ref, true); err != nil {
		if _, _, err = g.CreateRef(Config.GithubUser, "neveragaindottech.github.io", ref); err != nil {
			log.Printf("Error: %v processing %s", err, uid)
			return false
		}
	}
	baseC, _, err := g.GetCommit(Config.GithubUser, "neveragaindottech.github.io", *ref.Object.SHA)
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	path := fmt.Sprintf("_signatures/%s.md", uid)
	mode := "100644"
	kind := "blob"
	newT, _, err := g.CreateTree(Config.GithubUser, "neveragaindottech.github.io", *baseC.Tree.SHA, []github.TreeEntry{
		{Path: &path, Mode: &mode, Type: &kind, Content: &contents},
	})
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	desc := fmt.Sprintf("SignBot: Add signatory '%s' (%s)", name, handle)
	newC, _, err := g.CreateCommit(Config.GithubUser, "neveragaindottech.github.io", &github.Commit{
		Message: &desc,
		Tree:    newT,
		Parents: []github.Commit{*baseC},
	})
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	if _, _, err = g.UpdateRef(Config.GithubUser, "neveragaindottech.github.io", &github.Reference{
		Ref: &refStr,
		Object: &github.GitObject{
			SHA: newC.SHA,
		},
	}, false); err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	p := gh.PullRequests
	branchName := fmt.Sprintf("%s:%s", Config.GithubUser, uid)
	master := "master"
	_, _, err = p.Create("neveragaindottech", "neveragaindottech.github.io", &github.NewPullRequest{
		Title: &desc,
		Head:  &branchName,
		Base:  &master,
		Body:  &body,
	})
	if err != nil {
		log.Printf("Error: %v processing %s", err, uid)
		return false
	}
	fmt.Printf("Processed %s (https://twitter.com/%s)\n", uid, handle)
	return true
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package token

type File struct {
	base     int
	name     string
	src      string
	newlines []Pos
}

func NewFile(name, src string) *File {
	return &File{
		base:     1,
		name:     name,
		src:      src,
		newlines: make([]Pos, 0, 16),
	}
}

func (f *File) AddLine(p Pos) {
	base := Pos(1)
	if p.Valid() && p >= base && p < base+Pos(f.Size()) {
		f.newlines = append(f.newlines, p)
	}
}

func (f *File) Base() int {
	return f.base
}

func (f *File) Pos(offset int) Pos {
	if offset < 0 || offset >= len(f.src) {
		panic("illegal file offset")
	}
	return Pos(f.base + offset)
}

func (f *File) Position(p Pos) Position {
	start := Pos(0)
	col, row := int(p), 1

	for i, nl := range f.newlines {
		if p <= nl {
			col, row = int(p-start), i+1
			break
		}
		start = nl
	}

	return Position{Filename: f.name, Col: col, Row: row}
}

func (f *File) Size() int {
	return len(f.src)
}
<commit_msg>Modify File to track size not src code<commit_after>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package token

type File struct {
	base     int
	name     string
	newlines []Pos
	size     int
}

func NewFile(name string, base, size int) *File {
	return &File{
		base:     base,
		name:     name,
		newlines: make([]Pos, 0, 16),
		size:     size,
	}
}

func (f *File) AddLine(p Pos) {
	base := Pos(1)
	if p.Valid() && p >= base && p < base+Pos(f.Size()) {
		f.newlines = append(f.newlines, p)
	}
}

func (f *File) Base() int {
	return f.base
}

func (f *File) Pos(offset int) Pos {
	if offset < 0 || offset >= f.size {
		panic("illegal file offset")
	}
	return Pos(f.base + offset)
}

func (f *File) Position(p Pos) Position {
	start := Pos(0)
	col, row := int(p), 1

	for i, nl := range f.newlines {
		if p <= nl {
			col, row = int(p-start), i+1
			break
		}
		start = nl
	}

	return Position{Filename: f.name, Col: col, Row: row}
}

func (f *File) Size() int {
	return f.size
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 The SurgeMQ Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package service

import (
	"fmt"
	"io"
	"net"
	"time"

	"github.com/surgemq/message"
)

type netReader interface {
	io.Reader
	SetReadDeadline(t time.Time) error
}

type timeoutReader struct {
	d    time.Duration
	conn netReader
}

func (r timeoutReader) Read(b []byte) (int, error) {
	if err := r.conn.SetReadDeadline(time.Now().Add(r.d)); err != nil {
		return 0, err
	}
	return r.conn.Read(b)
}

// receiver() reads data from the network, and writes the data into the incoming buffer
func (this *service) receiver() {
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) receiver开始", this.cid())
	})
	defer func() {
		// Let's recover from panic
		if r := recover(); r != nil {
			Log.Errorc(func() string {
				return fmt.Sprintf("(%s) Recovering from panic: %v", this.cid(), r)
			})
		}

		this.wgStopped.Done()

		Log.Debugc(func() string {
			return fmt.Sprintf("(%s) Stopping receiver", this.cid())
		})
	}()

	//   Log.Debugc(func() string{ return fmt.Sprintf("(%s) Starting receiver", this.cid())})

	this.wgStarted.Done()

	switch conn := this.conn.(type) {
	case net.Conn:
		//Log.Debugc(func() string{ return fmt.Sprintf("server/handleConnection: Setting read deadline to %d", time.Second*time.Duration(this.keepAlive))})
		keepAlive := time.Second * time.Duration(this.keepAlive)
		r := timeoutReader{
			d:    keepAlive + (keepAlive / 2),
			conn: conn,
		}

		for {
			_, err := this.in.ReadFrom(r)
			//       Log.Errorc(func() string{ return fmt.Sprintf("this.sess is: %v", this.sess)})
			//       Log.Errorc(func() string{ return fmt.Sprintf("this.sessMgr is: %v", this.sessMgr)})

			/*if err != nil {
				Log.Infoc(func() string { return fmt.Sprintf("(%s) error reading from connection: %v", this.cid(), err) })
				//         if err != io.EOF {
				//         }
				return
			}*/
			if err != nil {

				if err == io.EOF {
					Log.Errorc(func() string {
						return fmt.Sprintf("(%s) error reading from connection: %v", this.cid(), err)
					})
					return
				} else {
					Log.Infoc(func() string {
						return fmt.Sprintf("(%s) info reading from connection: %v", this.cid(), err)
					})
				}

				continue
			} else {
				Log.Infoc(func() string {
					return fmt.Sprintf("(%s)向ringbuffer些数据成功！", this.cid())
				})
			}
		}

	//case *websocket.Conn:
	//	Log.Errorc(func() string{ return fmt.Sprintf("(%s) Websocket: %v", this.cid(), ErrInvalidConnectionType)})

	default:
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) %v", this.cid(), ErrInvalidConnectionType)
		})
	}
}

// sender() writes data from the outgoing buffer to the network
func (this *service) sender() {
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) sender开始", this.cid())
	})
	defer func() {
		// Let's recover from panic
		if r := recover(); r != nil {
			Log.Errorc(func() string {
				return fmt.Sprintf("(%s) Recovering from panic: %v", this.cid(), r)
			})
		}

		this.wgStopped.Done()

		Log.Debugc(func() string {
			return fmt.Sprintf("(%s) Stopping sender", this.cid())
		})
	}()

	//   Log.Debugc(func() string{ return fmt.Sprintf("(%s) Starting sender", this.cid())})

	this.wgStarted.Done()

	switch conn := this.conn.(type) {
	case net.Conn:
		for {
			_, err := this.out.WriteTo(conn)

			if err != nil {
				if err != io.EOF {
					Log.Errorc(func() string {
						return fmt.Sprintf("(%s) error writing data: %v", this.cid(), err)
					})
				}
				return
			}
		}

	//case *websocket.Conn:
	//	Log.Errorc(func() string{ return fmt.Sprintf("(%s) Websocket not supported", this.cid())})

	default:
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) Invalid connection type", this.cid())
		})
	}
}

// peekMessageSize() reads, but not commits, enough bytes to determine the size of
// the next message and returns the type and size.
func (this *service) peekMessageSize() (message.Message, int, error) {
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) peekMessageSize开始", this.cid())
	})
	var (
		b   []byte
		err error
		cnt int = 2
	)

	if this.in == nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize this.in is nil", this.cid())
		})
		err = ErrBufferNotReady
		return nil, 0, err
	}

	// Peek cnt bytes from the input buffer.
	b, err = this.in.ReadWait(cnt)
	if err != nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize this.in.ReadWait falure", this.cid())
		})
		return nil, 0, err
	}
	//total := int(remlen) + 1 + m
	mtype := message.MessageType((b)[0] >> 4)
	//return mtype, total, err
	var msg message.Message
	msg, err = mtype.New()
	if err != nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize mtype.New() falure", this.cid())
		})
		return nil, 0, err
	}
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) 开始创建对象(%s)", this.cid(), msg.Name())
	})
	_, err = msg.Decode(b)
	if err != nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize msg.Decode falure", this.cid())
		})
		return nil, 0, err
	}
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) peekMessageSize结束(%s)", this.cid(), msg.Name())
	})
	fmt.Println("this.in.readwait=", msg.Len())
	return msg, len(b), err
}

// peekMessage() reads a message from the buffer, but the bytes are NOT committed.
// This means the buffer still thinks the bytes are not read yet.
/*func (this *service) peekMessage(mtype message.MessageType, total int) (message.Message, int, error) {
	var (
		b    []byte
		err  error
		i, n int
		msg  message.Message
	)

	if this.in == nil {
		return nil, 0, ErrBufferNotReady
	}

	// Peek until we get total bytes
	for i = 0; ; i++ {
		// Peek remlen bytes from the input buffer.
		b, err = this.in.ReadWait(total)
		if err != nil && err != ErrBufferInsufficientData {
			return nil, 0, err
		}

		// If not enough bytes are returned, then continue until there's enough.
		if len(b) >= total {
			break
		}
	}

	msg, err = mtype.New()
	if err != nil {
		return nil, 0, err
	}

	n, err = msg.Decode(b)
	return msg, n, err
}*/

// readMessage() reads and copies a message from the buffer. The buffer bytes are
// committed as a result of the read.
/*
func (this *service) readMessage(mtype message.MessageType, total int) (message.Message, int, error) {
	var (
		b   []byte
		err error
		n   int
		msg message.Message
	)

	if this.in == nil {
		err = ErrBufferNotReady
		return nil, 0, err
	}

	if len(this.intmp) < total {
		this.intmp = make([]byte, total)
	}

	// Read until we get total bytes
	//l := 0
	//for l < total {
	n, err = this.in.Read(this.intmp[0:])
	//l += n
	Log.Debugc(func() string {
		return fmt.Sprintf("read %d bytes", n)
	})
	if err != nil {
		return nil, 0, err
	}
	//}

	b = this.intmp[:total]

	msg, err = mtype.New()
	if err != nil {
		return msg, 0, err
	}

	n, err = msg.Decode(b)
	return msg, n, err
}
*/

// writeMessage() writes a message to the outgoing buffer
func (this *service) writeMessage(msg message.Message) (int, error) {
	var (
		l           int = msg.Len()
		m, n, start int
		err         error
		buf         []byte
		//wrap bool
	)

	if this.out == nil {
		return 0, ErrBufferNotReady
	}

	// This is to serialize writes to the underlying buffer. Multiple goroutines could
	// potentially get here because of calling Publish() or Subscribe() or other
	// functions that will send messages. For example, if a message is received in
	// another connetion, and the message needs to be published to this client, then
	// the Publish() function is called, and at the same time, another client could
	// do exactly the same thing.
	//
	// Not an ideal fix though. If possible we should remove mutex and be lockfree.
	// Mainly because when there's a large number of goroutines that want to publish
	// to this client, then they will all block. However, this will do for now.
	//
	// FIXME: Try to find a better way than a mutex...if possible.
	this.wmu.Lock()
	defer this.wmu.Unlock()

	//buf, wrap, err = this.out.WriteWait(l)//zheliyouwenti
	start, _, err = this.out.waitForWriteSpace(l)
	if err != nil {
		return 0, err
	}
	buf = make([]byte, l)
	n, err = msg.Encode(buf[0:])
	if err != nil {
		return 0, err
	}
	this.out.buf[start] = ByteArray{bArray: buf}
	m, err = this.out.WriteCommit(n)
	if err != nil {
		return 0, err
	}
	/*if wrap {
		if len(this.outtmp) < l {
			this.outtmp = make([]byte, l)
		}

		n, err = msg.Encode(this.outtmp[0:])
		if err != nil {
			return 0, err
		}

		m, err = this.out.Write(this.outtmp[0:n])
		if err != nil {
			return m, err
		}
	} else {
		n, err = msg.Encode(buf[0:])
		if err != nil {
			return 0, err
		}

		m, err = this.out.WriteCommit(n)
		if err != nil {
			return 0, err
		}
	}*/

	this.outStat.increment(int64(m))

	return m, nil
}
<commit_msg>修改了buffer.go;sendrecv.go;process.go<commit_after>// Copyright (c) 2014 The SurgeMQ Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package service

import (
	"fmt"
	"io"
	"net"
	"time"

	"github.com/surgemq/message"
)

type netReader interface {
	io.Reader
	SetReadDeadline(t time.Time) error
}

type timeoutReader struct {
	d    time.Duration
	conn netReader
}

func (r timeoutReader) Read(b []byte) (int, error) {
	if err := r.conn.SetReadDeadline(time.Now().Add(r.d)); err != nil {
		return 0, err
	}
	return r.conn.Read(b)
}

// receiver() reads data from the network, and writes the data into the incoming buffer
func (this *service) receiver() {
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) receiver开始", this.cid())
	})
	defer func() {
		// Let's recover from panic
		if r := recover(); r != nil {
			Log.Errorc(func() string {
				return fmt.Sprintf("(%s) Recovering from panic: %v", this.cid(), r)
			})
		}

		this.wgStopped.Done()

		Log.Debugc(func() string {
			return fmt.Sprintf("(%s) Stopping receiver", this.cid())
		})
	}()

	//   Log.Debugc(func() string{ return fmt.Sprintf("(%s) Starting receiver", this.cid())})

	this.wgStarted.Done()

	switch conn := this.conn.(type) {
	case net.Conn:
		//Log.Debugc(func() string{ return fmt.Sprintf("server/handleConnection: Setting read deadline to %d", time.Second*time.Duration(this.keepAlive))})
		keepAlive := time.Second * time.Duration(this.keepAlive)
		r := timeoutReader{
			d:    keepAlive + (keepAlive / 2),
			conn: conn,
		}

		for {
			_, err := this.in.ReadFrom(r)
			//       Log.Errorc(func() string{ return fmt.Sprintf("this.sess is: %v", this.sess)})
			//       Log.Errorc(func() string{ return fmt.Sprintf("this.sessMgr is: %v", this.sessMgr)})

			/*if err != nil {
				Log.Infoc(func() string { return fmt.Sprintf("(%s) error reading from connection: %v", this.cid(), err) })
				//         if err != io.EOF {
				//         }
				return
			}*/
			if err != nil {

				if err == io.EOF {
					Log.Errorc(func() string {
						return fmt.Sprintf("(%s) error reading from connection: %v", this.cid(), err)
					})
					return
				} else {
					Log.Infoc(func() string {
						return fmt.Sprintf("(%s) info reading from connection: %v", this.cid(), err)
					})
				}

				continue
			} else {
				Log.Infoc(func() string {
					return fmt.Sprintf("(%s)向ringbuffer些数据成功！", this.cid())
				})
			}
		}

	//case *websocket.Conn:
	//	Log.Errorc(func() string{ return fmt.Sprintf("(%s) Websocket: %v", this.cid(), ErrInvalidConnectionType)})

	default:
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) %v", this.cid(), ErrInvalidConnectionType)
		})
	}
}

// sender() writes data from the outgoing buffer to the network
func (this *service) sender() {
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) sender开始", this.cid())
	})
	defer func() {
		// Let's recover from panic
		if r := recover(); r != nil {
			Log.Errorc(func() string {
				return fmt.Sprintf("(%s) Recovering from panic: %v", this.cid(), r)
			})
		}

		this.wgStopped.Done()

		Log.Debugc(func() string {
			return fmt.Sprintf("(%s) Stopping sender", this.cid())
		})
	}()

	//   Log.Debugc(func() string{ return fmt.Sprintf("(%s) Starting sender", this.cid())})

	this.wgStarted.Done()

	switch conn := this.conn.(type) {
	case net.Conn:
		for {
			_, err := this.out.WriteTo(conn)

			if err != nil {
				if err != io.EOF {
					Log.Errorc(func() string {
						return fmt.Sprintf("(%s) error writing data: %v", this.cid(), err)
					})
				}
				return
			}
		}

	//case *websocket.Conn:
	//	Log.Errorc(func() string{ return fmt.Sprintf("(%s) Websocket not supported", this.cid())})

	default:
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) Invalid connection type", this.cid())
		})
	}
}

// peekMessageSize() reads, but not commits, enough bytes to determine the size of
// the next message and returns the type and size.
func (this *service) peekMessageSize() (message.Message, int, error) {
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) peekMessageSize开始", this.cid())
	})
	var (
		b   []byte
		err error
		cnt int = 2
	)

	if this.in == nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize this.in is nil", this.cid())
		})
		err = ErrBufferNotReady
		return nil, 0, err
	}

	// Peek cnt bytes from the input buffer.
	b, err = this.in.ReadWait(cnt)
	if err != nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize this.in.ReadWait falure", this.cid())
		})
		return nil, 0, err
	}
	//total := int(remlen) + 1 + m
	mtype := message.MessageType((b)[0] >> 4)
	//return mtype, total, err
	var msg message.Message
	msg, err = mtype.New()
	if err != nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize mtype.New() falure", this.cid())
		})
		return nil, 0, err
	}
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) 开始创建对象(%s)", this.cid(), msg.Name())
	})
	_, err = msg.Decode(b)
	if err != nil {
		Log.Errorc(func() string {
			return fmt.Sprintf("(%s) peekMessageSize msg.Decode falure", this.cid())
		})
		return nil, 0, err
	}
	Log.Infoc(func() string {
		return fmt.Sprintf("(%s) peekMessageSize结束(%s)", this.cid(), msg.Name())
	})
	fmt.Println("this.in.readwait=", msg.Len())
	return msg, len(b), err
}

// peekMessage() reads a message from the buffer, but the bytes are NOT committed.
// This means the buffer still thinks the bytes are not read yet.
/*func (this *service) peekMessage(mtype message.MessageType, total int) (message.Message, int, error) {
	var (
		b    []byte
		err  error
		i, n int
		msg  message.Message
	)

	if this.in == nil {
		return nil, 0, ErrBufferNotReady
	}

	// Peek until we get total bytes
	for i = 0; ; i++ {
		// Peek remlen bytes from the input buffer.
		b, err = this.in.ReadWait(total)
		if err != nil && err != ErrBufferInsufficientData {
			return nil, 0, err
		}

		// If not enough bytes are returned, then continue until there's enough.
		if len(b) >= total {
			break
		}
	}

	msg, err = mtype.New()
	if err != nil {
		return nil, 0, err
	}

	n, err = msg.Decode(b)
	return msg, n, err
}*/

// readMessage() reads and copies a message from the buffer. The buffer bytes are
// committed as a result of the read.
/*
func (this *service) readMessage(mtype message.MessageType, total int) (message.Message, int, error) {
	var (
		b   []byte
		err error
		n   int
		msg message.Message
	)

	if this.in == nil {
		err = ErrBufferNotReady
		return nil, 0, err
	}

	if len(this.intmp) < total {
		this.intmp = make([]byte, total)
	}

	// Read until we get total bytes
	//l := 0
	//for l < total {
	n, err = this.in.Read(this.intmp[0:])
	//l += n
	Log.Debugc(func() string {
		return fmt.Sprintf("read %d bytes", n)
	})
	if err != nil {
		return nil, 0, err
	}
	//}

	b = this.intmp[:total]

	msg, err = mtype.New()
	if err != nil {
		return msg, 0, err
	}

	n, err = msg.Decode(b)
	return msg, n, err
}
*/

// writeMessage() writes a message to the outgoing buffer
func (this *service) writeMessage(msg message.Message) (int, error) {
	var (
		l           int = msg.Len()
		m, n, start int
		err         error
		buf         []byte
		//wrap bool
	)

	if this.out == nil {
		return 0, ErrBufferNotReady
	}

	// This is to serialize writes to the underlying buffer. Multiple goroutines could
	// potentially get here because of calling Publish() or Subscribe() or other
	// functions that will send messages. For example, if a message is received in
	// another connetion, and the message needs to be published to this client, then
	// the Publish() function is called, and at the same time, another client could
	// do exactly the same thing.
	//
	// Not an ideal fix though. If possible we should remove mutex and be lockfree.
	// Mainly because when there's a large number of goroutines that want to publish
	// to this client, then they will all block. However, this will do for now.
	//
	// FIXME: Try to find a better way than a mutex...if possible.
	this.wmu.Lock()
	defer this.wmu.Unlock()

	//buf, wrap, err = this.out.WriteWait(l)//zheliyouwenti
	start, _, err = this.out.waitForWriteSpace(int64(l))
	if err != nil {
		return 0, err
	}
	buf = make([]byte, l)
	n, err = msg.Encode(buf[0:])
	if err != nil {
		return 0, err
	}
	this.out.buf[start] = ByteArray{bArray: buf}
	m, err = this.out.WriteCommit(n)
	if err != nil {
		return 0, err
	}
	/*if wrap {
		if len(this.outtmp) < l {
			this.outtmp = make([]byte, l)
		}

		n, err = msg.Encode(this.outtmp[0:])
		if err != nil {
			return 0, err
		}

		m, err = this.out.Write(this.outtmp[0:n])
		if err != nil {
			return m, err
		}
	} else {
		n, err = msg.Encode(buf[0:])
		if err != nil {
			return 0, err
		}

		m, err = this.out.WriteCommit(n)
		if err != nil {
			return 0, err
		}
	}*/

	this.outStat.increment(int64(m))

	return m, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package leadermigration

// FilterResult indicates whether and how the controller manager should start the controller.
type FilterResult int32

const (
	// ControllerOwned indicates that the controller is owned by another controller manager
	//  and thus should NOT be started by this controller manager.
	ControllerUnowned = iota
	// ControllerMigrated indicates that the controller manager should start this controller
	//  with thte migration lock.
	ControllerMigrated
	// ControllerNonMigrated indicates that the controller manager should start this controller
	//  with thte main lock.
	ControllerNonMigrated
)

// FilterFunc takes a name of controller, returning a FilterResult indicating how to start controller.
type FilterFunc func(controllerName string) FilterResult
<commit_msg>fix commont of controller manager leadermigration filter<commit_after>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package leadermigration

// FilterResult indicates whether and how the controller manager should start the controller.
type FilterResult int32

const (
	// ControllerUnowned indicates that the controller is owned by another controller manager
	//  and thus should NOT be started by this controller manager.
	ControllerUnowned = iota
	// ControllerMigrated indicates that the controller manager should start this controller
	//  with the migration lock.
	ControllerMigrated
	// ControllerNonMigrated indicates that the controller manager should start this controller
	//  with the main lock.
	ControllerNonMigrated
)

// FilterFunc takes a name of controller, returning a FilterResult indicating how to start controller.
type FilterFunc func(controllerName string) FilterResult
<|endoftext|>


<commit_before>package db

import (
	"github.com/builderscon/octav/octav/tools"
	pdebug "github.com/lestrrat/go-pdebug"
)

func (v *BlogEntryList) LoadByConference(tx *Tx, confID string, status []string) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntryList.LoadByConference %s,%s", confID, status).BindError(&err)
		defer g.End()
	}

	stmt := tools.GetBuffer()
	defer tools.ReleaseBuffer(stmt)

	stmt.WriteString(`SELECT `)
	stmt.WriteString(BlogEntryStdSelectColumns)
	stmt.WriteString(` FROM `)
	stmt.WriteString(BlogEntryTable)
	stmt.WriteString(` WHERE `)
	stmt.WriteString(BlogEntryTable)
	stmt.WriteString(`.conference_id = ? `)

	var args []interface{}
	args = append(args, confID)

	where := tools.GetBuffer()
	defer tools.ReleaseBuffer(where)

	if l := len(status); l > 0 {
		if where.Len() > 0 {
			where.WriteString(` AND`)
		}
		where.WriteString(` status IN (`)
		for i, st := range status {
			where.WriteString(`?`)
			if i < l-1 {
				where.WriteString(`, `)
			}
			args = append(args, st)
		}
		where.WriteString(`)`)
	}

	if where.Len() > 0 {
		where.WriteString(` ORDER BY created_on ASC`)
	}

	where.WriteTo(stmt)

	rows, err := tx.Query(stmt.String(), args...)
	if err != nil {
		return err
	}

	if err := v.FromRows(rows, 0); err != nil {
		return err
	}
	return nil
}
<commit_msg>Update sql<commit_after>package db

import (
	"github.com/builderscon/octav/octav/tools"
	pdebug "github.com/lestrrat/go-pdebug"
)

func (v *BlogEntryList) LoadByConference(tx *Tx, confID string, status []string) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntryList.LoadByConference %s,%s", confID, status).BindError(&err)
		defer g.End()
	}

	stmt := tools.GetBuffer()
	defer tools.ReleaseBuffer(stmt)

	stmt.WriteString(`SELECT `)
	stmt.WriteString(BlogEntryStdSelectColumns)
	stmt.WriteString(` FROM `)
	stmt.WriteString(BlogEntryTable)

	var args []interface{}
	args = append(args, confID)

	where := tools.GetBuffer()
	defer tools.ReleaseBuffer(where)

	where.WriteString(` WHERE `)
	where.WriteString(BlogEntryTable)
	where.WriteString(`.conference_id = ? `)
	if l := len(status); l > 0 {
		if where.Len() > 0 {
			where.WriteString(` AND`)
		}
		where.WriteString(BlogEntryTable)
		where.WriteString(`.status IN (`)
		for i, st := range status {
			where.WriteString(`?`)
			if i < l-1 {
				where.WriteString(`, `)
			}
			args = append(args, st)
		}
		where.WriteString(`)`)
	}

	if where.Len() > 0 {
		where.WriteString(` ORDER BY created_on ASC`)
	}

	where.WriteTo(stmt)

	rows, err := tx.Query(stmt.String(), args...)
	if err != nil {
		return err
	}

	if err := v.FromRows(rows, 0); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

gorcon/track (lee8oi)

*/

//
package track

import (
	"fmt"
	"strings"
)

type game struct {
	Name, Ranked, Balance, Map, Mode, Round, Players, Joining,
	Ntickets, Nsize, Rtickets, Rsize, Elapsed, Remaining string
}

//update parses the data string and updates the server data in the current game object.
func (g *game) update(data string) {
	if len(data) > 1 {
		splitLine := strings.Split(data, "\t")
		mode := strings.Split(splitLine[20], "_")[1]
		if len(splitLine) < 27 {
			return
		}
		*g = game{
			Name:      splitLine[7],
			Ranked:    splitLine[25],
			Balance:   splitLine[24],
			Map:       mapName(splitLine[5]),
			Mode:      strings.ToUpper(mode),
			Round:     splitLine[31],
			Players:   splitLine[3],
			Joining:   splitLine[4],
			Ntickets:  splitLine[11],
			Nsize:     splitLine[26],
			Rtickets:  splitLine[16],
			Rsize:     splitLine[27],
			Elapsed:   splitLine[18],
			Remaining: splitLine[19],
		}
	}
	if err := writeJSON("game.json", g); err != nil {
		fmt.Println(err)
	}
}

//MapName returns the full name for the specified map.
func mapName(name string) string {
	switch name {
	case "dependant_day":
		return "Inland Invasion"
	case "dependant_day_night":
		return "Inland Invasion Night"
	case "heat":
		return "Riverside Rush"
	case "heat_snow":
		return "Riverside Rush Snow"
	case "lake":
		return "Buccaneer Bay"
	case "lake_night":
		return "Buccaneer Bay Night"
	case "lake_snow":
		return "Buccaneer Bay Snow"
	case "lunar":
		return "Lunar Landing"
	case "mayhem":
		return "Sunset Showdown"
	case "river":
		return "Fortress Frenzy"
	case "royal_rumble":
		return "Perilous Port Night"
	case "royal_rumble_day":
		return "Perilous Port Day"
	case "royal_rumble_snow":
		return "Perilous Port Snow"
	case "ruin":
		return "Midnight Mayhem"
	case "ruin_day":
		return "Morning Mayhem"
	case "ruin_snow":
		return "Midnight Mayhem Snow"
	case "seaside_skirmish":
		return "Seaside Skirmish"
	case "seaside_skirmish_night":
		return "Seaside Skirmish Night"
	case "smack2":
		return "Coastal Clash"
	case "smack2_night":
		return "Coastal Clash Night"
	case "smack2_snow":
		return "Coastal Clash Snow"
	case "village":
		return "Victory Village"
	case "village_snow":
		return "Victory Village Snow"
	case "wicked_wake":
		return "Wicked Wake"
	case "woodlands":
		return "Alpine Assault"
	case "woodlands_snow":
		return "Alpine Assault Snow"
	default:
		return name
	}
}
<commit_msg>Modified game.update in attempt to fix an elusive index out of range error.<commit_after>/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

gorcon/track (lee8oi)

*/

//
package track

import (
	"fmt"
	"strings"
)

type game struct {
	Name, Ranked, Balance, Map, Mode, Round, Players, Joining,
	Ntickets, Nsize, Rtickets, Rsize, Elapsed, Remaining string
}

//update parses the data string and updates the server data in the current game object.
func (g *game) update(data string) {
	splitLine := strings.Split(data, "\t")
	if len(splitLine) >= 27 {
		mode := strings.Split(splitLine[20], "_")[1]
		*g = game{
			Name:      splitLine[7],
			Ranked:    splitLine[25],
			Balance:   splitLine[24],
			Map:       mapName(splitLine[5]),
			Mode:      strings.ToUpper(mode),
			Round:     splitLine[31],
			Players:   splitLine[3],
			Joining:   splitLine[4],
			Ntickets:  splitLine[11],
			Nsize:     splitLine[26],
			Rtickets:  splitLine[16],
			Rsize:     splitLine[27],
			Elapsed:   splitLine[18],
			Remaining: splitLine[19],
		}
		if err := writeJSON("game.json", g); err != nil {
			fmt.Println(err)
		}
	}
}

//MapName returns the full name for the specified map.
func mapName(name string) string {
	switch name {
	case "dependant_day":
		return "Inland Invasion"
	case "dependant_day_night":
		return "Inland Invasion Night"
	case "heat":
		return "Riverside Rush"
	case "heat_snow":
		return "Riverside Rush Snow"
	case "lake":
		return "Buccaneer Bay"
	case "lake_night":
		return "Buccaneer Bay Night"
	case "lake_snow":
		return "Buccaneer Bay Snow"
	case "lunar":
		return "Lunar Landing"
	case "mayhem":
		return "Sunset Showdown"
	case "river":
		return "Fortress Frenzy"
	case "royal_rumble":
		return "Perilous Port Night"
	case "royal_rumble_day":
		return "Perilous Port Day"
	case "royal_rumble_snow":
		return "Perilous Port Snow"
	case "ruin":
		return "Midnight Mayhem"
	case "ruin_day":
		return "Morning Mayhem"
	case "ruin_snow":
		return "Midnight Mayhem Snow"
	case "seaside_skirmish":
		return "Seaside Skirmish"
	case "seaside_skirmish_night":
		return "Seaside Skirmish Night"
	case "smack2":
		return "Coastal Clash"
	case "smack2_night":
		return "Coastal Clash Night"
	case "smack2_snow":
		return "Coastal Clash Snow"
	case "village":
		return "Victory Village"
	case "village_snow":
		return "Victory Village Snow"
	case "wicked_wake":
		return "Wicked Wake"
	case "woodlands":
		return "Alpine Assault"
	case "woodlands_snow":
		return "Alpine Assault Snow"
	default:
		return name
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

// EntryMode the type of the object in the git tree
type EntryMode int

// There are only a few file modes in Git. They look like unix file modes, but they can only be
// one of these.
const (
	// EntryModeBlob
	EntryModeBlob EntryMode = 0100644
	// EntryModeExec
	EntryModeExec EntryMode = 0100755
	// EntryModeSymlink
	EntryModeSymlink EntryMode = 0120000
	// EntryModeCommit
	EntryModeCommit EntryMode = 0160000
	// EntryModeTree
	EntryModeTree EntryMode = 0040000
)

// TreeEntry the leaf in the git tree
type TreeEntry struct {
	ID   SHA1
	Type ObjectType

	mode EntryMode
	name string

	ptree *Tree

	commited bool

	size  int64
	sized bool
}

// Name returns the name of the entry
func (te *TreeEntry) Name() string {
	return te.name
}

// Size returns the size of the entry
func (te *TreeEntry) Size() int64 {
	if te.IsDir() {
		return 0
	} else if te.sized {
		return te.size
	}

	stdout, err := NewCommand("cat-file", "-s", te.ID.String()).RunInDir(te.ptree.repo.Path)
	if err != nil {
		return 0
	}

	te.sized = true
	te.size, _ = strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
	return te.size
}

// IsSubModule if the entry is a sub module
func (te *TreeEntry) IsSubModule() bool {
	return te.mode == EntryModeCommit
}

// IsDir if the entry is a sub dir
func (te *TreeEntry) IsDir() bool {
	return te.mode == EntryModeTree
}

// IsLink if the entry is a symlink
func (te *TreeEntry) IsLink() bool {
	return te.mode == EntryModeSymlink
}

// Blob retrun the blob object the entry
func (te *TreeEntry) Blob() *Blob {
	return &Blob{
		repo:      te.ptree.repo,
		TreeEntry: te,
	}
}

// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
func (te *TreeEntry) GetSubJumpablePathName() string {
	if te.IsSubModule() || !te.IsDir() {
		return ""
	}
	tree, err := te.ptree.SubTree(te.name)
	if err != nil {
		return te.name
	}
	entries, _ := tree.ListEntries()
	if len(entries) == 1 && entries[0].IsDir() {
		name := entries[0].GetSubJumpablePathName()
		if name != "" {
			return te.name + "/" + name
		}
	}
	return te.name
}

// Entries a list of entry
type Entries []*TreeEntry

var sorter = []func(t1, t2 *TreeEntry) bool{
	func(t1, t2 *TreeEntry) bool {
		return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule()
	},
	func(t1, t2 *TreeEntry) bool {
		return t1.name < t2.name
	},
}

func (tes Entries) Len() int      { return len(tes) }
func (tes Entries) Swap(i, j int) { tes[i], tes[j] = tes[j], tes[i] }
func (tes Entries) Less(i, j int) bool {
	t1, t2 := tes[i], tes[j]
	var k int
	for k = 0; k < len(sorter)-1; k++ {
		s := sorter[k]
		switch {
		case s(t1, t2):
			return true
		case s(t2, t1):
			return false
		}
	}
	return sorter[k](t1, t2)
}

// Sort sort the list of entry
func (tes Entries) Sort() {
	sort.Sort(tes)
}

// getCommitInfoState transient state for getting commit info for entries
type getCommitInfoState struct {
	entries        map[string]*TreeEntry // map from filepath to entry
	commits        map[string]*Commit    // map from entry name to commit
	lastCommitHash string
	lastCommit     *Commit
	treePath       string
	headCommit     *Commit
	nextSearchSize int // next number of commits to search for
}

func initGetCommitInfoState(entries Entries, headCommit *Commit, treePath string) *getCommitInfoState {
	entriesByPath := make(map[string]*TreeEntry, len(entries))
	for _, entry := range entries {
		entriesByPath[filepath.Join(treePath, entry.Name())] = entry
	}
	return &getCommitInfoState{
		entries:        entriesByPath,
		commits:        make(map[string]*Commit, len(entriesByPath)),
		treePath:       treePath,
		headCommit:     headCommit,
		nextSearchSize: 16,
	}
}

// GetCommitsInfo gets information of all commits that are corresponding to these entries
func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interface{}, error) {
	state := initGetCommitInfoState(tes, commit, treePath)
	if err := getCommitsInfo(state); err != nil {
		return nil, err
	}

	commitsInfo := make([][]interface{}, len(tes))
	for i, entry := range tes {
		commit = state.commits[filepath.Join(treePath, entry.Name())]
		switch entry.Type {
		case ObjectCommit:
			subModuleURL := ""
			if subModule, err := state.headCommit.GetSubModule(entry.Name()); err != nil {
				return nil, err
			} else if subModule != nil {
				subModuleURL = subModule.URL
			}
			subModuleFile := NewSubModuleFile(commit, subModuleURL, entry.ID.String())
			commitsInfo[i] = []interface{}{entry, subModuleFile}
		default:
			commitsInfo[i] = []interface{}{entry, commit}
		}
	}
	return commitsInfo, nil
}

func (state *getCommitInfoState) nextCommit(hash string) {
	state.lastCommitHash = hash
	state.lastCommit = nil
}

func (state *getCommitInfoState) commit() (*Commit, error) {
	var err error
	if state.lastCommit == nil {
		state.lastCommit, err = state.headCommit.repo.GetCommit(state.lastCommitHash)
	}
	return state.lastCommit, err
}

func (state *getCommitInfoState) update(path string) error {
	relPath, err := filepath.Rel(state.treePath, path)
	if err != nil {
		return nil
	}
	var entryPath string
	if index := strings.IndexRune(relPath, os.PathSeparator); index >= 0 {
		entryPath = filepath.Join(state.treePath, relPath[:index])
	} else {
		entryPath = path
	}
	if _, ok := state.entries[entryPath]; !ok {
		return nil
	} else if _, ok := state.commits[entryPath]; ok {
		return nil
	}
	state.commits[entryPath], err = state.commit()
	return err
}

func getCommitsInfo(state *getCommitInfoState) error {
	for len(state.entries) > len(state.commits) {
		if err := getNextCommitInfos(state); err != nil {
			return err
		}
	}
	return nil
}

func getNextCommitInfos(state *getCommitInfoState) error {
	logOutput, err := logCommand(state.lastCommitHash, state).RunInDir(state.headCommit.repo.Path)
	if err != nil {
		return err
	}
	lines := strings.Split(logOutput, "\n")
	i := 0
	for i < len(lines) {
		state.nextCommit(lines[i])
		i++
		for ; i < len(lines); i++ {
			path := lines[i]
			if path == "" {
				break
			}
			if path[0] == '"' {
				path, err = strconv.Unquote(path)
				if err != nil {
					return fmt.Errorf("Unquote: %v", err)
				}
			}
			state.update(path)
		}
		i++ // skip blank line
		if len(state.entries) == len(state.commits) {
			break
		}
	}
	return nil
}

func logCommand(exclusiveStartHash string, state *getCommitInfoState) *Command {
	var commitHash string
	if len(exclusiveStartHash) == 0 {
		commitHash = state.headCommit.ID.String()
	} else {
		commitHash = exclusiveStartHash + "^"
	}
	var command *Command
	numRemainingEntries := len(state.entries) - len(state.commits)
	if numRemainingEntries < 32 {
		searchSize := (numRemainingEntries + 1) / 2
		command = NewCommand("log", prettyLogFormat, "--name-only",
			"-"+strconv.Itoa(searchSize), commitHash, "--")
		for path, entry := range state.entries {
			if _, ok := state.commits[entry.Name()]; !ok {
				command.AddArguments(path)
			}
		}
	} else {
		command = NewCommand("log", prettyLogFormat, "--name-only",
			"-"+strconv.Itoa(state.nextSearchSize), commitHash, "--", state.treePath)
	}
	state.nextSearchSize += state.nextSearchSize
	return command
}
<commit_msg>Fix bug in GetCommitInfos (#66)<commit_after>// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

// EntryMode the type of the object in the git tree
type EntryMode int

// There are only a few file modes in Git. They look like unix file modes, but they can only be
// one of these.
const (
	// EntryModeBlob
	EntryModeBlob EntryMode = 0100644
	// EntryModeExec
	EntryModeExec EntryMode = 0100755
	// EntryModeSymlink
	EntryModeSymlink EntryMode = 0120000
	// EntryModeCommit
	EntryModeCommit EntryMode = 0160000
	// EntryModeTree
	EntryModeTree EntryMode = 0040000
)

// TreeEntry the leaf in the git tree
type TreeEntry struct {
	ID   SHA1
	Type ObjectType

	mode EntryMode
	name string

	ptree *Tree

	commited bool

	size  int64
	sized bool
}

// Name returns the name of the entry
func (te *TreeEntry) Name() string {
	return te.name
}

// Size returns the size of the entry
func (te *TreeEntry) Size() int64 {
	if te.IsDir() {
		return 0
	} else if te.sized {
		return te.size
	}

	stdout, err := NewCommand("cat-file", "-s", te.ID.String()).RunInDir(te.ptree.repo.Path)
	if err != nil {
		return 0
	}

	te.sized = true
	te.size, _ = strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
	return te.size
}

// IsSubModule if the entry is a sub module
func (te *TreeEntry) IsSubModule() bool {
	return te.mode == EntryModeCommit
}

// IsDir if the entry is a sub dir
func (te *TreeEntry) IsDir() bool {
	return te.mode == EntryModeTree
}

// IsLink if the entry is a symlink
func (te *TreeEntry) IsLink() bool {
	return te.mode == EntryModeSymlink
}

// Blob retrun the blob object the entry
func (te *TreeEntry) Blob() *Blob {
	return &Blob{
		repo:      te.ptree.repo,
		TreeEntry: te,
	}
}

// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
func (te *TreeEntry) GetSubJumpablePathName() string {
	if te.IsSubModule() || !te.IsDir() {
		return ""
	}
	tree, err := te.ptree.SubTree(te.name)
	if err != nil {
		return te.name
	}
	entries, _ := tree.ListEntries()
	if len(entries) == 1 && entries[0].IsDir() {
		name := entries[0].GetSubJumpablePathName()
		if name != "" {
			return te.name + "/" + name
		}
	}
	return te.name
}

// Entries a list of entry
type Entries []*TreeEntry

var sorter = []func(t1, t2 *TreeEntry) bool{
	func(t1, t2 *TreeEntry) bool {
		return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule()
	},
	func(t1, t2 *TreeEntry) bool {
		return t1.name < t2.name
	},
}

func (tes Entries) Len() int      { return len(tes) }
func (tes Entries) Swap(i, j int) { tes[i], tes[j] = tes[j], tes[i] }
func (tes Entries) Less(i, j int) bool {
	t1, t2 := tes[i], tes[j]
	var k int
	for k = 0; k < len(sorter)-1; k++ {
		s := sorter[k]
		switch {
		case s(t1, t2):
			return true
		case s(t2, t1):
			return false
		}
	}
	return sorter[k](t1, t2)
}

// Sort sort the list of entry
func (tes Entries) Sort() {
	sort.Sort(tes)
}

// getCommitInfoState transient state for getting commit info for entries
type getCommitInfoState struct {
	entries        map[string]*TreeEntry // map from filepath to entry
	commits        map[string]*Commit    // map from entry name to commit
	lastCommitHash string
	lastCommit     *Commit
	treePath       string
	headCommit     *Commit
	nextSearchSize int // next number of commits to search for
}

func initGetCommitInfoState(entries Entries, headCommit *Commit, treePath string) *getCommitInfoState {
	entriesByPath := make(map[string]*TreeEntry, len(entries))
	for _, entry := range entries {
		entriesByPath[filepath.Join(treePath, entry.Name())] = entry
	}
	return &getCommitInfoState{
		entries:        entriesByPath,
		commits:        make(map[string]*Commit, len(entriesByPath)),
		treePath:       treePath,
		headCommit:     headCommit,
		nextSearchSize: 16,
	}
}

// GetCommitsInfo gets information of all commits that are corresponding to these entries
func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interface{}, error) {
	state := initGetCommitInfoState(tes, commit, treePath)
	if err := getCommitsInfo(state); err != nil {
		return nil, err
	}

	commitsInfo := make([][]interface{}, len(tes))
	for i, entry := range tes {
		commit = state.commits[filepath.Join(treePath, entry.Name())]
		switch entry.Type {
		case ObjectCommit:
			subModuleURL := ""
			if subModule, err := state.headCommit.GetSubModule(entry.Name()); err != nil {
				return nil, err
			} else if subModule != nil {
				subModuleURL = subModule.URL
			}
			subModuleFile := NewSubModuleFile(commit, subModuleURL, entry.ID.String())
			commitsInfo[i] = []interface{}{entry, subModuleFile}
		default:
			commitsInfo[i] = []interface{}{entry, commit}
		}
	}
	return commitsInfo, nil
}

func (state *getCommitInfoState) nextCommit(hash string) {
	state.lastCommitHash = hash
	state.lastCommit = nil
}

func (state *getCommitInfoState) commit() (*Commit, error) {
	var err error
	if state.lastCommit == nil {
		state.lastCommit, err = state.headCommit.repo.GetCommit(state.lastCommitHash)
	}
	return state.lastCommit, err
}

func (state *getCommitInfoState) update(path string) error {
	relPath, err := filepath.Rel(state.treePath, path)
	if err != nil {
		return nil
	}
	var entryPath string
	if index := strings.IndexRune(relPath, os.PathSeparator); index >= 0 {
		entryPath = filepath.Join(state.treePath, relPath[:index])
	} else {
		entryPath = path
	}
	if _, ok := state.entries[entryPath]; !ok {
		return nil
	} else if _, ok := state.commits[entryPath]; ok {
		return nil
	}
	state.commits[entryPath], err = state.commit()
	return err
}

func getCommitsInfo(state *getCommitInfoState) error {
	for len(state.entries) > len(state.commits) {
		if err := getNextCommitInfos(state); err != nil {
			return err
		}
	}
	return nil
}

func getNextCommitInfos(state *getCommitInfoState) error {
	logOutput, err := logCommand(state.lastCommitHash, state).RunInDir(state.headCommit.repo.Path)
	if err != nil {
		return err
	}
	lines := strings.Split(logOutput, "\n")
	i := 0
	for i < len(lines) {
		state.nextCommit(lines[i])
		i++
		for ; i < len(lines); i++ {
			path := lines[i]
			if path == "" {
				break
			}
			if path[0] == '"' {
				path, err = strconv.Unquote(path)
				if err != nil {
					return fmt.Errorf("Unquote: %v", err)
				}
			}
			state.update(path)
		}
		i++ // skip blank line
		if len(state.entries) == len(state.commits) {
			break
		}
	}
	return nil
}

func logCommand(exclusiveStartHash string, state *getCommitInfoState) *Command {
	var commitHash string
	if len(exclusiveStartHash) == 0 {
		commitHash = state.headCommit.ID.String()
	} else {
		commitHash = exclusiveStartHash + "^"
	}
	var command *Command
	numRemainingEntries := len(state.entries) - len(state.commits)
	if numRemainingEntries < 32 {
		searchSize := (numRemainingEntries + 1) / 2
		command = NewCommand("log", prettyLogFormat, "--name-only",
			"-"+strconv.Itoa(searchSize), commitHash, "--")
		for path := range state.entries {
			if _, ok := state.commits[path]; !ok {
				command.AddArguments(path)
			}
		}
	} else {
		command = NewCommand("log", prettyLogFormat, "--name-only",
			"-"+strconv.Itoa(state.nextSearchSize), commitHash, "--", state.treePath)
	}
	state.nextSearchSize += state.nextSearchSize
	return command
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"fmt"
	"path"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

// EntryMode is the unix file mode of a tree entry.
type EntryMode int

// There are only a few file modes in Git. They look like unix file modes, but they can only be
// one of these.
const (
	EntryTree    EntryMode = 0040000
	EntryBlob    EntryMode = 0100644
	EntryExec    EntryMode = 0100755
	EntrySymlink EntryMode = 0120000
	EntryCommit  EntryMode = 0160000
)

type TreeEntry struct {
	mode EntryMode
	typ  ObjectType
	id   *SHA1
	name string

	parent *Tree

	size     int64
	sizeOnce sync.Once
}

// Mode returns the entry mode if the tree entry.
func (e *TreeEntry) Mode() EntryMode {
	return e.mode
}

// IsTree returns tree if the entry itself is another tree (i.e. a directory).
func (e *TreeEntry) IsTree() bool {
	return e.mode == EntryTree
}

// IsBlob returns true if the entry is a blob.
func (e *TreeEntry) IsBlob() bool {
	return e.mode == EntryBlob
}

// IsExec returns tree if the entry is an executable.
func (e *TreeEntry) IsExec() bool {
	return e.mode == EntryExec
}

// IsSymlink returns true if the entry is a symbolic link.
func (e *TreeEntry) IsSymlink() bool {
	return e.mode == EntrySymlink
}

// IsCommit returns true if the entry is a commit (i.e. a submodule).
func (e *TreeEntry) IsCommit() bool {
	return e.mode == EntryCommit
}

// Type returns the object type of the entry.
func (e *TreeEntry) Type() ObjectType {
	return e.typ
}

// ID returns the SHA-1 hash of the entry.
func (e *TreeEntry) ID() *SHA1 {
	return e.id
}

// Name returns name of the entry.
func (e *TreeEntry) Name() string {
	return e.name
}

// Size returns the size of thr entry.
func (e *TreeEntry) Size() int64 {
	e.sizeOnce.Do(func() {
		if e.IsTree() {
			return
		}

		stdout, err := NewCommand("cat-file", "-s", e.id.String()).RunInDir(e.parent.repo.path)
		if err != nil {
			return
		}
		e.size, _ = strconv.ParseInt(strings.TrimSpace(string(stdout)), 10, 64)
	})

	return e.size
}

// Blob returns a blob object from the entry.
func (e *TreeEntry) Blob() *Blob {
	return &Blob{
		TreeEntry: e,
	}
}

// Entries is a sortable list of tree entries.
type Entries []*TreeEntry

var sorters = []func(t1, t2 *TreeEntry) bool{
	func(t1, t2 *TreeEntry) bool {
		return (t1.IsTree() || t1.IsCommit()) && !t2.IsTree() && !t2.IsCommit()
	},
	func(t1, t2 *TreeEntry) bool {
		return t1.name < t2.name
	},
}

func (es Entries) Len() int      { return len(es) }
func (es Entries) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
func (es Entries) Less(i, j int) bool {
	t1, t2 := es[i], es[j]
	var k int
	for k = 0; k < len(sorters)-1; k++ {
		sorter := sorters[k]
		switch {
		case sorter(t1, t2):
			return true
		case sorter(t2, t1):
			return false
		}
	}
	return sorters[k](t1, t2)
}

func (es Entries) Sort() {
	sort.Sort(es)
}

// EntryCommitInfo contains a tree entry with its commit information.
type EntryCommitInfo struct {
	Entry     *TreeEntry
	Commit    *Commit
	Submodule *Submodule
}

// CommitsInfoOptions contains optional arguments for getting commits information.
type CommitsInfoOptions struct {
	// The relative path of the repository.
	Path string
	// The maximum number of goroutines to be used for getting commits information.
	// When not set (i.e. <=0), runtime.GOMAXPROCS is used to determine the value.
	MaxConcurrency int
	// The timeout duration before giving up for each shell command execution.
	// The default timeout duration will be used when not supplied.
	Timeout time.Duration
}

var defaultConcurrency = runtime.GOMAXPROCS(0)

// CommitsInfo returns a list of commit information for these tree entries in the state of
// given commit and subpath. It takes advantages of concurrency to speed up the process.
// The returned list has the same number of items as tree entries, so the caller can access
// them via slice indices.
func (es Entries) CommitsInfo(commit *Commit, opts ...CommitsInfoOptions) ([]*EntryCommitInfo, error) {
	if len(es) == 0 {
		return []*EntryCommitInfo{}, nil
	}

	var opt CommitsInfoOptions
	if len(opts) > 0 {
		opt = opts[0]
	}

	if opt.MaxConcurrency <= 0 {
		opt.MaxConcurrency = defaultConcurrency
	}

	// Length of bucket determines how many goroutines (subprocesses) can run at the same time.
	bucket := make(chan struct{}, opt.MaxConcurrency)
	results := make(chan *EntryCommitInfo, len(es))
	errs := make(chan error, 1)

	var errored int64
	hasErrored := func() bool {
		return atomic.LoadInt64(&errored) != 0
	}
	// Only count for the first error, discard the rest
	setError := func(err error) {
		if !atomic.CompareAndSwapInt64(&errored, 0, 1) {
			return
		}
		errs <- err
	}

	var wg sync.WaitGroup
	wg.Add(len(es))
	go func() {
		for i, e := range es {
			// Shrink down the counter and exit when there is an error
			if hasErrored() {
				wg.Add(i - len(es))
				return
			}

			// Block until there is an empty slot to control the maximum concurrency
			bucket <- struct{}{}

			go func(e *TreeEntry) {
				defer func() {
					wg.Done()
					<-bucket
				}()

				// Avoid expensive operations if has errored
				if hasErrored() {
					return
				}

				info := &EntryCommitInfo{
					Entry: e,
				}
				epath := path.Join(opt.Path, e.Name())

				var err error
				info.Commit, err = commit.CommitByPath(CommitByRevisionOptions{
					Path:    epath,
					Timeout: opt.Timeout,
				})
				if err != nil {
					setError(fmt.Errorf("get commit by path %q: %v", epath, err))
					return
				}

				// Get extra information for submodules
				if e.IsCommit() {
					info.Submodule, err = commit.Submodule(epath)
					if err != nil {
						setError(fmt.Errorf("get submodule %q: %v", epath, err))
						return
					}
				}

				results <- info
			}(e)
		}
	}()

	wg.Wait()
	if hasErrored() {
		return nil, <-errs
	}

	close(results)
	infos := make(map[[20]byte]*EntryCommitInfo, len(es))
	for info := range results {
		infos[info.Entry.id.bytes] = info
	}

	commitsInfo := make([]*EntryCommitInfo, len(es))
	for i, e := range es {
		commitsInfo[i] = infos[e.id.bytes]
	}
	return commitsInfo, nil
}
<commit_msg>tree_entry: fix CommitsInfo messed up with entries have the same SHA1 (#59)<commit_after>// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"fmt"
	"path"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

// EntryMode is the unix file mode of a tree entry.
type EntryMode int

// There are only a few file modes in Git. They look like unix file modes, but they can only be
// one of these.
const (
	EntryTree    EntryMode = 0040000
	EntryBlob    EntryMode = 0100644
	EntryExec    EntryMode = 0100755
	EntrySymlink EntryMode = 0120000
	EntryCommit  EntryMode = 0160000
)

type TreeEntry struct {
	mode EntryMode
	typ  ObjectType
	id   *SHA1
	name string

	parent *Tree

	size     int64
	sizeOnce sync.Once
}

// Mode returns the entry mode if the tree entry.
func (e *TreeEntry) Mode() EntryMode {
	return e.mode
}

// IsTree returns tree if the entry itself is another tree (i.e. a directory).
func (e *TreeEntry) IsTree() bool {
	return e.mode == EntryTree
}

// IsBlob returns true if the entry is a blob.
func (e *TreeEntry) IsBlob() bool {
	return e.mode == EntryBlob
}

// IsExec returns tree if the entry is an executable.
func (e *TreeEntry) IsExec() bool {
	return e.mode == EntryExec
}

// IsSymlink returns true if the entry is a symbolic link.
func (e *TreeEntry) IsSymlink() bool {
	return e.mode == EntrySymlink
}

// IsCommit returns true if the entry is a commit (i.e. a submodule).
func (e *TreeEntry) IsCommit() bool {
	return e.mode == EntryCommit
}

// Type returns the object type of the entry.
func (e *TreeEntry) Type() ObjectType {
	return e.typ
}

// ID returns the SHA-1 hash of the entry.
func (e *TreeEntry) ID() *SHA1 {
	return e.id
}

// Name returns name of the entry.
func (e *TreeEntry) Name() string {
	return e.name
}

// Size returns the size of thr entry.
func (e *TreeEntry) Size() int64 {
	e.sizeOnce.Do(func() {
		if e.IsTree() {
			return
		}

		stdout, err := NewCommand("cat-file", "-s", e.id.String()).RunInDir(e.parent.repo.path)
		if err != nil {
			return
		}
		e.size, _ = strconv.ParseInt(strings.TrimSpace(string(stdout)), 10, 64)
	})

	return e.size
}

// Blob returns a blob object from the entry.
func (e *TreeEntry) Blob() *Blob {
	return &Blob{
		TreeEntry: e,
	}
}

// Entries is a sortable list of tree entries.
type Entries []*TreeEntry

var sorters = []func(t1, t2 *TreeEntry) bool{
	func(t1, t2 *TreeEntry) bool {
		return (t1.IsTree() || t1.IsCommit()) && !t2.IsTree() && !t2.IsCommit()
	},
	func(t1, t2 *TreeEntry) bool {
		return t1.name < t2.name
	},
}

func (es Entries) Len() int      { return len(es) }
func (es Entries) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
func (es Entries) Less(i, j int) bool {
	t1, t2 := es[i], es[j]
	var k int
	for k = 0; k < len(sorters)-1; k++ {
		sorter := sorters[k]
		switch {
		case sorter(t1, t2):
			return true
		case sorter(t2, t1):
			return false
		}
	}
	return sorters[k](t1, t2)
}

func (es Entries) Sort() {
	sort.Sort(es)
}

// EntryCommitInfo contains a tree entry with its commit information.
type EntryCommitInfo struct {
	Entry     *TreeEntry
	Index     int
	Commit    *Commit
	Submodule *Submodule
}

// CommitsInfoOptions contains optional arguments for getting commits information.
type CommitsInfoOptions struct {
	// The relative path of the repository.
	Path string
	// The maximum number of goroutines to be used for getting commits information.
	// When not set (i.e. <=0), runtime.GOMAXPROCS is used to determine the value.
	MaxConcurrency int
	// The timeout duration before giving up for each shell command execution.
	// The default timeout duration will be used when not supplied.
	Timeout time.Duration
}

var defaultConcurrency = runtime.GOMAXPROCS(0)

// CommitsInfo returns a list of commit information for these tree entries in the state of
// given commit and subpath. It takes advantages of concurrency to speed up the process.
// The returned list has the same number of items as tree entries, so the caller can access
// them via slice indices.
func (es Entries) CommitsInfo(commit *Commit, opts ...CommitsInfoOptions) ([]*EntryCommitInfo, error) {
	if len(es) == 0 {
		return []*EntryCommitInfo{}, nil
	}

	var opt CommitsInfoOptions
	if len(opts) > 0 {
		opt = opts[0]
	}

	if opt.MaxConcurrency <= 0 {
		opt.MaxConcurrency = defaultConcurrency
	}

	// Length of bucket determines how many goroutines (subprocesses) can run at the same time.
	bucket := make(chan struct{}, opt.MaxConcurrency)
	results := make(chan *EntryCommitInfo, len(es))
	errs := make(chan error, 1)

	var errored int64
	hasErrored := func() bool {
		return atomic.LoadInt64(&errored) != 0
	}
	// Only count for the first error, discard the rest
	setError := func(err error) {
		if !atomic.CompareAndSwapInt64(&errored, 0, 1) {
			return
		}
		errs <- err
	}

	var wg sync.WaitGroup
	wg.Add(len(es))
	go func() {
		for i, e := range es {
			// Shrink down the counter and exit when there is an error
			if hasErrored() {
				wg.Add(i - len(es))
				return
			}

			// Block until there is an empty slot to control the maximum concurrency
			bucket <- struct{}{}

			go func(e *TreeEntry, i int) {
				defer func() {
					wg.Done()
					<-bucket
				}()

				// Avoid expensive operations if has errored
				if hasErrored() {
					return
				}

				info := &EntryCommitInfo{
					Entry: e,
					Index: i,
				}
				epath := path.Join(opt.Path, e.Name())

				var err error
				info.Commit, err = commit.CommitByPath(CommitByRevisionOptions{
					Path:    epath,
					Timeout: opt.Timeout,
				})
				if err != nil {
					setError(fmt.Errorf("get commit by path %q: %v", epath, err))
					return
				}

				// Get extra information for submodules
				if e.IsCommit() {
					info.Submodule, err = commit.Submodule(epath)
					if err != nil {
						setError(fmt.Errorf("get submodule %q: %v", epath, err))
						return
					}
				}

				results <- info
			}(e, i)
		}
	}()

	wg.Wait()
	if hasErrored() {
		return nil, <-errs
	}

	close(results)

	commitsInfo := make([]*EntryCommitInfo, len(es))
	for info := range results {
		commitsInfo[info.Index] = info
	}
	return commitsInfo, nil
}
<|endoftext|>