<commit_before>/*
   Copyright 2017 Artem Sidorenko <artem@posteo.de>

   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 github_test

import (
	"errors"
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/artem-sidorenko/chagen/connectors"
	"github.com/artem-sidorenko/chagen/connectors/github"
	"github.com/artem-sidorenko/chagen/connectors/github/internal/testclient"
	"github.com/artem-sidorenko/chagen/data"
	tcli "github.com/artem-sidorenko/chagen/internal/testing/cli"

	"github.com/urfave/cli"
)

func setupTestConnector(
	returnValue testclient.ReturnValueStr, newTagUseReleaseURL bool,
) connectors.Connector {

	github.NewGitHubClientFunc = testclient.New
	cliFlags := map[string]string{
		"github-owner": "testowner",
		"github-repo":  "testrepo",
	}
	if newTagUseReleaseURL {
		cliFlags["github-release-url"] = "true"
	}

	ctx := tcli.TestContext(github.CLIFlags(), cliFlags)

	// initialize error values
	testclient.ReturnValue = returnValue

	c, err := github.New(ctx)
	if err != nil {
		panic(fmt.Sprintf("got error from test consturctor: %v", err))
	}

	return c
}

func TestConnector_RepositoryExists(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        bool
		wantErr     error
	}{
		{
			name: "API returns 200 for Ok",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetRespCode: 200,
			},
			want: true,
		},
		{
			name: "API returns 404",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetRespCode: 404,
			},
			want: false,
		},
		{
			name: "API returns unhandled error code 500",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetRespCode: 500,
			},
			wantErr: errors.New("GitHub query 'RepositoryExists' failed: unhandled HTTP response code 500"),
		},
		{
			name: "Get returns an error",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetErr: true,
			},
			wantErr: errors.New("GitHub query 'RepositoryExists' failed: can't fetch the repo data"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.RepositoryExists()

			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.RepositoryExists() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if got != tt.want {
				t.Errorf("Connector.RepositoryExists() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGetTags(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        data.Tags
		wantErr     error
	}{
		{
			name: "API returns proper data",
			want: data.Tags{
				{
					Name:   "v0.0.1",
					Commit: "7d84cdb2f7c2d4619cda4b8adeb1897097b5c8fc",
					Date:   time.Unix(2147483647, 0),
					URL:    "https://github.com/testowner/testrepo/releases/v0.0.1",
				},
				{
					Name:   "v0.0.2",
					Commit: "b3622b516b8ad70ce5dc3fa422fb90c3b58fa9da",
					Date:   time.Unix(2047483647, 0),
					URL:    "https://github.com/testowner/testrepo/tree/v0.0.2",
				},
			},
		},
		{
			name: "ListTags call fails",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceListTagsErr: true,
			},
			wantErr: errors.New("GitHub query 'GetTags' failed: can't fetch the tags"),
		},
		{
			name: "GetCommit call fails",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetCommitsErr: true,
			},
			wantErr: errors.New("GitHub query 'GetTags' failed: can't fetch the commit"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.GetTags()

			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.GetTags() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Connector.GetTags() = %+v, want %+v", got, tt.want)
			}
		})
	}
}

func TestGetIssues(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        data.Issues
		wantErr     error
	}{
		{
			name: "API returns proper data",
			want: data.Issues{
				data.Issue{
					ID:         1234,
					Name:       "Test issue title",
					ClosedDate: time.Unix(1047483647, 0),
					URL:        "http://example.com/issues/1234",
					Labels:     []string{"enhancement"},
				},
			},
		},
		{
			name: "ListIssues call fails",
			returnValue: testclient.ReturnValueStr{
				RetIssueServiceListByRepoErr: true,
			},
			wantErr: errors.New("GitHub query 'GetIssues' failed: can't fetch the issues"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.GetIssues()
			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.GetIssues() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Connector.GetIssues() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGetMRs(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        data.MRs
		wantErr     error
	}{
		{
			name: "API returns proper data",
			want: data.MRs{
				data.MR{
					ID:         1234,
					Name:       "Test PR title",
					URL:        "https://example.com/pulls/1234",
					Author:     "test-user",
					AuthorURL:  "https://example.com/users/test-user",
					MergedDate: time.Unix(1747483647, 0),
					Labels:     []string{"bugfix"},
				},
			},
		},
		{
			name: "ListPRs call fails",
			returnValue: testclient.ReturnValueStr{
				RetPullRequestsListErr: true,
			},
			wantErr: errors.New("GitHub query 'GetMRs' failed: can't fetch the PRs"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.GetMRs()
			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.GetMRs() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Connector.GetMRs() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGetNewTagURL(t *testing.T) {
	type fields struct {
		NewTagUseReleaseURL bool
	}
	type args struct {
		TagName string
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    string
		wantErr bool
	}{
		{
			name: "Release is present, NewTagUseReleaseURL is disabled",
			fields: fields{
				NewTagUseReleaseURL: false,
			},
			args: args{
				TagName: "v0.0.1",
			},
			want: "https://github.com/testowner/testrepo/releases/v0.0.1",
		},
		{
			name: "Release is present, NewTagUseReleaseURL is enabled",
			fields: fields{
				NewTagUseReleaseURL: true,
			},
			args: args{
				TagName: "v0.0.1",
			},
			want: "https://github.com/testowner/testrepo/releases/v0.0.1",
		},
		{
			name: "Release is not present, NewTagUseReleaseURL is disabled",
			fields: fields{
				NewTagUseReleaseURL: false,
			},
			args: args{
				TagName: "v0.0.3",
			},
			want: "https://github.com/testowner/testrepo/tree/v0.0.3",
		},
		{
			name: "Release is not present, alwaysUseReleaseURL is enabled",
			fields: fields{
				NewTagUseReleaseURL: true,
			},
			args: args{
				TagName: "v0.0.3",
			},
			want: "https://github.com/testowner/testrepo/releases/v0.0.3",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(testclient.ReturnValueStr{}, tt.fields.NewTagUseReleaseURL)

			got, err := c.GetNewTagURL(tt.args.TagName)
			if (err != nil) != tt.wantErr {
				t.Errorf("Connector.GetNewTagURL() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if got != tt.want {
				t.Errorf("Connector.GetNewTagURL() = %v, want %v", got, tt.want)
			}
		})
	}
}

func setupCLIContext(githubOwner, githubRepo bool) *cli.Context {
	flags := map[string]string{}

	if githubOwner {
		flags["github-owner"] = "testowner"
	}

	if githubRepo {
		flags["github-repo"] = "testrepo"
	}

	return tcli.TestContext(github.CLIFlags(), flags)
}

func TestNew(t *testing.T) {
	type args struct {
		githubOwner bool
		githubRepo  bool
	}
	tests := []struct {
		name          string
		args          args
		retErrControl testclient.ReturnValueStr
		wantErr       error
	}{
		{
			name: "Proper CLI flags given",
			args: args{
				githubOwner: true,
				githubRepo:  true,
			},
			wantErr: nil,
		},
		{
			name: "github-owner flag is missing",
			args: args{
				githubOwner: false,
				githubRepo:  true,
			},
			wantErr: errors.New("option --github-owner is required"),
		},
		{
			name: "github-repo flag is missing",
			args: args{
				githubOwner: true,
				githubRepo:  false,
			},
			wantErr: errors.New("option --github-repo is required"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			github.NewGitHubClientFunc = testclient.New
			testclient.ReturnValue = tt.retErrControl
			_, err := github.New(setupCLIContext(tt.args.githubOwner, tt.args.githubRepo))

			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("New() got = %v, wantErr %v", err, tt.wantErr)
				return
			}
		})
	}
}
<commit_msg>Refactoring: removal of obsolete setupCLIContext<commit_after>/*
   Copyright 2017 Artem Sidorenko <artem@posteo.de>

   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 github_test

import (
	"errors"
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/artem-sidorenko/chagen/connectors"
	"github.com/artem-sidorenko/chagen/connectors/github"
	"github.com/artem-sidorenko/chagen/connectors/github/internal/testclient"
	"github.com/artem-sidorenko/chagen/data"
	tcli "github.com/artem-sidorenko/chagen/internal/testing/cli"
)

func setupTestConnector(
	returnValue testclient.ReturnValueStr, newTagUseReleaseURL bool,
) connectors.Connector {

	github.NewGitHubClientFunc = testclient.New
	cliFlags := map[string]string{
		"github-owner": "testowner",
		"github-repo":  "testrepo",
	}
	if newTagUseReleaseURL {
		cliFlags["github-release-url"] = "true"
	}

	ctx := tcli.TestContext(github.CLIFlags(), cliFlags)

	// initialize error values
	testclient.ReturnValue = returnValue

	c, err := github.New(ctx)
	if err != nil {
		panic(fmt.Sprintf("got error from test consturctor: %v", err))
	}

	return c
}

func TestConnector_RepositoryExists(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        bool
		wantErr     error
	}{
		{
			name: "API returns 200 for Ok",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetRespCode: 200,
			},
			want: true,
		},
		{
			name: "API returns 404",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetRespCode: 404,
			},
			want: false,
		},
		{
			name: "API returns unhandled error code 500",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetRespCode: 500,
			},
			wantErr: errors.New("GitHub query 'RepositoryExists' failed: unhandled HTTP response code 500"),
		},
		{
			name: "Get returns an error",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetErr: true,
			},
			wantErr: errors.New("GitHub query 'RepositoryExists' failed: can't fetch the repo data"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.RepositoryExists()

			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.RepositoryExists() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if got != tt.want {
				t.Errorf("Connector.RepositoryExists() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGetTags(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        data.Tags
		wantErr     error
	}{
		{
			name: "API returns proper data",
			want: data.Tags{
				{
					Name:   "v0.0.1",
					Commit: "7d84cdb2f7c2d4619cda4b8adeb1897097b5c8fc",
					Date:   time.Unix(2147483647, 0),
					URL:    "https://github.com/testowner/testrepo/releases/v0.0.1",
				},
				{
					Name:   "v0.0.2",
					Commit: "b3622b516b8ad70ce5dc3fa422fb90c3b58fa9da",
					Date:   time.Unix(2047483647, 0),
					URL:    "https://github.com/testowner/testrepo/tree/v0.0.2",
				},
			},
		},
		{
			name: "ListTags call fails",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceListTagsErr: true,
			},
			wantErr: errors.New("GitHub query 'GetTags' failed: can't fetch the tags"),
		},
		{
			name: "GetCommit call fails",
			returnValue: testclient.ReturnValueStr{
				RetRepoServiceGetCommitsErr: true,
			},
			wantErr: errors.New("GitHub query 'GetTags' failed: can't fetch the commit"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.GetTags()

			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.GetTags() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Connector.GetTags() = %+v, want %+v", got, tt.want)
			}
		})
	}
}

func TestGetIssues(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        data.Issues
		wantErr     error
	}{
		{
			name: "API returns proper data",
			want: data.Issues{
				data.Issue{
					ID:         1234,
					Name:       "Test issue title",
					ClosedDate: time.Unix(1047483647, 0),
					URL:        "http://example.com/issues/1234",
					Labels:     []string{"enhancement"},
				},
			},
		},
		{
			name: "ListIssues call fails",
			returnValue: testclient.ReturnValueStr{
				RetIssueServiceListByRepoErr: true,
			},
			wantErr: errors.New("GitHub query 'GetIssues' failed: can't fetch the issues"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.GetIssues()
			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.GetIssues() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Connector.GetIssues() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGetMRs(t *testing.T) {
	tests := []struct {
		name        string
		returnValue testclient.ReturnValueStr
		want        data.MRs
		wantErr     error
	}{
		{
			name: "API returns proper data",
			want: data.MRs{
				data.MR{
					ID:         1234,
					Name:       "Test PR title",
					URL:        "https://example.com/pulls/1234",
					Author:     "test-user",
					AuthorURL:  "https://example.com/users/test-user",
					MergedDate: time.Unix(1747483647, 0),
					Labels:     []string{"bugfix"},
				},
			},
		},
		{
			name: "ListPRs call fails",
			returnValue: testclient.ReturnValueStr{
				RetPullRequestsListErr: true,
			},
			wantErr: errors.New("GitHub query 'GetMRs' failed: can't fetch the PRs"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(tt.returnValue, false)

			got, err := c.GetMRs()
			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("Connector.GetMRs() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Connector.GetMRs() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGetNewTagURL(t *testing.T) {
	type fields struct {
		NewTagUseReleaseURL bool
	}
	type args struct {
		TagName string
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    string
		wantErr bool
	}{
		{
			name: "Release is present, NewTagUseReleaseURL is disabled",
			fields: fields{
				NewTagUseReleaseURL: false,
			},
			args: args{
				TagName: "v0.0.1",
			},
			want: "https://github.com/testowner/testrepo/releases/v0.0.1",
		},
		{
			name: "Release is present, NewTagUseReleaseURL is enabled",
			fields: fields{
				NewTagUseReleaseURL: true,
			},
			args: args{
				TagName: "v0.0.1",
			},
			want: "https://github.com/testowner/testrepo/releases/v0.0.1",
		},
		{
			name: "Release is not present, NewTagUseReleaseURL is disabled",
			fields: fields{
				NewTagUseReleaseURL: false,
			},
			args: args{
				TagName: "v0.0.3",
			},
			want: "https://github.com/testowner/testrepo/tree/v0.0.3",
		},
		{
			name: "Release is not present, alwaysUseReleaseURL is enabled",
			fields: fields{
				NewTagUseReleaseURL: true,
			},
			args: args{
				TagName: "v0.0.3",
			},
			want: "https://github.com/testowner/testrepo/releases/v0.0.3",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := setupTestConnector(testclient.ReturnValueStr{}, tt.fields.NewTagUseReleaseURL)

			got, err := c.GetNewTagURL(tt.args.TagName)
			if (err != nil) != tt.wantErr {
				t.Errorf("Connector.GetNewTagURL() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if got != tt.want {
				t.Errorf("Connector.GetNewTagURL() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestNew(t *testing.T) {
	type args struct {
		githubOwner bool
		githubRepo  bool
	}
	tests := []struct {
		name          string
		args          args
		retErrControl testclient.ReturnValueStr
		wantErr       error
	}{
		{
			name: "Proper CLI flags given",
			args: args{
				githubOwner: true,
				githubRepo:  true,
			},
			wantErr: nil,
		},
		{
			name: "github-owner flag is missing",
			args: args{
				githubOwner: false,
				githubRepo:  true,
			},
			wantErr: errors.New("option --github-owner is required"),
		},
		{
			name: "github-repo flag is missing",
			args: args{
				githubOwner: true,
				githubRepo:  false,
			},
			wantErr: errors.New("option --github-repo is required"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cliFlags := map[string]string{}
			if tt.args.githubOwner {
				cliFlags["github-owner"] = "testowner"
			}

			if tt.args.githubRepo {
				cliFlags["github-repo"] = "testrepo"
			}

			ctx := tcli.TestContext(github.CLIFlags(), cliFlags)

			github.NewGitHubClientFunc = testclient.New
			testclient.ReturnValue = tt.retErrControl
			_, err := github.New(ctx)

			if !reflect.DeepEqual(err, tt.wantErr) {
				t.Errorf("New() got = %v, wantErr %v", err, tt.wantErr)
				return
			}
		})
	}
}
<|endoftext|>


<commit_before>package rbac

import (
	"github.com/rancher/rancher/pkg/impersonation"
	"github.com/sirupsen/logrus"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apiserver/pkg/authentication/user"
)

func (m *manager) getUser(username, groupname string) (user.Info, error) {
	u, err := m.userLister.Get("", username)
	if err != nil {
		return &user.DefaultInfo{}, err
	}
	groups := []string{"system:authenticated", "system:cattle:authenticated"}
	if groupname != "" {
		groups = append(groups, groupname)
	}
	attribs, err := m.userAttributeLister.Get("", username)
	if err != nil {
		return &user.DefaultInfo{}, err
	}
	if attribs != nil {
		for _, gps := range attribs.GroupPrincipals {
			for _, principal := range gps.Items {
				groups = append(groups, principal.Name)
			}
		}
	}
	user := &user.DefaultInfo{
		UID:    u.GetName(),
		Name:   u.Username,
		Groups: groups,
		Extra:  map[string][]string{"username": []string{u.Username}},
	}
	if len(u.PrincipalIDs) > 0 {
		user.Extra["principalid"] = u.PrincipalIDs
	}
	return user, nil
}

func (m *manager) ensureServiceAccountImpersonator(username, groupname string) error {
	user, err := m.getUser(username, groupname)
	if apierrors.IsNotFound(err) {
		logrus.Warnf("could not find user %s, will not create impersonation account on cluster", username)
		return nil
	}
	if err != nil {
		return err
	}
	logrus.Debugf("ensuring service account impersonator for %s", user.GetUID())
	i := impersonation.New(user, m.workload)
	return i.SetUpImpersonation()
}

func (m *manager) deleteServiceAccountImpersonator(username string) error {
	crtbs, err := m.crtbIndexer.ByIndex(rtbByClusterAndUserIndex, m.workload.ClusterName+"-"+username)
	if err != nil {
		return err
	}
	prtbs, err := m.prtbIndexer.ByIndex(rtbByClusterAndUserIndex, m.workload.ClusterName+"-"+username)
	if err != nil {
		return err
	}
	if len(crtbs)+len(prtbs) > 0 {
		return nil
	}
	roleName := impersonation.ImpersonationPrefix + username
	logrus.Debugf("deleting service account impersonator for %s", username)
	err = m.workload.RBAC.ClusterRoles("").Delete(roleName, &metav1.DeleteOptions{})
	if apierrors.IsNotFound(err) {
		return nil
	}
	return err
}
<commit_msg>Ignore user not found in user attribute lister<commit_after>package rbac

import (
	"github.com/rancher/rancher/pkg/impersonation"
	"github.com/sirupsen/logrus"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apiserver/pkg/authentication/user"
)

func (m *manager) getUser(username, groupname string) (user.Info, error) {
	u, err := m.userLister.Get("", username)
	if err != nil {
		return &user.DefaultInfo{}, err
	}
	groups := []string{"system:authenticated", "system:cattle:authenticated"}
	if groupname != "" {
		groups = append(groups, groupname)
	}
	attribs, err := m.userAttributeLister.Get("", username)
	if err != nil && !apierrors.IsNotFound(err) {
		return &user.DefaultInfo{}, err
	}
	if attribs != nil {
		for _, gps := range attribs.GroupPrincipals {
			for _, principal := range gps.Items {
				groups = append(groups, principal.Name)
			}
		}
	}
	user := &user.DefaultInfo{
		UID:    u.GetName(),
		Name:   u.Username,
		Groups: groups,
		Extra:  map[string][]string{"username": []string{u.Username}},
	}
	if len(u.PrincipalIDs) > 0 {
		user.Extra["principalid"] = u.PrincipalIDs
	}
	return user, nil
}

func (m *manager) ensureServiceAccountImpersonator(username, groupname string) error {
	user, err := m.getUser(username, groupname)
	if apierrors.IsNotFound(err) {
		logrus.Warnf("could not find user %s, will not create impersonation account on cluster", username)
		return nil
	}
	if err != nil {
		return err
	}
	logrus.Debugf("ensuring service account impersonator for %s", user.GetUID())
	i := impersonation.New(user, m.workload)
	return i.SetUpImpersonation()
}

func (m *manager) deleteServiceAccountImpersonator(username string) error {
	crtbs, err := m.crtbIndexer.ByIndex(rtbByClusterAndUserIndex, m.workload.ClusterName+"-"+username)
	if err != nil {
		return err
	}
	prtbs, err := m.prtbIndexer.ByIndex(rtbByClusterAndUserIndex, m.workload.ClusterName+"-"+username)
	if err != nil {
		return err
	}
	if len(crtbs)+len(prtbs) > 0 {
		return nil
	}
	roleName := impersonation.ImpersonationPrefix + username
	logrus.Debugf("deleting service account impersonator for %s", username)
	err = m.workload.RBAC.ClusterRoles("").Delete(roleName, &metav1.DeleteOptions{})
	if apierrors.IsNotFound(err) {
		return nil
	}
	return err
}
<|endoftext|>


<commit_before>package workflowtrigger

import (
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/caicloud/cyclone/pkg/k8s/clientset"
	"github.com/caicloud/cyclone/pkg/workflow/common"
	"github.com/pkg/errors"
	"github.com/robfig/cron"
	"github.com/satori/go.uuid"
	log "github.com/sirupsen/logrus"

	"github.com/caicloud/cyclone/pkg/apis/cyclone/v1alpha1"
)

const (
	KeyTemplate = "%s/%s"

	// time zone offset to UTC, in minutes
	// -480 for Asia/Shanghai(+8)
	ParamTimeZoneOffset = "timeZoneOffset"
	ParamSchedule       = "schedule"
)

type CronTrigger struct {
	Cron                *cron.Cron
	IsRunning           bool
	SuccCount           int
	FailCount           int
	Namespace           string
	WorkflowTriggerName string
	WorkflowRun         *v1alpha1.WorkflowRun
	Manage              *CronTriggerManager
}

type CronTriggerManager struct {
	Client         clientset.Interface
	CronTriggerMap map[string]*CronTrigger
	mutex          sync.Mutex
}

func NewTriggerManager(client clientset.Interface) *CronTriggerManager {
	return &CronTriggerManager{
		Client:         client,
		CronTriggerMap: make(map[string]*CronTrigger),
		mutex:          sync.Mutex{},
	}
}

func (trigger *CronTrigger) getKeyFromTrigger() string {
	return fmt.Sprintf(KeyTemplate, trigger.Namespace, trigger.WorkflowTriggerName)
}

func (m *CronTriggerManager) AddTrigger(trigger *CronTrigger) {
	wftKey := trigger.getKeyFromTrigger()
	m.mutex.Lock()
	defer m.mutex.Unlock()
	if wft, ok := m.CronTriggerMap[wftKey]; ok {
		// this situation may not happen for k8s will do same name check
		log.Warnf("failed to add cronTrigger, already exists: %+v\n", wft)
	} else {
		m.CronTriggerMap[wftKey] = trigger
	}
}

func (m *CronTriggerManager) DeleteTrigger(wftKey string) {
	m.mutex.Lock()
	defer m.mutex.Unlock()
	if wft, ok := m.CronTriggerMap[wftKey]; ok {
		wft.Cron.Stop()
		wft.IsRunning = false
		delete(m.CronTriggerMap, wftKey)
	} else {
		log.Warnf("failed to delete cronTrigger(%s), not exist\n", wftKey)
	}
}

func ToWorkflowTrigger(obj interface{}) (*v1alpha1.WorkflowTrigger, error) {

	wft, ok := obj.(*v1alpha1.WorkflowTrigger)
	if !ok {
		return nil, errors.New(fmt.Sprintf("I want type: WorkflowTrigger, but it is: %T", obj))
	} else {
		return wft, nil
	}
}

func (c *CronTrigger) Run() {

	c.WorkflowRun.Name = c.WorkflowTriggerName + "-" + strings.Replace(uuid.NewV1().String(), "-", "", -1)

	if c.WorkflowRun.Labels == nil {
		c.WorkflowRun.Labels = make(map[string]string)
	}
	c.WorkflowRun.Labels[common.WorkflowRunLabelName] = c.WorkflowRun.Spec.WorkflowRef.Name

	_, err := c.Manage.Client.CycloneV1alpha1().WorkflowRuns(c.Namespace).Create(c.WorkflowRun)
	if err != nil {
		c.FailCount++
		log.Warnf("can not create WorkflowRun: %s", err)
	} else {
		c.SuccCount++
	}
}

func getParamValue(items []v1alpha1.ParameterItem, key string) (string, bool) {
	for _, item := range items {
		if item.Name == key {
			return item.Value, true
		}
	}
	return "", false
}

func (m *CronTriggerManager) CreateCron(wft *v1alpha1.WorkflowTrigger) {

	schedule, has := getParamValue(wft.Spec.Parameters, ParamSchedule)
	if !has {
		log.WithField("wft", wft.Name).Warn("Parameter 'schedule' not set in WorkflowTrigger spec")
		return
	}

	timezone, has := getParamValue(wft.Spec.Parameters, ParamTimeZoneOffset)
	if !has {
		timezone = "0"
	}

	minuteOffUTC, err := strconv.Atoi(timezone)
	if err != nil {
		log.Warnf("can not parse timezone(%s) to int", timezone)
		minuteOffUTC = 0
	}

	ct := &CronTrigger{
		Namespace:           wft.Namespace,
		WorkflowTriggerName: wft.Name,
	}

	wfr := &v1alpha1.WorkflowRun{
		Spec: wft.Spec.WorkflowRunSpec,
	}

	ct.WorkflowRun = wfr

	c := cron.NewWithLocation(time.FixedZone("userZone", -1*60*minuteOffUTC))
	err = c.AddJob(schedule, ct)
	if err != nil {
		log.Errorf("can not create Cron job: %s", err)
		return
	}

	ct.Cron = c
	ct.Manage = m
	m.AddTrigger(ct)

	if !wft.Spec.Disabled {
		ct.Cron.Start()
		ct.IsRunning = true
	}
}

func (m *CronTriggerManager) UpdateCron(wft *v1alpha1.WorkflowTrigger) {
	m.DeleteCron(wft)
	m.CreateCron(wft)
}

func (m *CronTriggerManager) DeleteCron(wft *v1alpha1.WorkflowTrigger) {
	wftKey := getKeyFromWorkflowTrigger(wft)
	m.DeleteTrigger(wftKey)
}

func getKeyFromWorkflowTrigger(wft *v1alpha1.WorkflowTrigger) string {
	return fmt.Sprintf(KeyTemplate, wft.Namespace, wft.Name)
}
<commit_msg>fix(trigger): reduce the name length of wfr created by trigger (#700)<commit_after>package workflowtrigger

import (
	"fmt"
	"strconv"
	"sync"
	"time"

	"github.com/caicloud/cyclone/pkg/apis/cyclone/v1alpha1"
	"github.com/caicloud/cyclone/pkg/k8s/clientset"
	"github.com/caicloud/cyclone/pkg/workflow/common"
	"github.com/pkg/errors"
	"github.com/robfig/cron"
	log "github.com/sirupsen/logrus"
	errors2 "k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/names"
)

const (
	KeyTemplate = "%s/%s"

	// time zone offset to UTC, in minutes
	// -480 for Asia/Shanghai(+8)
	ParamTimeZoneOffset = "timeZoneOffset"
	ParamSchedule       = "schedule"
)

type CronTrigger struct {
	Cron                *cron.Cron
	IsRunning           bool
	SuccCount           int
	FailCount           int
	Namespace           string
	WorkflowTriggerName string
	WorkflowRun         *v1alpha1.WorkflowRun
	Manage              *CronTriggerManager
}

type CronTriggerManager struct {
	Client         clientset.Interface
	CronTriggerMap map[string]*CronTrigger
	mutex          sync.Mutex
}

func NewTriggerManager(client clientset.Interface) *CronTriggerManager {
	return &CronTriggerManager{
		Client:         client,
		CronTriggerMap: make(map[string]*CronTrigger),
		mutex:          sync.Mutex{},
	}
}

func (trigger *CronTrigger) getKeyFromTrigger() string {
	return fmt.Sprintf(KeyTemplate, trigger.Namespace, trigger.WorkflowTriggerName)
}

func (m *CronTriggerManager) AddTrigger(trigger *CronTrigger) {
	wftKey := trigger.getKeyFromTrigger()
	m.mutex.Lock()
	defer m.mutex.Unlock()
	if wft, ok := m.CronTriggerMap[wftKey]; ok {
		// this situation may not happen for k8s will do same name check
		log.Warnf("failed to add cronTrigger, already exists: %+v\n", wft)
	} else {
		m.CronTriggerMap[wftKey] = trigger
	}
}

func (m *CronTriggerManager) DeleteTrigger(wftKey string) {
	m.mutex.Lock()
	defer m.mutex.Unlock()
	if wft, ok := m.CronTriggerMap[wftKey]; ok {
		wft.Cron.Stop()
		wft.IsRunning = false
		delete(m.CronTriggerMap, wftKey)
	} else {
		log.Warnf("failed to delete cronTrigger(%s), not exist\n", wftKey)
	}
}

func ToWorkflowTrigger(obj interface{}) (*v1alpha1.WorkflowTrigger, error) {

	wft, ok := obj.(*v1alpha1.WorkflowTrigger)
	if !ok {
		return nil, errors.New(fmt.Sprintf("I want type: WorkflowTrigger, but it is: %T", obj))
	} else {
		return wft, nil
	}
}

func (c *CronTrigger) Run() {

	if c.WorkflowRun.Labels == nil {
		c.WorkflowRun.Labels = make(map[string]string)
	}
	c.WorkflowRun.Labels[common.WorkflowRunLabelName] = c.WorkflowRun.Spec.WorkflowRef.Name

	var wfrName string
	for {
		wfrName = names.SimpleNameGenerator.GenerateName(c.WorkflowTriggerName + "-")
		c.WorkflowRun.Name = wfrName
		_, err := c.Manage.Client.CycloneV1alpha1().WorkflowRuns(c.Namespace).Create(c.WorkflowRun)
		if err != nil {
			if errors2.IsAlreadyExists(err) {
				continue;
			} else {
				c.FailCount++
				log.Warnf("can not create WorkflowRun: %s", err)
			}
		} else {
			c.SuccCount++
		}
	}
}

func getParamValue(items []v1alpha1.ParameterItem, key string) (string, bool) {
	for _, item := range items {
		if item.Name == key {
			return item.Value, true
		}
	}
	return "", false
}

func (m *CronTriggerManager) CreateCron(wft *v1alpha1.WorkflowTrigger) {

	schedule, has := getParamValue(wft.Spec.Parameters, ParamSchedule)
	if !has {
		log.WithField("wft", wft.Name).Warn("Parameter 'schedule' not set in WorkflowTrigger spec")
		return
	}

	timezone, has := getParamValue(wft.Spec.Parameters, ParamTimeZoneOffset)
	if !has {
		timezone = "0"
	}

	minuteOffUTC, err := strconv.Atoi(timezone)
	if err != nil {
		log.Warnf("can not parse timezone(%s) to int", timezone)
		minuteOffUTC = 0
	}

	ct := &CronTrigger{
		Namespace:           wft.Namespace,
		WorkflowTriggerName: wft.Name,
	}

	wfr := &v1alpha1.WorkflowRun{
		Spec: wft.Spec.WorkflowRunSpec,
	}

	ct.WorkflowRun = wfr

	c := cron.NewWithLocation(time.FixedZone("userZone", -1*60*minuteOffUTC))
	err = c.AddJob(schedule, ct)
	if err != nil {
		log.Errorf("can not create Cron job: %s", err)
		return
	}

	ct.Cron = c
	ct.Manage = m
	m.AddTrigger(ct)

	if !wft.Spec.Disabled {
		ct.Cron.Start()
		ct.IsRunning = true
	}
}

func (m *CronTriggerManager) UpdateCron(wft *v1alpha1.WorkflowTrigger) {
	m.DeleteCron(wft)
	m.CreateCron(wft)
}

func (m *CronTriggerManager) DeleteCron(wft *v1alpha1.WorkflowTrigger) {
	wftKey := getKeyFromWorkflowTrigger(wft)
	m.DeleteTrigger(wftKey)
}

func getKeyFromWorkflowTrigger(wft *v1alpha1.WorkflowTrigger) string {
	return fmt.Sprintf(KeyTemplate, wft.Namespace, wft.Name)
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"os"
	"strings"

	"github.com/rancher/rancher/pkg/controllers/management/drivers/kontainerdriver"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
)

func addKontainerDrivers(management *config.ManagementContext) error {
	// create binary drop location if not exists
	err := os.MkdirAll(kontainerdriver.DriverDir, 0777)
	if err != nil {
		return fmt.Errorf("error creating binary drop folder: %v", err)
	}

	creator := driverCreator{
		driversLister: management.Management.KontainerDrivers("").Controller().Lister(),
		drivers:       management.Management.KontainerDrivers(""),
	}

	if err := creator.add("import"); err != nil {
		return err
	}

	if err := creator.add("rancherKubernetesEngine"); err != nil {
		return err
	}

	if err := creator.add("googleKubernetesEngine"); err != nil {
		return err
	}

	if err := creator.add("azureKubernetesService"); err != nil {
		return err
	}

	if err := creator.add("amazonElasticContainerService"); err != nil {
		return err
	}

	if err := creator.addCustomDriver(
		"aliyunkubernetescontainerservice",
		"https://github.com/rancher/kontainer-engine-driver-aliyun/releases/download/v0.2.1/kontainer-engine-driver-aliyun-linux",
		"",
		"",
		false,
		"*.aliyuncs.com",
	); err != nil {
		return err
	}

	if err := creator.addCustomDriver(
		"tencentkubernetesengine",
		"https://github.com/rancher/kontainer-engine-driver-tencent/releases/download/v0.2.0/kontainer-engine-driver-tencent-linux",
		"",
		"",
		false,
		"*.tencentcloudapi.com", "*.qcloud.com",
	); err != nil {
		return err
	}

	return nil
}

type driverCreator struct {
	driversLister v3.KontainerDriverLister
	drivers       v3.KontainerDriverInterface
}

func (c *driverCreator) add(name string) error {
	logrus.Infof("adding kontainer driver %v", name)

	driver, err := c.driversLister.Get("", name)
	if err != nil {
		if errors.IsNotFound(err) {
			_, err = c.drivers.Create(&v3.KontainerDriver{
				ObjectMeta: v1.ObjectMeta{
					Name:      strings.ToLower(name),
					Namespace: "",
				},
				Spec: v3.KontainerDriverSpec{
					URL:     "",
					BuiltIn: true,
					Active:  true,
				},
				Status: v3.KontainerDriverStatus{
					DisplayName: name,
				},
			})
			if err != nil && !errors.IsAlreadyExists(err) {
				return fmt.Errorf("error creating driver: %v", err)
			}
		} else {
			return fmt.Errorf("error getting driver: %v", err)
		}
	} else {
		driver.Spec.URL = ""

		_, err = c.drivers.Update(driver)
		if err != nil {
			return fmt.Errorf("error updating driver: %v", err)
		}
	}

	return nil
}

func (c *driverCreator) addCustomDriver(name, url, checksum, uiURL string, active bool, domains ...string) error {
	logrus.Infof("adding kontainer driver %v", name)
	_, err := c.driversLister.Get("", name)
	if err != nil {
		if errors.IsNotFound(err) {
			_, err = c.drivers.Create(&v3.KontainerDriver{
				ObjectMeta: v1.ObjectMeta{
					Name: strings.ToLower(name),
				},
				Spec: v3.KontainerDriverSpec{
					URL:              url,
					BuiltIn:          false,
					Active:           active,
					Checksum:         checksum,
					UIURL:            uiURL,
					WhitelistDomains: domains,
				},
				Status: v3.KontainerDriverStatus{
					DisplayName: name,
				},
			})
			if err != nil && !errors.IsAlreadyExists(err) {
				return fmt.Errorf("error creating driver: %v", err)
			}
		} else {
			return fmt.Errorf("error getting driver: %v", err)
		}
	}
	return nil
}
<commit_msg>add huawei driver<commit_after>package app

import (
	"fmt"
	"os"
	"strings"

	"github.com/rancher/rancher/pkg/controllers/management/drivers/kontainerdriver"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
)

func addKontainerDrivers(management *config.ManagementContext) error {
	// create binary drop location if not exists
	err := os.MkdirAll(kontainerdriver.DriverDir, 0777)
	if err != nil {
		return fmt.Errorf("error creating binary drop folder: %v", err)
	}

	creator := driverCreator{
		driversLister: management.Management.KontainerDrivers("").Controller().Lister(),
		drivers:       management.Management.KontainerDrivers(""),
	}

	if err := creator.add("import"); err != nil {
		return err
	}

	if err := creator.add("rancherKubernetesEngine"); err != nil {
		return err
	}

	if err := creator.add("googleKubernetesEngine"); err != nil {
		return err
	}

	if err := creator.add("azureKubernetesService"); err != nil {
		return err
	}

	if err := creator.add("amazonElasticContainerService"); err != nil {
		return err
	}

	if err := creator.addCustomDriver(
		"aliyunkubernetescontainerservice",
		"https://github.com/rancher/kontainer-engine-driver-aliyun/releases/download/v0.2.1/kontainer-engine-driver-aliyun-linux",
		"",
		"",
		false,
		"*.aliyuncs.com",
	); err != nil {
		return err
	}

	if err := creator.addCustomDriver(
		"tencentkubernetesengine",
		"https://github.com/rancher/kontainer-engine-driver-tencent/releases/download/v0.2.0/kontainer-engine-driver-tencent-linux",
		"",
		"",
		false,
		"*.tencentcloudapi.com", "*.qcloud.com",
	); err != nil {
		return err
	}

	if err := creator.addCustomDriver(
		"huaweicontainercloudengine",
		"https://github.com/rancher/kontainer-engine-driver-huawei/releases/download/v0.1.0/kontainer-engine-driver-huawei-linux",
		"",
		"",
		false,
		"*.myhuaweicloud.com",
	); err != nil {
		return err
	}

	return nil
}

type driverCreator struct {
	driversLister v3.KontainerDriverLister
	drivers       v3.KontainerDriverInterface
}

func (c *driverCreator) add(name string) error {
	logrus.Infof("adding kontainer driver %v", name)

	driver, err := c.driversLister.Get("", name)
	if err != nil {
		if errors.IsNotFound(err) {
			_, err = c.drivers.Create(&v3.KontainerDriver{
				ObjectMeta: v1.ObjectMeta{
					Name:      strings.ToLower(name),
					Namespace: "",
				},
				Spec: v3.KontainerDriverSpec{
					URL:     "",
					BuiltIn: true,
					Active:  true,
				},
				Status: v3.KontainerDriverStatus{
					DisplayName: name,
				},
			})
			if err != nil && !errors.IsAlreadyExists(err) {
				return fmt.Errorf("error creating driver: %v", err)
			}
		} else {
			return fmt.Errorf("error getting driver: %v", err)
		}
	} else {
		driver.Spec.URL = ""

		_, err = c.drivers.Update(driver)
		if err != nil {
			return fmt.Errorf("error updating driver: %v", err)
		}
	}

	return nil
}

func (c *driverCreator) addCustomDriver(name, url, checksum, uiURL string, active bool, domains ...string) error {
	logrus.Infof("adding kontainer driver %v", name)
	_, err := c.driversLister.Get("", name)
	if err != nil {
		if errors.IsNotFound(err) {
			_, err = c.drivers.Create(&v3.KontainerDriver{
				ObjectMeta: v1.ObjectMeta{
					Name: strings.ToLower(name),
				},
				Spec: v3.KontainerDriverSpec{
					URL:              url,
					BuiltIn:          false,
					Active:           active,
					Checksum:         checksum,
					UIURL:            uiURL,
					WhitelistDomains: domains,
				},
				Status: v3.KontainerDriverStatus{
					DisplayName: name,
				},
			})
			if err != nil && !errors.IsAlreadyExists(err) {
				return fmt.Errorf("error creating driver: %v", err)
			}
		} else {
			return fmt.Errorf("error getting driver: %v", err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package plugins

import (
	"strings"

	"github.com/Seklfreak/Robyul2/cache"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/VojtechVitek/go-trello"
	"github.com/bwmarrin/discordgo"
	"github.com/sirupsen/logrus"
)

type feedbackAction func(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) (next feedbackAction)

type Feedback struct{}

func (f *Feedback) Commands() []string {
	return []string{
		"feedback",
		"suggestion",
		"suggest",
		"issue",
		"bug",
	}
}

var (
	trelloClient          *trello.Client
	trelloListSuggestions *trello.List
	trelloListIssues      *trello.List
)

func (f *Feedback) Init(session *discordgo.Session) {
	var err error
	token := helpers.GetConfig().Path("trello.token").Data().(string)
	trelloClient, err = trello.NewAuthClient(
		helpers.GetConfig().Path("trello.key").Data().(string),
		&token)
	helpers.Relax(err)

	trelloListSuggestions, err = trelloClient.List(
		helpers.GetConfig().Path("trello.board-ids.suggestions").Data().(string))
	helpers.Relax(err)
	trelloListIssues, err = trelloClient.List(
		helpers.GetConfig().Path("trello.board-ids.issues").Data().(string))
	helpers.Relax(err)
}

func (f *Feedback) Uninit(session *discordgo.Session) {

}

func (f *Feedback) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
	if !helpers.ModuleIsAllowed(msg.ChannelID, msg.ID, msg.Author.ID, helpers.ModulePermFeedback) {
		return
	}

	session.ChannelTyping(msg.ChannelID)

	var result *discordgo.MessageSend
	args := strings.Fields(content)

	action := f.actionStart
	for action != nil {
		action = action(command, args, msg, &result)
	}
}

func (f *Feedback) actionStart(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	cache.GetSession().ChannelTyping(in.ChannelID)

	if len(args) < 1 {
		*out = f.newMsg("plugins.feedback.arguments-too-few")
		return f.actionFinish
	}

	switch command {
	case "suggestion", "suggest", "feedback":
		return f.actionSuggestion
	case "issue", "bug":
		return f.actionIssue
	}

	*out = f.newMsg("bot.arguments.invalid")
	return f.actionFinish
}

func (f *Feedback) actionSuggestion(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	parts := strings.Split(in.Content, command)
	content := strings.TrimSpace(strings.Join(parts[1:], command))

	cardName := content
	cardDesc := ""

	// check for description
	if strings.Contains(content, "|") {
		cardName = strings.Split(content, "|")[0]
		cardDesc = strings.Split(content, "|")[1]
	}

	_, err := trelloListSuggestions.AddCard(trello.Card{
		Name: strings.TrimSpace(cardName),
		Desc: strings.TrimSpace(cardDesc),
	})
	helpers.Relax(err)

	f.logger().Infof("user #%s submitted a suggestion: %s", in.Author.ID, content)

	*out = f.newMsg("plugins.feedback.suggestion-received")
	return f.actionFinish
}

func (f *Feedback) actionIssue(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	parts := strings.Split(in.Content, command)
	content := strings.TrimSpace(strings.Join(parts[1:], command))

	_, err := trelloListIssues.AddCard(trello.Card{
		Name: content,
	})
	helpers.Relax(err)

	f.logger().Infof("user #%s submitted an issue: %s", in.Author.ID, content)

	*out = f.newMsg("plugins.feedback.issue-received")
	return f.actionFinish
}

func (f *Feedback) actionFinish(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	_, err := helpers.SendComplex(in.ChannelID, *out)
	helpers.RelaxMessage(err, in.ChannelID, in.ID)

	return nil
}

func (f *Feedback) newMsg(content string) *discordgo.MessageSend {
	return &discordgo.MessageSend{Content: helpers.GetText(content)}
}

func (f *Feedback) logger() *logrus.Entry {
	return cache.GetLogger().WithField("module", "feedback")
}
<commit_msg>[feedback] adds description for trello issues/bugs<commit_after>package plugins

import (
	"strings"

	"github.com/Seklfreak/Robyul2/cache"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/VojtechVitek/go-trello"
	"github.com/bwmarrin/discordgo"
	"github.com/sirupsen/logrus"
)

type feedbackAction func(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) (next feedbackAction)

type Feedback struct{}

func (f *Feedback) Commands() []string {
	return []string{
		"feedback",
		"suggestion",
		"suggest",
		"issue",
		"bug",
	}
}

var (
	trelloClient          *trello.Client
	trelloListSuggestions *trello.List
	trelloListIssues      *trello.List
)

func (f *Feedback) Init(session *discordgo.Session) {
	var err error
	token := helpers.GetConfig().Path("trello.token").Data().(string)
	trelloClient, err = trello.NewAuthClient(
		helpers.GetConfig().Path("trello.key").Data().(string),
		&token)
	helpers.Relax(err)

	trelloListSuggestions, err = trelloClient.List(
		helpers.GetConfig().Path("trello.board-ids.suggestions").Data().(string))
	helpers.Relax(err)
	trelloListIssues, err = trelloClient.List(
		helpers.GetConfig().Path("trello.board-ids.issues").Data().(string))
	helpers.Relax(err)
}

func (f *Feedback) Uninit(session *discordgo.Session) {

}

func (f *Feedback) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
	if !helpers.ModuleIsAllowed(msg.ChannelID, msg.ID, msg.Author.ID, helpers.ModulePermFeedback) {
		return
	}

	session.ChannelTyping(msg.ChannelID)

	var result *discordgo.MessageSend
	args := strings.Fields(content)

	action := f.actionStart
	for action != nil {
		action = action(command, args, msg, &result)
	}
}

func (f *Feedback) actionStart(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	cache.GetSession().ChannelTyping(in.ChannelID)

	if len(args) < 1 {
		*out = f.newMsg("plugins.feedback.arguments-too-few")
		return f.actionFinish
	}

	switch command {
	case "suggestion", "suggest", "feedback":
		return f.actionSuggestion
	case "issue", "bug":
		return f.actionIssue
	}

	*out = f.newMsg("bot.arguments.invalid")
	return f.actionFinish
}

func (f *Feedback) actionSuggestion(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	parts := strings.Split(in.Content, command)
	content := strings.TrimSpace(strings.Join(parts[1:], command))

	cardName := content
	cardDesc := ""

	// check for description
	if strings.Contains(content, "|") {
		cardName = strings.Split(content, "|")[0]
		cardDesc = strings.Split(content, "|")[1]
	}

	_, err := trelloListSuggestions.AddCard(trello.Card{
		Name: strings.TrimSpace(cardName),
		Desc: strings.TrimSpace(cardDesc),
	})
	helpers.Relax(err)

	f.logger().Infof("user #%s submitted a suggestion: %s", in.Author.ID, content)

	*out = f.newMsg("plugins.feedback.suggestion-received")
	return f.actionFinish
}

func (f *Feedback) actionIssue(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	parts := strings.Split(in.Content, command)
	content := strings.TrimSpace(strings.Join(parts[1:], command))

	cardName := content
	cardDesc := ""

	// check for description
	if strings.Contains(content, "|") {
		cardName = strings.Split(content, "|")[0]
		cardDesc = strings.Join(strings.Split(content, "|")[1:], "|")
	}

	_, err := trelloListIssues.AddCard(trello.Card{
		Name: strings.TrimSpace(cardName),
		Desc: strings.TrimSpace(cardDesc),
	})
	helpers.Relax(err)

	f.logger().Infof("user #%s submitted an issue: %s", in.Author.ID, content)

	*out = f.newMsg("plugins.feedback.issue-received")
	return f.actionFinish
}

func (f *Feedback) actionFinish(command string, args []string, in *discordgo.Message, out **discordgo.MessageSend) feedbackAction {
	_, err := helpers.SendComplex(in.ChannelID, *out)
	helpers.RelaxMessage(err, in.ChannelID, in.ID)

	return nil
}

func (f *Feedback) newMsg(content string) *discordgo.MessageSend {
	return &discordgo.MessageSend{Content: helpers.GetText(content)}
}

func (f *Feedback) logger() *logrus.Entry {
	return cache.GetLogger().WithField("module", "feedback")
}
<|endoftext|>


<commit_before>package relay

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
)

var serverIP = &net.UDPAddr{IP: net.IP([]byte{192, 168, 16, 12}), Port: UDPPort}

//Relay listens for clients and connects them to the local server.
func (r *Client) Relay() error {
	go func() {
		tcl, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IPv4zero, Port: TCPPort})
		if err != nil {
			log.Println("err", err)
		}

		for {
			c, err := tcl.Accept()
			if err != nil {
				log.Println("tcp err", err)
			} else {
				go func(c net.Conn) {
					server, err := net.Dial("tcp", "192.168.16.12:27000")
					if err != nil {
						log.Fatal(err)
					}

					go hexSpy(c, server, "To Client")
					go hexSpy(server, c, "To Server")
					select {}
				}(c)
			}
		}
	}()

	log.Println(r.Discover())

	l := r.u

	bs := make([]byte, 1024)
	for {
		n, addr, err := l.ReadFrom(bs)
		if err != nil {
			return err
		}

		m := make(map[string]interface{})
		json.Unmarshal(bs[:n], &m)
		fmt.Printf("m = %+v\n", m)

		if addr.String() == "192.168.16.15:28000" {
			continue
		}

		switch addr.String() {
		case "192.168.16.12:28000":
			if r.cli != nil {
				l.WriteToUDP(bs[:n], r.cli.(*net.UDPAddr))
			}
		case r.cliAddr:
			l.WriteToUDP(bs[:n], serverIP)
		default:
			if r.cli == nil {
				r.cli = addr
				r.cliAddr = addr.String()
				l.WriteToUDP(bs[:n], serverIP)
			}
			fmt.Printf("r = %+v\n", r)
		}

		if addr.String() != "192.168.16.15:28000" {
			if m["cmd"] != nil || m["MachineType"] != nil {
			}
		}
	}
}

var db = make(map[uint32]*DataEntry, 65000)

func hexSpy(w io.Writer, r io.Reader, pre string) {
	for {
		p, err := ReadPacket(r)
		if err != nil {
			log.Fatal(err)
		}
		p.WriteTo(w)

		if p.PacketType == DataUpdatePacket {

			for ct := 0; ct < len(p.Body); {
				d, n, err := UnmarshalDataEntry(p.Body[ct:])
				if err != nil {
					log.Println("Error unmarshalling", err)
					fmt.Printf("d = %+v\n", d)
					break
				}

				if d.Type == 8 {
					v := d.Value.(InsRemove)
					for _, ins := range v.Insert {
						db[ins.Ref].Name = ins.Name
					}
				}

				if _, ok := db[d.ID]; !ok {
					db[d.ID] = d
				} else {
					db[d.ID].Value = d.Value
				}

				if db[d.ID].Name == "TimeHour" {
					v := db[d.ID].Value.(float32)
					hComp := int(v)
					mComp := int((v - float32(hComp)) * 60)
					fmt.Printf("%d:%d\n", hComp, mComp)
				} else {
					log.Println(db[d.ID])
				}

				ct += n
			}
		}
	}
}
<commit_msg>Update IP variables<commit_after>package relay

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
)

var serverIP = net.IP([]byte{192, 168, 16, 12})
var serverUDP = net.UDPAddr{IP: serverIP, Port: UDPPort}

//Relay listens for clients and connects them to the local server.
func (r *Client) Relay() error {
	go func() {
		tcl, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IPv4zero, Port: TCPPort})
		if err != nil {
			log.Println("err", err)
		}

		for {
			c, err := tcl.Accept()
			if err != nil {
				log.Println("tcp err", err)
			} else {
				go func(c net.Conn) {
					server, err := net.Dial("tcp", "192.168.16.12:27000")
					if err != nil {
						log.Fatal(err)
					}

					go hexSpy(c, server, "To Client")
					go hexSpy(server, c, "To Server")
					select {}
				}(c)
			}
		}
	}()

	log.Println(r.Discover())

	l := r.u

	bs := make([]byte, 1024)
	for {
		n, addr, err := l.ReadFrom(bs)
		if err != nil {
			return err
		}

		m := make(map[string]interface{})
		json.Unmarshal(bs[:n], &m)
		fmt.Printf("m = %+v\n", m)

		if addr.String() == "192.168.16.15:28000" {
			continue
		}

		switch addr.String() {
		case "192.168.16.12:28000":
			if r.cli != nil {
				l.WriteToUDP(bs[:n], r.cli.(*net.UDPAddr))
			}
		case r.cliAddr:
			l.WriteToUDP(bs[:n], &serverUDP)
		default:
			if r.cli == nil {
				r.cli = addr
				r.cliAddr = addr.String()
				l.WriteToUDP(bs[:n], &serverUDP)
			}
			fmt.Printf("r = %+v\n", r)
		}

		if addr.String() != "192.168.16.15:28000" {
			if m["cmd"] != nil || m["MachineType"] != nil {
			}
		}
	}
}

var db = make(map[uint32]*DataEntry, 65000)

func hexSpy(w io.Writer, r io.Reader, pre string) {
	for {
		p, err := ReadPacket(r)
		if err != nil {
			log.Fatal(err)
		}
		p.WriteTo(w)

		if p.PacketType == DataUpdatePacket {

			for ct := 0; ct < len(p.Body); {
				d, n, err := UnmarshalDataEntry(p.Body[ct:])
				if err != nil {
					log.Println("Error unmarshalling", err)
					fmt.Printf("d = %+v\n", d)
					break
				}

				if d.Type == 8 {
					v := d.Value.(InsRemove)
					for _, ins := range v.Insert {
						db[ins.Ref].Name = ins.Name
					}
				}

				if _, ok := db[d.ID]; !ok {
					db[d.ID] = d
				} else {
					db[d.ID].Value = d.Value
				}

				if db[d.ID].Name == "TimeHour" {
					v := db[d.ID].Value.(float32)
					hComp := int(v)
					mComp := int((v - float32(hComp)) * 60)
					fmt.Printf("%d:%d\n", hComp, mComp)
				} else {
					log.Println(db[d.ID])
				}

				ct += n
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 JT Olds
// See LICENSE for copying information

package repo

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"

	gs_ssh "github.com/jtolds/gitserve/ssh"
	"github.com/spacemonkeygo/monotime"
	"golang.org/x/crypto/ssh"
)

type SubmissionHandler func(
	repo_path string,
	output io.Writer,
	meta ssh.ConnMetadata,
	key ssh.PublicKey,
	repo_name string, tags map[Ref][]Tag) (
	exit_status uint32,
	err error)

type AuthHandler func(meta ssh.ConnMetadata, key ssh.PublicKey) (
	unique_user_id *string, err error)

type NewRepoHandler func(
	repo_path string,
	output io.Writer,
	meta ssh.ConnMetadata,
	key ssh.PublicKey,
	repo_name string) error

type session struct {
	key            ssh.PublicKey
	unique_user_id string
}

type RepoSubmissions struct {
	PrivateKey        ssh.Signer
	ShellError        string
	MOTD              string
	StoragePath       string
	Clean             bool
	SubmissionHandler SubmissionHandler
	AuthHandler       AuthHandler
	NewRepoHandler    NewRepoHandler
	MaxPushSize       int64

	// If set, these commands override the default git-receive-pack and
	// git-upload-pack
	GitReceivePack string
	GitUploadPack  string

	mtx          sync.Mutex
	repo_lock_cv *sync.Cond
	sessions     map[string]*session
	repo_locks   map[string]bool
}

func (rs *RepoSubmissions) getSession(session_id []byte) *session {
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.sessions == nil {
		return nil
	}
	return rs.sessions[string(session_id)]
}

func (rs *RepoSubmissions) lockRepo(repo_id string) {
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.repo_lock_cv == nil {
		rs.repo_lock_cv = sync.NewCond(&rs.mtx)
	}
	if rs.repo_locks == nil {
		rs.repo_locks = make(map[string]bool)
	}
	for rs.repo_locks[repo_id] {
		rs.repo_lock_cv.Wait()
	}
	rs.repo_locks[repo_id] = true
}

func (rs *RepoSubmissions) unlockRepo(repo_id string) {
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	delete(rs.repo_locks, repo_id)
	rs.repo_lock_cv.Broadcast()
}

func userIdFromKey(key ssh.PublicKey) string {
	keyhash := sha256.Sum256(ssh.MarshalAuthorizedKey(key))
	return hex.EncodeToString(keyhash[:])
}

func (rs *RepoSubmissions) repoId(unique_user_id, repo_name string) string {
	mac := hmac.New(sha256.New, []byte(unique_user_id))
	mac.Write([]byte(repo_name))
	id := mac.Sum(nil)
	return hex.EncodeToString(id)
}

func (rs *RepoSubmissions) getUserRepo(repo_id string, output io.Writer,
	meta ssh.ConnMetadata, key ssh.PublicKey, repo_name string) (
	path string, err error) {
	user_repo := filepath.Join(rs.StoragePath, repo_id)
	_, err = os.Stat(user_repo)
	if err == nil {
		return user_repo, nil
	}
	if !os.IsNotExist(err) {
		return "", err
	}
	err = os.MkdirAll(user_repo, 0755)
	if err != nil {
		return "", err
	}

	if rs.NewRepoHandler != nil {
		err = rs.NewRepoHandler(user_repo, output, meta, key, repo_name)
		if err != nil {
			os.RemoveAll(user_repo)
			return "", err
		}
	} else {
		err = exec.Command(
			"git", "--git-dir", user_repo, "init", "--bare").Run()
		if err != nil {
			os.RemoveAll(user_repo)
			return "", err
		}
	}

	return user_repo, nil
}

func (rs *RepoSubmissions) cmdHandler(command string,
	stdin io.Reader, stdout, stderr io.Writer,
	meta ssh.ConnMetadata) (exit_status uint32, err error) {
	defer mon.Task()(&err)
	session := rs.getSession(meta.SessionID())
	if session == nil {
		panic("unauthorized?")
	}
	parts := strings.Split(command, " ")
	if len(parts) != 2 || (parts[0] != "git-receive-pack" &&
		parts[0] != "git-upload-pack") {
		_, err = fmt.Fprintf(stderr, "invalid command: %#v\r\n", command)
		return 1, err
	}

	repo_name := strings.Trim(parts[1], "'")

	repo_id := rs.repoId(session.unique_user_id, repo_name)
	rs.lockRepo(repo_id)
	user_repo, err := rs.getUserRepo(repo_id, stderr, meta, session.key,
		repo_name)
	if err != nil {
		rs.unlockRepo(repo_id)
		return 1, err
	}
	if rs.Clean {
		defer func() {
			os.RemoveAll(user_repo)
			rs.unlockRepo(repo_id)
		}()
	} else {
		rs.unlockRepo(repo_id)
	}

	if parts[0] != "git-receive-pack" {
		logger.Infof("git fetch: %s %s %s", meta.User(), repo_name, user_repo)
		os_cmd := "git-upload-pack"
		if rs.GitUploadPack != "" {
			os_cmd = rs.GitUploadPack
		}
		start_time := monotime.Monotonic()
		cmd := exec.Command(os_cmd, user_repo)
		cmd.Stdin = stdin
		cmd.Stdout = stdout
		cmd.Stderr = stderr
		exit_status, err = RunExec(cmd)
		logger.Noticef("git fetch: %s %s %s [took %s]", meta.User(), repo_name,
			user_repo, monotime.Monotonic()-start_time)
		return exit_status, err
	}

	logger.Infof("git push: %s %s %s", meta.User(), repo_name, user_repo)
	os_cmd := "git-receive-pack"
	if rs.GitReceivePack != "" {
		os_cmd = rs.GitReceivePack
	}
	start_time := monotime.Monotonic()
	cmd := exec.Command(os_cmd, user_repo)
	tags := &tagger{Reader: &maxReader{Reader: stdin, Max: rs.MaxPushSize}}
	cmd.Stdin = tags
	cmd.Stdout = stdout
	cmd.Stderr = stderr

	exit_status, err = RunExec(cmd)
	logger.Noticef("git push: %s %s %s [took %s]", meta.User(), repo_name,
		user_repo, monotime.Monotonic()-start_time)
	if err != nil {
		if tags.Err != nil {
			fmt.Fprintf(stderr, "error: %s\n", tags.Err)
		}
		return exit_status, err
	}

	if rs.SubmissionHandler != nil {
		start_time := monotime.Monotonic()
		exit_status, err = rs.SubmissionHandler(user_repo, stderr, meta,
			session.key, repo_name, tags.NewTags)
		logger.Infof("processed submission: %s %s %s [took %s]", meta.User(),
			repo_name, user_repo, monotime.Monotonic()-start_time)
		return exit_status, err
	}
	return 0, nil
}

func (rs *RepoSubmissions) publicKeyCallback(
	meta ssh.ConnMetadata, key ssh.PublicKey) (rv *ssh.Permissions, err error) {
	defer mon.Task()(&err)

	var unique_user_id *string
	if rs.AuthHandler != nil {
		unique_user_id, err = rs.AuthHandler(meta, key)
		if err != nil {
			return nil, err
		}
	}
	if unique_user_id == nil {
		id := userIdFromKey(key)
		unique_user_id = &id
	}

	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.sessions == nil {
		rs.sessions = make(map[string]*session)
	}

	session_id := string(meta.SessionID())
	if _, exists := rs.sessions[session_id]; exists {
		panic("session should be unique")
	}
	rs.sessions[session_id] = &session{key: key, unique_user_id: *unique_user_id}
	return nil, nil
}

func (rs *RepoSubmissions) sessionEnd(meta ssh.ConnMetadata) {
	defer mon.Task()(nil)
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.sessions != nil {
		delete(rs.sessions, string(meta.SessionID()))
	}
}

func (rs *RepoSubmissions) ListenAndServe(network, address string) (
	err error) {
	defer mon.Task()(&err)
	config := &ssh.ServerConfig{PublicKeyCallback: rs.publicKeyCallback}
	config.AddHostKey(rs.PrivateKey)
	return (&gs_ssh.RestrictedServer{
		SSHConfig:  config,
		ShellError: rs.ShellError,
		MOTD:       rs.MOTD,
		Handler:    rs.cmdHandler,
		SessionEnd: rs.sessionEnd}).ListenAndServe(network, address)
}
<commit_msg>support presubmission checking<commit_after>// Copyright (C) 2014 JT Olds
// See LICENSE for copying information

package repo

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"

	gs_ssh "github.com/jtolds/gitserve/ssh"
	"github.com/spacemonkeygo/monotime"
	"golang.org/x/crypto/ssh"
)

type SubmissionHandler func(
	repo_path string,
	output io.Writer,
	meta ssh.ConnMetadata,
	key ssh.PublicKey,
	repo_name string, tags map[Ref][]Tag) (
	exit_status uint32,
	err error)

type PresubmissionHandler func(
	repo_path string,
	output io.Writer,
	meta ssh.ConnMetadata,
	key ssh.PublicKey,
	repo_name string) (
	err error)

type AuthHandler func(meta ssh.ConnMetadata, key ssh.PublicKey) (
	unique_user_id *string, err error)

type NewRepoHandler func(
	repo_path string,
	output io.Writer,
	meta ssh.ConnMetadata,
	key ssh.PublicKey,
	repo_name string) error

type session struct {
	key            ssh.PublicKey
	unique_user_id string
}

type RepoSubmissions struct {
	PrivateKey           ssh.Signer
	ShellError           string
	MOTD                 string
	StoragePath          string
	Clean                bool
	PresubmissionHandler PresubmissionHandler
	SubmissionHandler    SubmissionHandler
	AuthHandler          AuthHandler
	NewRepoHandler       NewRepoHandler
	MaxPushSize          int64

	// If set, these commands override the default git-receive-pack and
	// git-upload-pack
	GitReceivePack string
	GitUploadPack  string

	mtx          sync.Mutex
	repo_lock_cv *sync.Cond
	sessions     map[string]*session
	repo_locks   map[string]bool
}

func (rs *RepoSubmissions) getSession(session_id []byte) *session {
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.sessions == nil {
		return nil
	}
	return rs.sessions[string(session_id)]
}

func (rs *RepoSubmissions) lockRepo(repo_id string) {
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.repo_lock_cv == nil {
		rs.repo_lock_cv = sync.NewCond(&rs.mtx)
	}
	if rs.repo_locks == nil {
		rs.repo_locks = make(map[string]bool)
	}
	for rs.repo_locks[repo_id] {
		rs.repo_lock_cv.Wait()
	}
	rs.repo_locks[repo_id] = true
}

func (rs *RepoSubmissions) unlockRepo(repo_id string) {
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	delete(rs.repo_locks, repo_id)
	rs.repo_lock_cv.Broadcast()
}

func userIdFromKey(key ssh.PublicKey) string {
	keyhash := sha256.Sum256(ssh.MarshalAuthorizedKey(key))
	return hex.EncodeToString(keyhash[:])
}

func (rs *RepoSubmissions) repoId(unique_user_id, repo_name string) string {
	mac := hmac.New(sha256.New, []byte(unique_user_id))
	mac.Write([]byte(repo_name))
	id := mac.Sum(nil)
	return hex.EncodeToString(id)
}

func (rs *RepoSubmissions) getUserRepo(repo_id string, output io.Writer,
	meta ssh.ConnMetadata, key ssh.PublicKey, repo_name string) (
	path string, err error) {
	user_repo := filepath.Join(rs.StoragePath, repo_id)
	_, err = os.Stat(user_repo)
	if err == nil {
		return user_repo, nil
	}
	if !os.IsNotExist(err) {
		return "", err
	}
	err = os.MkdirAll(user_repo, 0755)
	if err != nil {
		return "", err
	}

	if rs.NewRepoHandler != nil {
		err = rs.NewRepoHandler(user_repo, output, meta, key, repo_name)
		if err != nil {
			os.RemoveAll(user_repo)
			return "", err
		}
	} else {
		err = exec.Command(
			"git", "--git-dir", user_repo, "init", "--bare").Run()
		if err != nil {
			os.RemoveAll(user_repo)
			return "", err
		}
	}

	return user_repo, nil
}

func (rs *RepoSubmissions) cmdHandler(command string,
	stdin io.Reader, stdout, stderr io.Writer,
	meta ssh.ConnMetadata) (exit_status uint32, err error) {
	defer mon.Task()(&err)
	session := rs.getSession(meta.SessionID())
	if session == nil {
		panic("unauthorized?")
	}
	parts := strings.Split(command, " ")
	if len(parts) != 2 || (parts[0] != "git-receive-pack" &&
		parts[0] != "git-upload-pack") {
		_, err = fmt.Fprintf(stderr, "invalid command: %#v\r\n", command)
		return 1, err
	}

	repo_name := strings.Trim(parts[1], "'")

	repo_id := rs.repoId(session.unique_user_id, repo_name)
	rs.lockRepo(repo_id)
	user_repo, err := rs.getUserRepo(repo_id, stderr, meta, session.key,
		repo_name)
	if err != nil {
		rs.unlockRepo(repo_id)
		return 1, err
	}
	if rs.Clean {
		defer func() {
			os.RemoveAll(user_repo)
			rs.unlockRepo(repo_id)
		}()
	} else {
		rs.unlockRepo(repo_id)
	}

	if parts[0] != "git-receive-pack" {
		logger.Infof("git fetch: %s %s %s", meta.User(), repo_name, user_repo)
		os_cmd := "git-upload-pack"
		if rs.GitUploadPack != "" {
			os_cmd = rs.GitUploadPack
		}
		start_time := monotime.Monotonic()
		cmd := exec.Command(os_cmd, user_repo)
		cmd.Stdin = stdin
		cmd.Stdout = stdout
		cmd.Stderr = stderr
		exit_status, err = RunExec(cmd)
		logger.Noticef("git fetch: %s %s %s [took %s]", meta.User(), repo_name,
			user_repo, monotime.Monotonic()-start_time)
		return exit_status, err
	}

	if rs.PresubmissionHandler != nil {
		err := rs.PresubmissionHandler(user_repo, stderr, meta, session.key,
			repo_name)
		if err != nil {
			return 1, err
		}
	}

	logger.Infof("git push: %s %s %s", meta.User(), repo_name, user_repo)
	os_cmd := "git-receive-pack"
	if rs.GitReceivePack != "" {
		os_cmd = rs.GitReceivePack
	}
	start_time := monotime.Monotonic()
	cmd := exec.Command(os_cmd, user_repo)
	tags := &tagger{Reader: &maxReader{Reader: stdin, Max: rs.MaxPushSize}}
	cmd.Stdin = tags
	cmd.Stdout = stdout
	cmd.Stderr = stderr

	exit_status, err = RunExec(cmd)
	logger.Noticef("git push: %s %s %s [took %s]", meta.User(), repo_name,
		user_repo, monotime.Monotonic()-start_time)
	if err != nil {
		if tags.Err != nil {
			fmt.Fprintf(stderr, "error: %s\n", tags.Err)
		}
		return exit_status, err
	}

	if rs.SubmissionHandler != nil {
		start_time := monotime.Monotonic()
		exit_status, err = rs.SubmissionHandler(user_repo, stderr, meta,
			session.key, repo_name, tags.NewTags)
		logger.Infof("processed submission: %s %s %s [took %s]", meta.User(),
			repo_name, user_repo, monotime.Monotonic()-start_time)
		return exit_status, err
	}
	return 0, nil
}

func (rs *RepoSubmissions) publicKeyCallback(
	meta ssh.ConnMetadata, key ssh.PublicKey) (rv *ssh.Permissions, err error) {
	defer mon.Task()(&err)

	var unique_user_id *string
	if rs.AuthHandler != nil {
		unique_user_id, err = rs.AuthHandler(meta, key)
		if err != nil {
			return nil, err
		}
	}
	if unique_user_id == nil {
		id := userIdFromKey(key)
		unique_user_id = &id
	}

	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.sessions == nil {
		rs.sessions = make(map[string]*session)
	}

	session_id := string(meta.SessionID())
	if _, exists := rs.sessions[session_id]; exists {
		panic("session should be unique")
	}
	rs.sessions[session_id] = &session{key: key, unique_user_id: *unique_user_id}
	return nil, nil
}

func (rs *RepoSubmissions) sessionEnd(meta ssh.ConnMetadata) {
	defer mon.Task()(nil)
	rs.mtx.Lock()
	defer rs.mtx.Unlock()
	if rs.sessions != nil {
		delete(rs.sessions, string(meta.SessionID()))
	}
}

func (rs *RepoSubmissions) ListenAndServe(network, address string) (
	err error) {
	defer mon.Task()(&err)
	config := &ssh.ServerConfig{PublicKeyCallback: rs.publicKeyCallback}
	config.AddHostKey(rs.PrivateKey)
	return (&gs_ssh.RestrictedServer{
		SSHConfig:  config,
		ShellError: rs.ShellError,
		MOTD:       rs.MOTD,
		Handler:    rs.cmdHandler,
		SessionEnd: rs.sessionEnd}).ListenAndServe(network, address)
}
<|endoftext|>


<commit_before>package common

import (
	"math"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/henrylee2cn/pholcus/common/goquery"
	"github.com/henrylee2cn/pholcus/common/mahonia"
	"github.com/henrylee2cn/pholcus/common/ping"
)

// 清除标签
func CleanHtml(str string, depth int) string {
	if depth > 0 {
		//将HTML标签全转换成小写
		re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
		str = re.ReplaceAllStringFunc(str, strings.ToLower)
	}
	if depth > 1 {
		//去除STYLE
		re, _ := regexp.Compile("\\")
		str = re.ReplaceAllString(str, "")
	}
	if depth > 2 {
		//去除SCRIPT
		re, _ := regexp.Compile("\\")
		str = re.ReplaceAllString(str, "")
	}
	if depth > 3 {
		//去除所有尖括号内的HTML代码，并换成换行符
		re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
		str = re.ReplaceAllString(str, "\n")
	}
	if depth > 4 {
		//去除连续的换行符
		re, _ := regexp.Compile("\\s{2,}")
		str = re.ReplaceAllString(str, "\n")
	}
	return str
}

// 提取文章页的正文
// 思路：认为文本节点最长的标签的父标签为文章正文
func ExtractArticle(html string) string {
	//将HTML标签全转换成小写
	re := regexp.MustCompile("<[\\S\\s]+?>")
	html = re.ReplaceAllStringFunc(html, strings.ToLower)
	//去除head
	re = regexp.MustCompile("<head[\\S\\s]+?")
	html = re.ReplaceAllString(html, "")
	//去除STYLE
	re = regexp.MustCompile("")
	html = re.ReplaceAllString(html, "")
	//去除SCRIPT
	re = regexp.MustCompile("")
	html = re.ReplaceAllString(html, "")
	//去除注释
	re = regexp.MustCompile("<![\\S\\s]+?>")
	html = re.ReplaceAllString(html, "")
	// fmt.Println(html)

	// 获取每个子标签
	re = regexp.MustCompile("<[A-Za-z]+[^<]*>([^<>]+)</[A-Za-z]+>")
	ss := re.FindAllStringSubmatch(html, -1)
	// fmt.Printf("所有子标签：\n%#v\n", ss)

	var maxLen int
	var idx int
	for k, v := range ss {
		l := len([]rune(v[1]))
		if l > maxLen {
			maxLen = l
			idx = k
		}
	}
	// fmt.Println("最长段落：", ss[idx][0])

	html = strings.Replace(html, ss[idx][0], `<pholcus id="pholcus">`+ss[idx][1]+`</pholcus>`, -1)
	r := strings.NewReader(html)
	dom, err := goquery.NewDocumentFromReader(r)
	if err != nil {
		return ""
	}
	return dom.Find("pholcus#pholcus").Parent().Text()
}

// 去除常见转义字符
func Deprive(s string) string {
	s = strings.Replace(s, "\n", "", -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\t", "", -1)
	s = strings.Replace(s, ` `, "", -1)
	return s
}

// 去除常见转义字符
func Deprive2(s string) string {
	s = strings.Replace(s, "\n", "", -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\t", "", -1)
	s = strings.Replace(s, `\n`, "", -1)
	s = strings.Replace(s, `\r`, "", -1)
	s = strings.Replace(s, `\t`, "", -1)
	s = strings.Replace(s, ` `, "", -1)
	return s
}

// 舍去尾数
func Floor(f float64, n int) float64 {
	pow10_n := math.Pow10(n)
	return math.Trunc((f)*pow10_n) / pow10_n
}

// cookies字符串转[]*http.Cookie，（如"mt=ci%3D-1_0; thw=cn; sec=5572dc7c40ce07d4e8c67e4879a; v=0;"）
func SplitCookies(cookieStr string) (cookies []*http.Cookie) {
	slice := strings.Split(cookieStr, ";")
	for _, v := range slice {
		oneCookie := &http.Cookie{}
		s := strings.Split(v, "=")
		if len(s) == 2 {
			oneCookie.Name = strings.Trim(s[0], " ")
			oneCookie.Value = strings.Trim(s[1], " ")
			cookies = append(cookies, oneCookie)
		}
	}
	return
}

func DecodeString(src, charset string) string {
	return mahonia.NewDecoder(charset).ConvertString(src)
}

func EncodeString(src, charset string) string {
	return mahonia.NewEncoder(charset).ConvertString(src)
}

func ConvertToString(src string, srcCode string, tagCode string) string {
	srcCoder := mahonia.NewDecoder(srcCode)
	srcResult := srcCoder.ConvertString(src)
	tagCoder := mahonia.NewDecoder(tagCode)
	_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
	result := string(cdata)
	return result
}

// func GBKToUTF8(src string) string {
// 	return DecodeString(EncodeString(src, "ISO-8859-1"), "GBK")
// }

func GBKToUTF8(src string) string {
	return DecodeString(src, "GB18030")
}

//将"咖啡色|绿色"转为"咖啡色|绿色"
func UnicodeToUTF8(str string) string {
	str = strings.TrimLeft(str, "&#")
	str = strings.TrimRight(str, ";")
	strSlice := strings.Split(str, ";&#")

	for k, s := range strSlice {
		if i, err := strconv.Atoi(s); err == nil {
			strSlice[k] = string(i)
		}
	}
	return strings.Join(strSlice, "")
}

//将`{"area":[["quanguo","\u5168\u56fd\u8054\u9500"]]｝`转为`{"area":[["quanguo","全国联销"]]｝`
func Unicode16ToUTF8(str string) string {
	i := 0
	if strings.Index(str, `\u`) > 0 {
		i = 1
	}
	strSlice := strings.Split(str, `\u`)
	last := len(strSlice) - 1
	if len(strSlice[last]) > 4 {
		strSlice = append(strSlice, string(strSlice[last][4:]))
		strSlice[last] = string(strSlice[last][:4])
	}
	for ; i <= last; i++ {
		if x, err := strconv.ParseInt(strSlice[i], 16, 32); err == nil {
			strSlice[i] = string(x)
		}
	}
	return strings.Join(strSlice, "")
}

//@SchemeAndHost https://www.baidu.com
//@path /search?w=x
func MakeUrl(path string, schemeAndHost ...string) (string, bool) {
	if string(path[0]) != "/" && strings.ToLower(string(path[0])) != "h" {
		path = "/" + path
	}
	u := path
	idx := strings.Index(path, "://")
	if idx < 0 {
		if len(schemeAndHost) > 0 {
			u = schemeAndHost[0] + u
		} else {
			return u, false
		}
	}
	_, err := url.Parse(u)
	if err != nil {
		return u, false
	}
	return u, true
}

func Pinger(address string, timeoutSecond int) error {
	return ping.Pinger(address, timeoutSecond)
}

func Ping(address string, timeoutSecond int) (alive bool, err error, timedelay time.Duration) {
	return ping.Ping(address, timeoutSecond)
}

//html过滤注释
//var htmlReg = regexp.MustCompile(`(<!--(.)*-->)|([\s\v]+/*([^(/\*)]|[^(\*/)])*\*/)|([\t\n\f\r\v\v]+[#|//][^\t\n\f\r\v]+)`) //|([\r|\f|\t|\n|\v])
var htmlReg = regexp.MustCompile(`(\*{1,2}[\s\S]*?\*)|(<!-[\s\S]*?-->)|(^\s*\n)`) //(//[\s\S]*?\n)|

//处理html文件--add by lyken 20160512
func ProcessHtml(html string) string {
	//去除注释
	html = htmlReg.ReplaceAllString(html, "")
	//re := regexp.MustCompile("<![\\S\\s]+?>")
	//html = re.ReplaceAllString(html, "")

	//将HTML标签全转换成小写
	//re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
	//html = re.ReplaceAllStringFunc(html, strings.ToLower)

	//去除连续的换行符
	//re, _ = regexp.Compile("\\s{2,}")
	//html = re.ReplaceAllString(html, "\n")

	return html
}

//清除换行--add by lyken 20160512
func DepriveBreak(s string) string {
	s = strings.Replace(s, "\n", "", -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\t", "", -1)
	s = strings.Replace(s, `\n`, "", -1)
	s = strings.Replace(s, `\r`, "", -1)
	s = strings.Replace(s, `\t`, "", -1)
	return s
}

//多余的换行--add by lyken 20160819
func DepriveMutiBreak(s string) string {
	re, _ := regexp.Compile(`([^\n\f\r\t 　 ]*)([ 　 ]*[\n\f\r\t]+[ 　 ]*)+`)
	return re.ReplaceAllString(s, "${1}\n")

}

//在原有网址上添加参数--add by lyken 20160901
func HrefSub(src string, sub string) string {
	if len(sub) > 0 {
		if strings.Index(src, "?") > -1 {
			src += "&" + sub
		} else {
			src += "?" + sub
		}
	}
	return src
}

//域名获取 Reg
var domainReg = regexp.MustCompile(`([a-zA-Z0-9]+://([a-zA-Z0-9\:\_\-\.])+(/)?)(.)*`)

//网址组合--add by lyken 20160512
func GetHerf(baseurl string, url string, herf string, mustBase bool) string {
	if strings.HasPrefix(herf, `javascript:`) {
		return ``
	}
	result := ""
	herf = Deprive2(herf)
	if !strings.HasSuffix(baseurl, "/") {
		baseurl += "/"
	}

	if !mustBase && !strings.HasPrefix(url, baseurl) {
		baseurl = domainReg.ReplaceAllString(url, "$1")
	}

	refIndex := strings.LastIndex(url, "/") + 1
	/*sub := url[refIndex:]
	if !strings.HasSuffix(url, "/") {
		if strings.Index(sub, ".") == -1 &&
			strings.Index(sub, "?") == -1 &&
			strings.Index(sub, "#") == -1 {
			url = url + `/`
		} else {
			url = url[:refIndex]
		}
	}*/
	url = url[:refIndex]

	/*refIndex = strings.LastIndex(herf, "/") + 1
	sub = herf[refIndex:]
	if len(sub) > 0 &&
		strings.Index(sub, ".") == -1 &&
		strings.Index(sub, "?") == -1 &&
		strings.Index(sub, "#") == -1 {
		herf = herf + `/`
	}*/

	if strings.HasPrefix(herf, "./../") {
		herf = strings.Replace(herf, "./", "", 1)
	}

	if len(herf) == 0 {
		result = ""
	} else if herf == "/" {
		result = baseurl
	} else if strings.HasPrefix(herf, "./") {
		/*reg := regexp.MustCompile(`^(./)(.*)`)
		result = url + strings.Trim(reg.ReplaceAllString(herf, "$2"), " ")*/
		result = url + strings.Replace(herf, "./", "", 1)
	} else if strings.HasPrefix(herf, "/") {
		//reg = regexp.MustCompile(`^(http)(s)?(://)([0-9A-Za-z.\-_]+)(/)(.*)`)
		result = strings.Trim(baseurl, " ") + herf[1:]
	} else if mustBase && !strings.HasPrefix(herf, baseurl) &&
		(strings.Index(herf, "://") > -1 ||
			(strings.Index(herf, "/") == -1 &&
				strings.Count(herf, ".") > 3)) { //IP

		result = ""
	} else if strings.Index(herf, "://") > -1 ||
		(strings.Index(herf, "/") == -1 && strings.Count(herf, ".") > 3) { //IP
		result = herf
	} else {
		count := strings.Count(herf, "../")
		if count > 0 {
			urlArr := strings.SplitAfter(url, "/")
			len := cap(urlArr) - count - 1
			if len > 2 {
				preUrl := ""
				for i, str := range urlArr {
					if len > i {
						preUrl += str
					}
				}
				result = preUrl + strings.Replace(herf, "../", "", -1)
			}
		} else {
			result = url + herf
		}
	}

	/*if strings.Count(result, "://") > 1 {
		result = strings.SplitN(result, "://", 2)[1]
	}*/

	return result
}
<commit_msg>optimize code(#93): "\<" => "<" and “\\>” => ">"<commit_after>package common

import (
	"math"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/henrylee2cn/pholcus/common/goquery"
	"github.com/henrylee2cn/pholcus/common/mahonia"
	"github.com/henrylee2cn/pholcus/common/ping"
)

// 清除标签
func CleanHtml(str string, depth int) string {
	if depth > 0 {
		//将HTML标签全转换成小写
		re, _ := regexp.Compile("<[\\S\\s]+?>")
		str = re.ReplaceAllStringFunc(str, strings.ToLower)
	}
	if depth > 1 {
		//去除STYLE
		re, _ := regexp.Compile("")
		str = re.ReplaceAllString(str, "")
	}
	if depth > 2 {
		//去除SCRIPT
		re, _ := regexp.Compile("")
		str = re.ReplaceAllString(str, "")
	}
	if depth > 3 {
		//去除所有尖括号内的HTML代码，并换成换行符
		re, _ := regexp.Compile("<[\\S\\s]+?>")
		str = re.ReplaceAllString(str, "\n")
	}
	if depth > 4 {
		//去除连续的换行符
		re, _ := regexp.Compile("\\s{2,}")
		str = re.ReplaceAllString(str, "\n")
	}
	return str
}

// 提取文章页的正文
// 思路：认为文本节点最长的标签的父标签为文章正文
func ExtractArticle(html string) string {
	//将HTML标签全转换成小写
	re := regexp.MustCompile("<[\\S\\s]+?>")
	html = re.ReplaceAllStringFunc(html, strings.ToLower)
	//去除head
	re = regexp.MustCompile("<head[\\S\\s]+?")
	html = re.ReplaceAllString(html, "")
	//去除STYLE
	re = regexp.MustCompile("")
	html = re.ReplaceAllString(html, "")
	//去除SCRIPT
	re = regexp.MustCompile("")
	html = re.ReplaceAllString(html, "")
	//去除注释
	re = regexp.MustCompile("<![\\S\\s]+?>")
	html = re.ReplaceAllString(html, "")
	// fmt.Println(html)

	// 获取每个子标签
	re = regexp.MustCompile("<[A-Za-z]+[^<]*>([^<>]+)</[A-Za-z]+>")
	ss := re.FindAllStringSubmatch(html, -1)
	// fmt.Printf("所有子标签：\n%#v\n", ss)

	var maxLen int
	var idx int
	for k, v := range ss {
		l := len([]rune(v[1]))
		if l > maxLen {
			maxLen = l
			idx = k
		}
	}
	// fmt.Println("最长段落：", ss[idx][0])

	html = strings.Replace(html, ss[idx][0], `<pholcus id="pholcus">`+ss[idx][1]+`</pholcus>`, -1)
	r := strings.NewReader(html)
	dom, err := goquery.NewDocumentFromReader(r)
	if err != nil {
		return ""
	}
	return dom.Find("pholcus#pholcus").Parent().Text()
}

// 去除常见转义字符
func Deprive(s string) string {
	s = strings.Replace(s, "\n", "", -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\t", "", -1)
	s = strings.Replace(s, ` `, "", -1)
	return s
}

// 去除常见转义字符
func Deprive2(s string) string {
	s = strings.Replace(s, "\n", "", -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\t", "", -1)
	s = strings.Replace(s, `\n`, "", -1)
	s = strings.Replace(s, `\r`, "", -1)
	s = strings.Replace(s, `\t`, "", -1)
	s = strings.Replace(s, ` `, "", -1)
	return s
}

// 舍去尾数
func Floor(f float64, n int) float64 {
	pow10_n := math.Pow10(n)
	return math.Trunc((f)*pow10_n) / pow10_n
}

// cookies字符串转[]*http.Cookie，（如"mt=ci%3D-1_0; thw=cn; sec=5572dc7c40ce07d4e8c67e4879a; v=0;"）
func SplitCookies(cookieStr string) (cookies []*http.Cookie) {
	slice := strings.Split(cookieStr, ";")
	for _, v := range slice {
		oneCookie := &http.Cookie{}
		s := strings.Split(v, "=")
		if len(s) == 2 {
			oneCookie.Name = strings.Trim(s[0], " ")
			oneCookie.Value = strings.Trim(s[1], " ")
			cookies = append(cookies, oneCookie)
		}
	}
	return
}

func DecodeString(src, charset string) string {
	return mahonia.NewDecoder(charset).ConvertString(src)
}

func EncodeString(src, charset string) string {
	return mahonia.NewEncoder(charset).ConvertString(src)
}

func ConvertToString(src string, srcCode string, tagCode string) string {
	srcCoder := mahonia.NewDecoder(srcCode)
	srcResult := srcCoder.ConvertString(src)
	tagCoder := mahonia.NewDecoder(tagCode)
	_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
	result := string(cdata)
	return result
}

// func GBKToUTF8(src string) string {
// 	return DecodeString(EncodeString(src, "ISO-8859-1"), "GBK")
// }

func GBKToUTF8(src string) string {
	return DecodeString(src, "GB18030")
}

//将"咖啡色|绿色"转为"咖啡色|绿色"
func UnicodeToUTF8(str string) string {
	str = strings.TrimLeft(str, "&#")
	str = strings.TrimRight(str, ";")
	strSlice := strings.Split(str, ";&#")

	for k, s := range strSlice {
		if i, err := strconv.Atoi(s); err == nil {
			strSlice[k] = string(i)
		}
	}
	return strings.Join(strSlice, "")
}

//将`{"area":[["quanguo","\u5168\u56fd\u8054\u9500"]]｝`转为`{"area":[["quanguo","全国联销"]]｝`
func Unicode16ToUTF8(str string) string {
	i := 0
	if strings.Index(str, `\u`) > 0 {
		i = 1
	}
	strSlice := strings.Split(str, `\u`)
	last := len(strSlice) - 1
	if len(strSlice[last]) > 4 {
		strSlice = append(strSlice, string(strSlice[last][4:]))
		strSlice[last] = string(strSlice[last][:4])
	}
	for ; i <= last; i++ {
		if x, err := strconv.ParseInt(strSlice[i], 16, 32); err == nil {
			strSlice[i] = string(x)
		}
	}
	return strings.Join(strSlice, "")
}

//@SchemeAndHost https://www.baidu.com
//@path /search?w=x
func MakeUrl(path string, schemeAndHost ...string) (string, bool) {
	if string(path[0]) != "/" && strings.ToLower(string(path[0])) != "h" {
		path = "/" + path
	}
	u := path
	idx := strings.Index(path, "://")
	if idx < 0 {
		if len(schemeAndHost) > 0 {
			u = schemeAndHost[0] + u
		} else {
			return u, false
		}
	}
	_, err := url.Parse(u)
	if err != nil {
		return u, false
	}
	return u, true
}

func Pinger(address string, timeoutSecond int) error {
	return ping.Pinger(address, timeoutSecond)
}

func Ping(address string, timeoutSecond int) (alive bool, err error, timedelay time.Duration) {
	return ping.Ping(address, timeoutSecond)
}

//html过滤注释
//var htmlReg = regexp.MustCompile(`(<!--(.)*-->)|([\s\v]+/*([^(/\*)]|[^(\*/)])*\*/)|([\t\n\f\r\v\v]+[#|//][^\t\n\f\r\v]+)`) //|([\r|\f|\t|\n|\v])
var htmlReg = regexp.MustCompile(`(\*{1,2}[\s\S]*?\*)|(<!-[\s\S]*?-->)|(^\s*\n)`) //(//[\s\S]*?\n)|

//处理html文件--add by lyken 20160512
func ProcessHtml(html string) string {
	//去除注释
	html = htmlReg.ReplaceAllString(html, "")
	//re := regexp.MustCompile("<![\\S\\s]+?>")
	//html = re.ReplaceAllString(html, "")

	//将HTML标签全转换成小写
	//re, _ = regexp.Compile("<[\\S\\s]+?>")
	//html = re.ReplaceAllStringFunc(html, strings.ToLower)

	//去除连续的换行符
	//re, _ = regexp.Compile("\\s{2,}")
	//html = re.ReplaceAllString(html, "\n")

	return html
}

//清除换行--add by lyken 20160512
func DepriveBreak(s string) string {
	s = strings.Replace(s, "\n", "", -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\t", "", -1)
	s = strings.Replace(s, `\n`, "", -1)
	s = strings.Replace(s, `\r`, "", -1)
	s = strings.Replace(s, `\t`, "", -1)
	return s
}

//多余的换行--add by lyken 20160819
func DepriveMutiBreak(s string) string {
	re, _ := regexp.Compile(`([^\n\f\r\t 　 ]*)([ 　 ]*[\n\f\r\t]+[ 　 ]*)+`)
	return re.ReplaceAllString(s, "${1}\n")

}

//在原有网址上添加参数--add by lyken 20160901
func HrefSub(src string, sub string) string {
	if len(sub) > 0 {
		if strings.Index(src, "?") > -1 {
			src += "&" + sub
		} else {
			src += "?" + sub
		}
	}
	return src
}

//域名获取 Reg
var domainReg = regexp.MustCompile(`([a-zA-Z0-9]+://([a-zA-Z0-9\:\_\-\.])+(/)?)(.)*`)

//网址组合--add by lyken 20160512
func GetHerf(baseurl string, url string, herf string, mustBase bool) string {
	if strings.HasPrefix(herf, `javascript:`) {
		return ``
	}
	result := ""
	herf = Deprive2(herf)
	if !strings.HasSuffix(baseurl, "/") {
		baseurl += "/"
	}

	if !mustBase && !strings.HasPrefix(url, baseurl) {
		baseurl = domainReg.ReplaceAllString(url, "$1")
	}

	refIndex := strings.LastIndex(url, "/") + 1
	/*sub := url[refIndex:]
	if !strings.HasSuffix(url, "/") {
		if strings.Index(sub, ".") == -1 &&
			strings.Index(sub, "?") == -1 &&
			strings.Index(sub, "#") == -1 {
			url = url + `/`
		} else {
			url = url[:refIndex]
		}
	}*/
	url = url[:refIndex]

	/*refIndex = strings.LastIndex(herf, "/") + 1
	sub = herf[refIndex:]
	if len(sub) > 0 &&
		strings.Index(sub, ".") == -1 &&
		strings.Index(sub, "?") == -1 &&
		strings.Index(sub, "#") == -1 {
		herf = herf + `/`
	}*/

	if strings.HasPrefix(herf, "./../") {
		herf = strings.Replace(herf, "./", "", 1)
	}

	if len(herf) == 0 {
		result = ""
	} else if herf == "/" {
		result = baseurl
	} else if strings.HasPrefix(herf, "./") {
		/*reg := regexp.MustCompile(`^(./)(.*)`)
		result = url + strings.Trim(reg.ReplaceAllString(herf, "$2"), " ")*/
		result = url + strings.Replace(herf, "./", "", 1)
	} else if strings.HasPrefix(herf, "/") {
		//reg = regexp.MustCompile(`^(http)(s)?(://)([0-9A-Za-z.\-_]+)(/)(.*)`)
		result = strings.Trim(baseurl, " ") + herf[1:]
	} else if mustBase && !strings.HasPrefix(herf, baseurl) &&
		(strings.Index(herf, "://") > -1 ||
			(strings.Index(herf, "/") == -1 &&
				strings.Count(herf, ".") > 3)) { //IP

		result = ""
	} else if strings.Index(herf, "://") > -1 ||
		(strings.Index(herf, "/") == -1 && strings.Count(herf, ".") > 3) { //IP
		result = herf
	} else {
		count := strings.Count(herf, "../")
		if count > 0 {
			urlArr := strings.SplitAfter(url, "/")
			len := cap(urlArr) - count - 1
			if len > 2 {
				preUrl := ""
				for i, str := range urlArr {
					if len > i {
						preUrl += str
					}
				}
				result = preUrl + strings.Replace(herf, "../", "", -1)
			}
		} else {
			result = url + herf
		}
	}

	/*if strings.Count(result, "://") > 1 {
		result = strings.SplitN(result, "://", 2)[1]
	}*/

	return result
}
<|endoftext|>


<commit_before>package resize

import (
	"image"
	"image/color"
	"runtime"
	"testing"
)

var img = image.NewGray16(image.Rect(0, 0, 3, 3))

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	img.Set(1, 1, color.White)
}

func Test_Nearest(t *testing.T) {
	m := Resize(6, 0, img, NearestNeighbor)
	if m.At(1, 1) == m.At(2, 2) {
		t.Fail()
	}
}

func Test_Param1(t *testing.T) {
	m := Resize(0, 0, img, NearestNeighbor)
	if m.Bounds() != img.Bounds() {
		t.Fail()
	}
}

func Test_Param2(t *testing.T) {
	m := Resize(100, 0, img, NearestNeighbor)
	if m.Bounds() != image.Rect(0, 0, 100, 100) {
		t.Fail()
	}
}

func Test_ZeroImg(t *testing.T) {
	zeroImg := image.NewGray16(image.Rect(0, 0, 0, 0))

	m := Resize(0, 0, zeroImg, NearestNeighbor)
	if m.Bounds() != zeroImg.Bounds() {
		t.Fail()
	}
}

func Test_CorrectResize(t *testing.T) {
	zeroImg := image.NewGray16(image.Rect(0, 0, 256, 256))

	m := Resize(60, 0, zeroImg, NearestNeighbor)
	if m.Bounds() != image.Rect(0, 0, 60, 60) {
		t.Fail()
	}
}

func Benchmark_BigResize(b *testing.B) {
	var m image.Image
	for i := 0; i < b.N; i++ {
		m = Resize(1000, 1000, img, Lanczos3)
	}
	m.At(0, 0)
}

func Benchmark_Reduction(b *testing.B) {
	largeImg := image.NewRGBA(image.Rect(0, 0, 1000, 1000))

	var m image.Image
	for i := 0; i < b.N; i++ {
		m = Resize(300, 300, largeImg, Bicubic)
	}
	m.At(0, 0)
}
<commit_msg>Add benchmarks for Lanczos3Lut to compare it with Lanczos3 performance.<commit_after>package resize

import (
	"image"
	"image/color"
	"runtime"
	"testing"
)

var img = image.NewGray16(image.Rect(0, 0, 3, 3))

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	img.Set(1, 1, color.White)
}

func Test_Nearest(t *testing.T) {
	m := Resize(6, 0, img, NearestNeighbor)
	if m.At(1, 1) == m.At(2, 2) {
		t.Fail()
	}
}

func Test_Param1(t *testing.T) {
	m := Resize(0, 0, img, NearestNeighbor)
	if m.Bounds() != img.Bounds() {
		t.Fail()
	}
}

func Test_Param2(t *testing.T) {
	m := Resize(100, 0, img, NearestNeighbor)
	if m.Bounds() != image.Rect(0, 0, 100, 100) {
		t.Fail()
	}
}

func Test_ZeroImg(t *testing.T) {
	zeroImg := image.NewGray16(image.Rect(0, 0, 0, 0))

	m := Resize(0, 0, zeroImg, NearestNeighbor)
	if m.Bounds() != zeroImg.Bounds() {
		t.Fail()
	}
}

func Test_CorrectResize(t *testing.T) {
	zeroImg := image.NewGray16(image.Rect(0, 0, 256, 256))

	m := Resize(60, 0, zeroImg, NearestNeighbor)
	if m.Bounds() != image.Rect(0, 0, 60, 60) {
		t.Fail()
	}
}

func Benchmark_BigResizeLanczos3(b *testing.B) {
	var m image.Image
	for i := 0; i < b.N; i++ {
		m = Resize(1000, 1000, img, Lanczos3)
	}
	m.At(0, 0)
}

func Benchmark_BigResizeLanczos3Lut(b *testing.B) {
	var m image.Image
	for i := 0; i < b.N; i++ {
		m = Resize(1000, 1000, img, Lanczos3Lut)
	}
	m.At(0, 0)
}

func Benchmark_Reduction(b *testing.B) {
	largeImg := image.NewRGBA(image.Rect(0, 0, 1000, 1000))

	var m image.Image
	for i := 0; i < b.N; i++ {
		m = Resize(300, 300, largeImg, Bicubic)
	}
	m.At(0, 0)
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
	"testing"
)

func TestJenkinsTestsToStart(t *testing.T) {
	testCases := []struct {
		projects            []string
		expectedJenkinsTest []string
	}{
		{
			projects: []string{"release.js.core"},
			expectedJenkinsTest: []string{
				"vanadium-js-browser-integration",
				"vanadium-js-build-extension",
				"vanadium-js-node-integration",
				"vanadium-js-unit",
				"vanadium-js-vdl",
				"vanadium-js-vom",
				"vanadium-namespace-browser-test",
			},
		},
		{
			projects: []string{"release.go.core"},
			expectedJenkinsTest: []string{
				"vanadium-go-build",
				"vanadium-namespace-browser-test",
			},
		},
	}

	for _, test := range testCases {
		got, err := jenkinsTestsToStart(test.projects)
		if err != nil {
			t.Fatalf("want no errors, got: %v", err)
		}
		if !reflect.DeepEqual(test.expectedJenkinsTest, got) {
			t.Fatalf("want %v, got %v", test.expectedJenkinsTest, got)
		}
	}
}
<commit_msg>tools/postsubmit: fixing a test breakage caused by go/vcl/2411<commit_after>package main

import (
	"reflect"
	"testing"
)

// TODO(jingjin): Mock out a VANADIUM_ROOT instance and common.json so
// that changes to the actual common.json do not break this test.

func TestJenkinsTestsToStart(t *testing.T) {
	testCases := []struct {
		projects            []string
		expectedJenkinsTest []string
	}{
		{
			projects: []string{"release.js.core"},
			expectedJenkinsTest: []string{
				"vanadium-js-browser-integration",
				"vanadium-js-build-extension",
				"vanadium-js-node-integration",
				"vanadium-js-unit",
				"vanadium-js-vdl",
				"vanadium-js-vom",
				"vanadium-namespace-browser-test",
			},
		},
		{
			projects: []string{"release.go.core"},
			expectedJenkinsTest: []string{
				"vanadium-go-build",
				"vanadium-namespace-browser-test",
				"vanadium-www-tutorials",
			},
		},
	}

	for _, test := range testCases {
		got, err := jenkinsTestsToStart(test.projects)
		if err != nil {
			t.Fatalf("want no errors, got: %v", err)
		}
		if !reflect.DeepEqual(test.expectedJenkinsTest, got) {
			t.Fatalf("want %v, got %v", test.expectedJenkinsTest, got)
		}
	}
}
<|endoftext|>