From 5ffc9656c63ab44224819412c7d23b2881038844 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sun, 12 May 2019 13:29:07 -0400 Subject: [PATCH 001/220] Change drone token name to let users know to use oauth2 (#6912) --- routers/api/v1/user/app.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index c090a724b7..8e3b476d36 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -36,6 +36,9 @@ func ListAccessTokens(ctx *context.APIContext) { apiTokens := make([]*api.AccessToken, len(tokens)) for i := range tokens { + if tokens[i].Name == "drone" { + tokens[i].Name = "drone-legacy-use-oauth2-instead" + } apiTokens[i] = &api.AccessToken{ ID: tokens[i].ID, Name: tokens[i].Name, @@ -76,14 +79,18 @@ func CreateAccessToken(ctx *context.APIContext, form api.CreateAccessTokenOption UID: ctx.User.ID, Name: form.Name, } + if t.Name == "drone" { + t.Name = "drone-legacy-use-oauth2-instead" + } if err := models.NewAccessToken(t); err != nil { ctx.Error(500, "NewAccessToken", err) return } ctx.JSON(201, &api.AccessToken{ - Name: t.Name, - Token: t.Token, - ID: t.ID, + Name: t.Name, + Token: t.Token, + ID: t.ID, + TokenLastEight: t.TokenLastEight, }) } From 0b785481d71dfe43304eebbfa379b77dd87d48cb Mon Sep 17 00:00:00 2001 From: Mura Li Date: Mon, 13 May 2019 13:06:47 +0800 Subject: [PATCH 002/220] Use modules/git for git commands (#6775) --- models/pull.go | 124 +++++++++++++++++-------------------------------- 1 file changed, 42 insertions(+), 82 deletions(-) diff --git a/models/pull.go b/models/pull.go index 6f37145d9b..fe18765fc0 100644 --- a/models/pull.go +++ b/models/pull.go @@ -363,16 +363,13 @@ func (pr *PullRequest) CheckUserAllowedToMerge(doer *User) (err error) { func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) { getDiffTreeFromBranch := func(repoPath, baseBranch, headBranch string) (string, error) { - var stdout, stderr string + var outbuf, errbuf strings.Builder // Compute the diff-tree for sparse-checkout // The branch argument must be enclosed with double-quotes ("") in case it contains slashes (e.g "feature/test") - stdout, stderr, err := process.GetManager().ExecDir(-1, repoPath, - fmt.Sprintf("PullRequest.Merge (git diff-tree): %s", repoPath), - "git", "diff-tree", "--no-commit-id", "--name-only", "-r", "--root", baseBranch, headBranch) - if err != nil { - return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, stderr) + if err := git.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "--root", baseBranch, headBranch).RunInDirPipeline(repoPath, &outbuf, &errbuf); err != nil { + return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String()) } - return stdout, nil + return outbuf.String(), nil } list, err := getDiffTreeFromBranch(repoPath, baseBranch, headBranch) @@ -455,17 +452,15 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil { return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err) } - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath), - "git", "remote", "add", remoteRepoName, headRepoPath); err != nil { - return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + + var errbuf strings.Builder + if err := git.NewCommand("remote", "add", remoteRepoName, headRepoPath).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } // Fetch head branch - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath), - "git", "fetch", remoteRepoName); err != nil { - return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + if err := git.NewCommand("fetch", remoteRepoName).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } trackingBranch := path.Join(remoteRepoName, pr.HeadBranch) @@ -486,108 +481,75 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle return fmt.Errorf("Writing sparse-checkout file to %s: %v", sparseCheckoutListPath, err) } - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git config): %s", tmpBasePath), - "git", "config", "--local", "core.sparseCheckout", "true"); err != nil { - return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", stderr) + if err := git.NewCommand("config", "--local", "core.sparseCheckout", "true").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", errbuf.String()) } // Read base branch index - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git read-tree): %s", tmpBasePath), - "git", "read-tree", "HEAD"); err != nil { - return fmt.Errorf("git read-tree HEAD: %s", stderr) + if err := git.NewCommand("read-tree", "HEAD").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git read-tree HEAD: %s", errbuf.String()) } // Merge commits. switch mergeStyle { case MergeStyleMerge: - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath), - "git", "merge", "--no-ff", "--no-commit", trackingBranch); err != nil { - return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr) + if err := git.NewCommand("merge", "--no-ff", "--no-commit", trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) } sig := doer.NewGitSig() - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath), - "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), - "-m", message); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr) + if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) } case MergeStyleRebase: // Checkout head branch - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath), - "git", "checkout", "-b", stagingBranch, trackingBranch); err != nil { - return fmt.Errorf("git checkout: %s", stderr) + if err := git.NewCommand("checkout", "-b", stagingBranch, trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) } // Rebase before merging - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath), - "git", "rebase", "-q", pr.BaseBranch); err != nil { - return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } // Checkout base branch again - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath), - "git", "checkout", pr.BaseBranch); err != nil { - return fmt.Errorf("git checkout: %s", stderr) + if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) } // Merge fast forward - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath), - "git", "merge", "--ff-only", "-q", stagingBranch); err != nil { - return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + if err := git.NewCommand("merge", "--ff-only", "-q", stagingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } case MergeStyleRebaseMerge: // Checkout head branch - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath), - "git", "checkout", "-b", stagingBranch, trackingBranch); err != nil { - return fmt.Errorf("git checkout: %s", stderr) + if err := git.NewCommand("checkout", "-b", stagingBranch, trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) } // Rebase before merging - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath), - "git", "rebase", "-q", pr.BaseBranch); err != nil { - return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } // Checkout base branch again - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath), - "git", "checkout", pr.BaseBranch); err != nil { - return fmt.Errorf("git checkout: %s", stderr) + if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) } // Prepare merge with commit - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath), - "git", "merge", "--no-ff", "--no-commit", "-q", stagingBranch); err != nil { - return fmt.Errorf("git merge --no-ff [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + if err := git.NewCommand("merge", "--no-ff", "--no-commit", "-q", stagingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --no-ff [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } // Set custom message and author and create merge commit sig := doer.NewGitSig() - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git commit): %s", tmpBasePath), - "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), - "-m", message); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr) + if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) } case MergeStyleSquash: // Merge with squash - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git squash): %s", tmpBasePath), - "git", "merge", "-q", "--squash", trackingBranch); err != nil { - return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + if err := git.NewCommand("merge", "-q", "--squash", trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } sig := pr.Issue.Poster.NewGitSig() - if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git squash): %s", tmpBasePath), - "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), - "-m", message); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr) + if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) } default: return ErrInvalidMergeStyle{pr.BaseRepo.ID, mergeStyle} @@ -596,10 +558,8 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle env := PushingEnvironment(doer, pr.BaseRepo) // Push back to upstream. - if _, stderr, err := process.GetManager().ExecDirEnv(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath), - env, "git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil { - return fmt.Errorf("git push: %s", stderr) + if err := git.NewCommand("push", baseGitRepo.Path, pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git push: %s", errbuf.String()) } pr.MergedCommitID, err = baseGitRepo.GetBranchCommitID(pr.BaseBranch) From 6fb58a8cdcd76aa45902e50da8f2b450fe9d3d35 Mon Sep 17 00:00:00 2001 From: Xaver Maierhofer Date: Mon, 13 May 2019 08:26:32 +0200 Subject: [PATCH 003/220] Clean less files (#6921) --- public/css/index.css | 2 +- public/css/theme-arc-green.css | 2 +- public/less/_admin.less | 4 +- public/less/_base.less | 126 ++- public/less/_dashboard.less | 62 +- public/less/_editor.less | 9 +- public/less/_explore.less | 20 +- public/less/_form.less | 177 +-- public/less/_home.less | 98 +- public/less/_install.less | 8 + public/less/_markdown.less | 362 +++---- public/less/_organization.less | 9 +- public/less/_repository.less | 72 +- public/less/_review.less | 20 +- public/less/_tribute.less | 53 +- public/less/_user.less | 9 +- public/less/themes/arc-green.less | 1671 ++++++++++++++++------------- 17 files changed, 1545 insertions(+), 1159 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 8a7e61d500..1e4598ddb1 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -1 +1 @@ -.tribute-container{box-shadow:0 1px 3px 1px #c7c7c7}.tribute-container ul{background:#fff}.tribute-container li{padding:8px 12px;border-bottom:1px solid #dcdcdc}.tribute-container li img{display:inline-block;vertical-align:middle;width:28px;height:28px;margin-right:5px}.tribute-container li span.fullname{font-weight:400;font-size:.8rem;margin-left:3px}.tribute-container li.highlight,.tribute-container li:hover{background:#2185D0;color:#fff}.emoji{width:1.5em;height:1.5em;display:inline-block;background-size:contain}.ui.label .emoji{height:1.2em!important}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-regular.eot);src:url(../vendor/assets/lato-fonts/lato-regular.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-regular.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-regular.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-italic.eot);src:url(../vendor/assets/lato-fonts/lato-italic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-italic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-italic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bold.eot);src:url(../vendor/assets/lato-fonts/lato-bold.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bold.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bold.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot);src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bolditalic.ttf) format('truetype');font-weight:700;font-style:italic}@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Medium');font-weight:400}@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Bold');font-weight:700}textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}h1,h2,h3,h4,h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.home .hero h1,.home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.ui.accordion .title:not(.ui),.ui.button,.ui.card>.content>.header.ui.card>.content>.header,.ui.category.search>.results .category>.name,.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=file],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url],.ui.header,.ui.input input,.ui.input>input,.ui.items>.item>.content>.header,.ui.language>.menu>.item,.ui.list .list>.item .header,.ui.list>.item .header,.ui.menu,.ui.message .header,.ui.modal>.header,.ui.popup>.header,.ui.search>.results .result .title,.ui.search>.results>.message .header,.ui.statistic>.label,.ui.statistic>.value,.ui.statistics .statistic>.label,.ui.statistics .statistic>.value,.ui.steps .step .title,.ui.text.container,body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}body{background-color:#fff;overflow-y:auto;-webkit-font-smoothing:antialiased;display:flex;flex-direction:column}:lang(ja) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) h1,:lang(ja) h2,:lang(ja) h3,:lang(ja) h4,:lang(ja) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) .home .hero h1,:lang(ja) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}.ui.language>.menu>.item:lang(ja),:lang(ja) .ui.accordion .title:not(.ui),:lang(ja) .ui.button,:lang(ja) .ui.card>.content>.header.ui.card>.content>.header,:lang(ja) .ui.category.search>.results .category>.name,:lang(ja) .ui.form input:not([type]),:lang(ja) .ui.form input[type=date],:lang(ja) .ui.form input[type=datetime-local],:lang(ja) .ui.form input[type=email],:lang(ja) .ui.form input[type=file],:lang(ja) .ui.form input[type=number],:lang(ja) .ui.form input[type=password],:lang(ja) .ui.form input[type=search],:lang(ja) .ui.form input[type=tel],:lang(ja) .ui.form input[type=text],:lang(ja) .ui.form input[type=time],:lang(ja) .ui.form input[type=url],:lang(ja) .ui.header,:lang(ja) .ui.input input,:lang(ja) .ui.input>input,:lang(ja) .ui.items>.item>.content>.header,:lang(ja) .ui.list .list>.item .header,:lang(ja) .ui.list>.item .header,:lang(ja) .ui.menu,:lang(ja) .ui.message .header,:lang(ja) .ui.modal>.header,:lang(ja) .ui.popup>.header,:lang(ja) .ui.search>.results .result .title,:lang(ja) .ui.search>.results>.message .header,:lang(ja) .ui.statistic>.label,:lang(ja) .ui.statistic>.value,:lang(ja) .ui.statistics .statistic>.label,:lang(ja) .ui.statistics .statistic>.value,:lang(ja) .ui.steps .step .title,:lang(ja) .ui.text.container,:lang(ja) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(zh-CN) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) h1,:lang(zh-CN) h2,:lang(zh-CN) h3,:lang(zh-CN) h4,:lang(zh-CN) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) .home .hero h1,:lang(zh-CN) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}.ui.language>.menu>.item:lang(zh-CN),:lang(zh-CN) .ui.accordion .title:not(.ui),:lang(zh-CN) .ui.button,:lang(zh-CN) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-CN) .ui.category.search>.results .category>.name,:lang(zh-CN) .ui.form input:not([type]),:lang(zh-CN) .ui.form input[type=date],:lang(zh-CN) .ui.form input[type=datetime-local],:lang(zh-CN) .ui.form input[type=email],:lang(zh-CN) .ui.form input[type=file],:lang(zh-CN) .ui.form input[type=number],:lang(zh-CN) .ui.form input[type=password],:lang(zh-CN) .ui.form input[type=search],:lang(zh-CN) .ui.form input[type=tel],:lang(zh-CN) .ui.form input[type=text],:lang(zh-CN) .ui.form input[type=time],:lang(zh-CN) .ui.form input[type=url],:lang(zh-CN) .ui.header,:lang(zh-CN) .ui.input input,:lang(zh-CN) .ui.input>input,:lang(zh-CN) .ui.items>.item>.content>.header,:lang(zh-CN) .ui.list .list>.item .header,:lang(zh-CN) .ui.list>.item .header,:lang(zh-CN) .ui.menu,:lang(zh-CN) .ui.message .header,:lang(zh-CN) .ui.modal>.header,:lang(zh-CN) .ui.popup>.header,:lang(zh-CN) .ui.search>.results .result .title,:lang(zh-CN) .ui.search>.results>.message .header,:lang(zh-CN) .ui.statistic>.label,:lang(zh-CN) .ui.statistic>.value,:lang(zh-CN) .ui.statistics .statistic>.label,:lang(zh-CN) .ui.statistics .statistic>.value,:lang(zh-CN) .ui.steps .step .title,:lang(zh-CN) .ui.text.container,:lang(zh-CN) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-TW) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) h1,:lang(zh-TW) h2,:lang(zh-TW) h3,:lang(zh-TW) h4,:lang(zh-TW) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) .home .hero h1,:lang(zh-TW) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}.ui.language>.menu>.item:lang(zh-TW),:lang(zh-TW) .ui.accordion .title:not(.ui),:lang(zh-TW) .ui.button,:lang(zh-TW) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-TW) .ui.category.search>.results .category>.name,:lang(zh-TW) .ui.form input:not([type]),:lang(zh-TW) .ui.form input[type=date],:lang(zh-TW) .ui.form input[type=datetime-local],:lang(zh-TW) .ui.form input[type=email],:lang(zh-TW) .ui.form input[type=file],:lang(zh-TW) .ui.form input[type=number],:lang(zh-TW) .ui.form input[type=password],:lang(zh-TW) .ui.form input[type=search],:lang(zh-TW) .ui.form input[type=tel],:lang(zh-TW) .ui.form input[type=text],:lang(zh-TW) .ui.form input[type=time],:lang(zh-TW) .ui.form input[type=url],:lang(zh-TW) .ui.header,:lang(zh-TW) .ui.input input,:lang(zh-TW) .ui.input>input,:lang(zh-TW) .ui.items>.item>.content>.header,:lang(zh-TW) .ui.list .list>.item .header,:lang(zh-TW) .ui.list>.item .header,:lang(zh-TW) .ui.menu,:lang(zh-TW) .ui.message .header,:lang(zh-TW) .ui.modal>.header,:lang(zh-TW) .ui.popup>.header,:lang(zh-TW) .ui.search>.results .result .title,:lang(zh-TW) .ui.search>.results>.message .header,:lang(zh-TW) .ui.statistic>.label,:lang(zh-TW) .ui.statistic>.value,:lang(zh-TW) .ui.statistics .statistic>.label,:lang(zh-TW) .ui.statistics .statistic>.value,:lang(zh-TW) .ui.steps .step .title,:lang(zh-TW) .ui.text.container,:lang(zh-TW) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-HK) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) h1,:lang(zh-HK) h2,:lang(zh-HK) h3,:lang(zh-HK) h4,:lang(zh-HK) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) .home .hero h1,:lang(zh-HK) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}.ui.language>.menu>.item:lang(zh-HK),:lang(zh-HK) .ui.accordion .title:not(.ui),:lang(zh-HK) .ui.button,:lang(zh-HK) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-HK) .ui.category.search>.results .category>.name,:lang(zh-HK) .ui.form input:not([type]),:lang(zh-HK) .ui.form input[type=date],:lang(zh-HK) .ui.form input[type=datetime-local],:lang(zh-HK) .ui.form input[type=email],:lang(zh-HK) .ui.form input[type=file],:lang(zh-HK) .ui.form input[type=number],:lang(zh-HK) .ui.form input[type=password],:lang(zh-HK) .ui.form input[type=search],:lang(zh-HK) .ui.form input[type=tel],:lang(zh-HK) .ui.form input[type=text],:lang(zh-HK) .ui.form input[type=time],:lang(zh-HK) .ui.form input[type=url],:lang(zh-HK) .ui.header,:lang(zh-HK) .ui.input input,:lang(zh-HK) .ui.input>input,:lang(zh-HK) .ui.items>.item>.content>.header,:lang(zh-HK) .ui.list .list>.item .header,:lang(zh-HK) .ui.list>.item .header,:lang(zh-HK) .ui.menu,:lang(zh-HK) .ui.message .header,:lang(zh-HK) .ui.modal>.header,:lang(zh-HK) .ui.popup>.header,:lang(zh-HK) .ui.search>.results .result .title,:lang(zh-HK) .ui.search>.results>.message .header,:lang(zh-HK) .ui.statistic>.label,:lang(zh-HK) .ui.statistic>.value,:lang(zh-HK) .ui.statistics .statistic>.label,:lang(zh-HK) .ui.statistics .statistic>.value,:lang(zh-HK) .ui.steps .step .title,:lang(zh-HK) .ui.text.container,:lang(zh-HK) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(ko) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) h1,:lang(ko) h2,:lang(ko) h3,:lang(ko) h4,:lang(ko) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) .home .hero h1,:lang(ko) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}.ui.language>.menu>.item:lang(ko),:lang(ko) .ui.accordion .title:not(.ui),:lang(ko) .ui.button,:lang(ko) .ui.card>.content>.header.ui.card>.content>.header,:lang(ko) .ui.category.search>.results .category>.name,:lang(ko) .ui.form input:not([type]),:lang(ko) .ui.form input[type=date],:lang(ko) .ui.form input[type=datetime-local],:lang(ko) .ui.form input[type=email],:lang(ko) .ui.form input[type=file],:lang(ko) .ui.form input[type=number],:lang(ko) .ui.form input[type=password],:lang(ko) .ui.form input[type=search],:lang(ko) .ui.form input[type=tel],:lang(ko) .ui.form input[type=text],:lang(ko) .ui.form input[type=time],:lang(ko) .ui.form input[type=url],:lang(ko) .ui.header,:lang(ko) .ui.input input,:lang(ko) .ui.input>input,:lang(ko) .ui.items>.item>.content>.header,:lang(ko) .ui.list .list>.item .header,:lang(ko) .ui.list>.item .header,:lang(ko) .ui.menu,:lang(ko) .ui.message .header,:lang(ko) .ui.modal>.header,:lang(ko) .ui.popup>.header,:lang(ko) .ui.search>.results .result .title,:lang(ko) .ui.search>.results>.message .header,:lang(ko) .ui.statistic>.label,:lang(ko) .ui.statistic>.value,:lang(ko) .ui.statistics .statistic>.label,:lang(ko) .ui.statistics .statistic>.value,:lang(ko) .ui.steps .step .title,:lang(ko) .ui.text.container,:lang(ko) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}img{border-radius:3px}table{border-collapse:collapse}a{cursor:pointer}.rounded{border-radius:.28571429rem!important}code,pre{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto}code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word}.dont-break-out{overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.full.height{flex-grow:1;padding-bottom:80px}.following.bar{z-index:900;left:0;margin:0!important}.following.bar.light{background-color:#fff;border-bottom:1px solid #DDD;box-shadow:0 2px 3px rgba(0,0,0,.04)}.following.bar .column .menu{margin-top:0}.following.bar .top.menu a.item.brand{padding-left:0}.following.bar .brand .ui.mini.image{width:30px}.following.bar .top.menu .dropdown.item.active,.following.bar .top.menu .dropdown.item:hover,.following.bar .top.menu a.item:hover{background-color:transparent}.following.bar .top.menu a.item:hover{color:rgba(0,0,0,.45)}.following.bar .top.menu .menu{z-index:900}.following.bar .octicon{margin-right:.75em}.following.bar .octicon.fitted{margin-right:0}.following.bar .searchbox{background-color:#f4f4f4!important}.following.bar .searchbox:focus{background-color:#e9e9e9!important}.following.bar .text .octicon{width:16px;text-align:center}.following.bar #navbar{width:100vw;min-height:52px;padding:0 .5rem}.following.bar #navbar .brand{margin:0}@media only screen and (max-width:767px){.following.bar #navbar:not(.shown)>:not(:first-child){display:none}}.right.stackable.menu{margin-left:auto;display:flex;align-items:inherit;flex-direction:inherit}.ui.left{float:left}.ui.right{float:right}.ui.button,.ui.menu .item{-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto}.ui.container.fluid.padded{padding:0 10px 0 10px}.ui.form .ui.button{font-weight:400}.ui.floating.label{z-index:10}.ui.transparent.label{background-color:transparent}.ui.menu,.ui.segment,.ui.vertical.menu{box-shadow:none}.ui .menu:not(.vertical) .item>.button.compact{padding:.58928571em 1.125em}.ui .menu:not(.vertical) .item>.button.small{font-size:.92857143rem}.ui.menu .ui.dropdown.item .menu .item{margin-right:auto}.ui.dropdown .menu>.item>.floating.label{z-index:11}.ui.dropdown .menu .menu>.item>.floating.label{z-index:21}.ui .text.red{color:#d95c5c!important}.ui .text.red a{color:#d95c5c!important}.ui .text.red a:hover{color:#E67777!important}.ui .text.blue{color:#428bca!important}.ui .text.blue a{color:#15c!important}.ui .text.blue a:hover{color:#428bca!important}.ui .text.black{color:#444}.ui .text.black:hover{color:#000}.ui .text.grey{color:#767676!important}.ui .text.grey a{color:#444!important}.ui .text.grey a:hover{color:#000!important}.ui .text.light.grey{color:#888!important}.ui .text.green{color:#6cc644!important}.ui .text.purple{color:#6e5494!important}.ui .text.yellow{color:#FBBD08!important}.ui .text.gold{color:#a1882b!important}.ui .text.left{text-align:left!important}.ui .text.right{text-align:right!important}.ui .text.small{font-size:.75em}.ui .text.normal{font-weight:400}.ui .text.bold{font-weight:700}.ui .text.italic{font-style:italic}.ui .text.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}.ui .text.thin{font-weight:400}.ui .text.middle{vertical-align:middle}.ui .message{text-align:center}.ui.bottom.attached.message{font-weight:700;text-align:left;color:#000}.ui.bottom.attached.message .pull-right{color:#000}.ui.bottom.attached.message .pull-right>span,.ui.bottom.attached.message>span{color:#21ba45}.ui .header>i+.content{padding-left:.75rem;vertical-align:middle}.ui .warning.header{background-color:#F9EDBE!important;border-color:#F0C36D}.ui .warning.segment{border-color:#F0C36D}.ui .info.segment{border:1px solid #c5d5dd}.ui .info.segment.top{background-color:#e6f1f6!important}.ui .info.segment.top h3,.ui .info.segment.top h4{margin-top:0}.ui .info.segment.top h3:last-child{margin-top:4px}.ui .info.segment.top>:last-child{margin-bottom:0}.ui .normal.header{font-weight:400}.ui .avatar.image{border-radius:3px}.ui .form .fake{display:none!important}.ui .form .sub.field{margin-left:25px}.ui .sha.label{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;font-size:13px;padding:6px 10px 4px 10px;font-weight:400;margin:0 6px}.ui.status.buttons .octicon{margin-right:4px}.ui.inline.delete-button{padding:8px 15px;font-weight:400}.ui .background.red{background-color:#d95c5c!important}.ui .background.blue{background-color:#428bca!important}.ui .background.black{background-color:#444}.ui .background.grey{background-color:#767676!important}.ui .background.light.grey{background-color:#888!important}.ui .background.green{background-color:#6cc644!important}.ui .background.purple{background-color:#6e5494!important}.ui .background.yellow{background-color:#FBBD08!important}.ui .background.gold{background-color:#a1882b!important}.ui .branch-tag-choice{line-height:20px}@media only screen and (max-width:767px){.ui.pagination.menu .item.navigation span.navigation_label,.ui.pagination.menu .item:not(.active):not(.navigation){display:none}}.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)}.ui.floating.dropdown .overflow.menu .scrolling.menu.items{border-radius:0!important;box-shadow:none!important;border-bottom:1px solid rgba(34,36,38,.15)}.user-menu>.item{width:100%;border-radius:0!important}.scrolling.menu .item.selected{font-weight:700!important}footer{background-color:#fff;border-top:1px solid #d6d6d6;width:100%;flex-basis:40px;color:#888}footer .container{width:100vw!important;padding:0 .5rem}footer .container .fa{width:16px;text-align:center;color:#428bca}footer .container .links>*{border-left:1px solid #d6d6d6;padding-left:8px;margin-left:5px}footer .container .links>:first-child{border-left:none}footer .ui.language .menu{max-height:500px;overflow-y:auto;margin-bottom:7px}footer .ui.left,footer .ui.right{line-height:40px}.hide{display:none}.hide.show-outdated{display:none!important}.hide.hide-outdated{display:none!important}.center{text-align:center}.img-1{width:2px!important;height:2px!important}.img-2{width:4px!important;height:4px!important}.img-3{width:6px!important;height:6px!important}.img-4{width:8px!important;height:8px!important}.img-5{width:10px!important;height:10px!important}.img-6{width:12px!important;height:12px!important}.img-7{width:14px!important;height:14px!important}.img-8{width:16px!important;height:16px!important}.img-9{width:18px!important;height:18px!important}.img-10{width:20px!important;height:20px!important}.img-11{width:22px!important;height:22px!important}.img-12{width:24px!important;height:24px!important}.img-13{width:26px!important;height:26px!important}.img-14{width:28px!important;height:28px!important}.img-15{width:30px!important;height:30px!important}.img-16{width:32px!important;height:32px!important}@media only screen and (min-width:768px){.mobile-only,.ui.button.mobile-only{display:none}.sr-mobile-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}}@media only screen and (max-width:767px){.not-mobile{display:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}@media only screen and (max-width:991px) and (min-width:768px){.ui.container{width:95%}}.hljs{background:inherit!important;padding:0!important}.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}@media only screen and (max-width:1200px){.ui.menu.new-menu{overflow-x:auto!important;justify-content:left!important;padding-bottom:5px}.ui.menu.new-menu::-webkit-scrollbar{height:8px;display:none}.ui.menu.new-menu:hover::-webkit-scrollbar{display:block}.ui.menu.new-menu::-webkit-scrollbar-track{background:rgba(0,0,0,.01)}.ui.menu.new-menu::-webkit-scrollbar-thumb{background:rgba(0,0,0,.2)}.ui.menu.new-menu:after{position:absolute;margin-top:-15px;display:block;background-image:linear-gradient(to right,rgba(255,255,255,0),#fff 100%);content:' ';right:0;height:53px;z-index:1000;width:60px;clear:none;visibility:visible}.ui.menu.new-menu a.item:last-child{padding-right:30px!important}}[v-cloak]{display:none!important}.repos-search{padding-bottom:0!important}.repos-filter{margin-top:0!important;border-bottom-width:0!important;margin-bottom:2px!important}#user-heatmap{width:107%;text-align:center}#user-heatmap svg:not(:root){overflow:inherit;padding:0!important}@media only screen and (max-width:1200px){#user-heatmap{display:none}}.heatmap-color-0{background-color:#f4f4f4}.heatmap-color-1{background-color:#d7e5db}.heatmap-color-2{background-color:#adc7ab}.heatmap-color-3{background-color:#83a87b}.heatmap-color-4{background-color:#598a4b}.heatmap-color-5{background-color:#2f6b1b}.archived-icon{color:#b3b3b3!important}.archived-icon{color:#b3b3b3!important}.oauth2-authorize-application-box{margin-top:3em!important}.ui.tabular.menu .item{color:rgba(0,0,0,.5)}.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}.markdown:not(code).ui.segment{padding:3em}.markdown:not(code).file-view{padding:2em 2em 2em!important}.markdown:not(code)>:first-child{margin-top:0!important}.markdown:not(code)>:last-child{margin-bottom:0!important}.markdown:not(code) a:not([href]){color:inherit;text-decoration:none}.markdown:not(code) .absent{color:#c00}.markdown:not(code) .anchor{position:absolute;top:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown:not(code) .anchor:focus{outline:0}.markdown:not(code) h1,.markdown:not(code) h2,.markdown:not(code) h3,.markdown:not(code) h4,.markdown:not(code) h5,.markdown:not(code) h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}.markdown:not(code) h1:first-of-type,.markdown:not(code) h2:first-of-type,.markdown:not(code) h3:first-of-type,.markdown:not(code) h4:first-of-type,.markdown:not(code) h5:first-of-type,.markdown:not(code) h6:first-of-type{margin-top:0!important}.markdown:not(code) h1 .octicon-link,.markdown:not(code) h2 .octicon-link,.markdown:not(code) h3 .octicon-link,.markdown:not(code) h4 .octicon-link,.markdown:not(code) h5 .octicon-link,.markdown:not(code) h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown:not(code) h1:hover .anchor,.markdown:not(code) h2:hover .anchor,.markdown:not(code) h3:hover .anchor,.markdown:not(code) h4:hover .anchor,.markdown:not(code) h5:hover .anchor,.markdown:not(code) h6:hover .anchor{padding-left:8px;margin-left:-30px;text-decoration:none}.markdown:not(code) h1:hover .anchor .octicon-link,.markdown:not(code) h2:hover .anchor .octicon-link,.markdown:not(code) h3:hover .anchor .octicon-link,.markdown:not(code) h4:hover .anchor .octicon-link,.markdown:not(code) h5:hover .anchor .octicon-link,.markdown:not(code) h6:hover .anchor .octicon-link{display:inline-block}.markdown:not(code) h1 code,.markdown:not(code) h1 tt,.markdown:not(code) h2 code,.markdown:not(code) h2 tt,.markdown:not(code) h3 code,.markdown:not(code) h3 tt,.markdown:not(code) h4 code,.markdown:not(code) h4 tt,.markdown:not(code) h5 code,.markdown:not(code) h5 tt,.markdown:not(code) h6 code,.markdown:not(code) h6 tt{font-size:inherit}.markdown:not(code) h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee}.markdown:not(code) h1 .anchor{line-height:1}.markdown:not(code) h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee}.markdown:not(code) h2 .anchor{line-height:1}.markdown:not(code) h3{font-size:1.5em;line-height:1.43}.markdown:not(code) h3 .anchor{line-height:1.2}.markdown:not(code) h4{font-size:1.25em}.markdown:not(code) h4 .anchor{line-height:1.2}.markdown:not(code) h5{font-size:1em}.markdown:not(code) h5 .anchor{line-height:1.1}.markdown:not(code) h6{font-size:1em;color:#777}.markdown:not(code) h6 .anchor{line-height:1.1}.markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px}.markdown:not(code) blockquote{margin-left:0}.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none}.markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em}.markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none}.markdown:not(code) ol ol,.markdown:not(code) ol ul,.markdown:not(code) ul ol,.markdown:not(code) ul ul{margin-top:0;margin-bottom:0}.markdown:not(code) ol ol,.markdown:not(code) ul ol{list-style-type:lower-roman}.markdown:not(code) li>p{margin-top:0}.markdown:not(code) dl{padding:0}.markdown:not(code) dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown:not(code) dl dd{padding:0 16px;margin-bottom:16px}.markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown:not(code) blockquote>:first-child{margin-top:0}.markdown:not(code) blockquote>:last-child{margin-bottom:0}.markdown:not(code) table{width:auto;overflow:auto;word-break:normal;word-break:keep-all;display:block}.markdown:not(code) table th{font-weight:700}.markdown:not(code) table td,.markdown:not(code) table th{padding:6px 13px!important;border:1px solid #ddd!important}.markdown:not(code) table tr{background-color:#fff;border-top:1px solid #ccc}.markdown:not(code) table tr:nth-child(2n){background-color:#f8f8f8}.markdown:not(code) img{max-width:100%;box-sizing:border-box}.markdown:not(code) .emoji{max-width:none}.markdown:not(code) span.frame{display:block;overflow:hidden}.markdown:not(code) span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown:not(code) span.frame span img{display:block;float:left}.markdown:not(code) span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown:not(code) span.align-center{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown:not(code) span.align-center span img{margin:0 auto;text-align:center}.markdown:not(code) span.align-right{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown:not(code) span.align-right span img{margin:0;text-align:right}.markdown:not(code) span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown:not(code) span.float-left span{margin:13px 0 0}.markdown:not(code) span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown:not(code) span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown:not(code) code,.markdown:not(code) tt{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown:not(code) code:after,.markdown:not(code) code:before,.markdown:not(code) tt:after,.markdown:not(code) tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown:not(code) code br,.markdown:not(code) tt br{display:none}.markdown:not(code) del code{text-decoration:inherit}.markdown:not(code) pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown:not(code) .highlight{margin-bottom:16px}.markdown:not(code) .highlight pre,.markdown:not(code) pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown:not(code) .highlight pre{margin-bottom:0;word-break:normal}.markdown:not(code) pre{word-wrap:normal}.markdown:not(code) pre code,.markdown:not(code) pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown:not(code) pre code:after,.markdown:not(code) pre code:before,.markdown:not(code) pre tt:after,.markdown:not(code) pre tt:before{content:normal}.markdown:not(code) kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:solid 1px #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown:not(code) input[type=checkbox]{vertical-align:middle!important}.markdown:not(code) .csv-data td,.markdown:not(code) .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown:not(code) .csv-data .blob-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown:not(code) .csv-data tr{border-top:0}.markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em}.home .logo{max-width:220px}@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em}.home .hero h2{font-size:2em}}@media only screen and (min-width:768px){.home .hero h1{font-size:5.5em}.home .hero h2{font-size:3em}}.home .hero .octicon{color:#5aa509;font-size:40px;width:50px}.home .hero.header{font-size:20px}.home p.large{font-size:16px}.home .stackable{padding-top:30px}.home a{color:#5aa509}.signup{padding-top:15px}@media only screen and (max-width:880px){footer .ui.container .left,footer .ui.container .right{display:block;text-align:center;float:none}}.install{padding-top:45px}.install form label{text-align:right;width:320px!important}.install form input{width:35%!important}.install form .field{text-align:left}.install form .field .help{margin-left:335px!important}.install form .field.optional .title{margin-left:38%}.install .ui .checkbox{margin-left:40%!important}.install .ui .checkbox label{width:auto!important}.form .help{color:#999;padding-top:.6em;padding-bottom:.6em;display:inline-block}.ui.attached.header{background:#f0f0f0}.ui.attached.header .right{margin-top:-5px}.ui.attached.header .right .button{padding:8px 10px;font-weight:400}#create-page-form form{margin:auto}#create-page-form form .ui.message{text-align:center}@media only screen and (min-width:768px){#create-page-form form{width:800px!important}#create-page-form form .header{padding-left:280px!important}#create-page-form form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}#create-page-form form .help{margin-left:265px!important}#create-page-form form .optional .title{margin-left:250px!important}#create-page-form form input,#create-page-form form textarea{width:50%!important}}@media only screen and (max-width:767px){#create-page-form form .optional .title{margin-left:15px}#create-page-form form .inline.field>label{display:block}}.signin .oauth2 div{display:inline-block}.signin .oauth2 div p{margin:10px 5px 0 0;float:left}.signin .oauth2 a{margin-right:3px}.signin .oauth2 a:last-child{margin-right:0}.signin .oauth2 img{width:32px;height:32px}.signin .oauth2 img.openidConnect{width:auto}@media only screen and (min-width:768px){.g-recaptcha{margin:0 auto!important;width:304px;padding-left:30px}}@media screen and (max-height:575px){#rc-imageselect,.g-recaptcha{transform:scale(.77);transform-origin:0 0}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{margin:auto}.user.activate form .ui.message,.user.forgot.password form .ui.message,.user.reset.password form .ui.message,.user.signin form .ui.message,.user.signup form .ui.message{text-align:center}@media only screen and (min-width:768px){.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:800px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:280px!important}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.user.activate form .help,.user.forgot.password form .help,.user.reset.password form .help,.user.signin form .help,.user.signup form .help{margin-left:265px!important}.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:250px!important}.user.activate form input,.user.activate form textarea,.user.forgot.password form input,.user.forgot.password form textarea,.user.reset.password form input,.user.reset.password form textarea,.user.signin form input,.user.signin form textarea,.user.signup form input,.user.signup form textarea{width:50%!important}}@media only screen and (max-width:767px){.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:15px}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{display:block}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:700px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:0!important;text-align:center}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{width:200px}@media only screen and (max-width:768px){.user.activate form .inline.field>label,.user.activate form input,.user.forgot.password form .inline.field>label,.user.forgot.password form input,.user.reset.password form .inline.field>label,.user.reset.password form input,.user.signin form .inline.field>label,.user.signin form input,.user.signup form .inline.field>label,.user.signup form input{width:100%!important}}.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{margin:auto}.repository.new.fork form .ui.message,.repository.new.migrate form .ui.message,.repository.new.repo form .ui.message{text-align:center}@media only screen and (min-width:768px){.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{width:800px!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:280px!important}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.repository.new.fork form .help,.repository.new.migrate form .help,.repository.new.repo form .help{margin-left:265px!important}.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:250px!important}.repository.new.fork form input,.repository.new.fork form textarea,.repository.new.migrate form input,.repository.new.migrate form textarea,.repository.new.repo form input,.repository.new.repo form textarea{width:50%!important}}@media only screen and (max-width:767px){.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:15px}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{display:block}}.repository.new.fork form .dropdown .dropdown.icon,.repository.new.migrate form .dropdown .dropdown.icon,.repository.new.repo form .dropdown .dropdown.icon{margin-top:-7px!important;padding-bottom:5px}.repository.new.fork form .dropdown .text,.repository.new.migrate form .dropdown .text,.repository.new.repo form .dropdown .text{margin-right:0!important}.repository.new.fork form .dropdown .text i,.repository.new.migrate form .dropdown .text i,.repository.new.repo form .dropdown .text i{margin-right:0!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:0!important;text-align:center}@media only screen and (max-width:768px){.repository.new.fork form .selection.dropdown,.repository.new.fork form input,.repository.new.fork form label,.repository.new.migrate form .selection.dropdown,.repository.new.migrate form input,.repository.new.migrate form label,.repository.new.repo form .selection.dropdown,.repository.new.repo form input,.repository.new.repo form label{width:100%!important}.repository.new.fork form .field a,.repository.new.fork form .field button,.repository.new.migrate form .field a,.repository.new.migrate form .field button,.repository.new.repo form .field a,.repository.new.repo form .field button{margin-bottom:1em;width:100%}}@media only screen and (min-width:768px){.repository.new.repo .ui.form #auto-init{margin-left:265px!important}}.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:50%!important}@media only screen and (max-width:768px){.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:100%!important}}.new.webhook form .help{margin-left:25px}.new.webhook .events.fields .column{padding-left:40px}.githook textarea{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}@media only screen and (max-width:768px){.new.org .ui.form .field a,.new.org .ui.form .field button{margin-bottom:1em;width:100%}.new.org .ui.form .field input{width:100%!important}}.repository{padding-top:15px}.repository .repo-header .ui.compact.menu{margin-left:1rem}.repository .repo-header .ui.header{margin-top:0}.repository .repo-header .mega-octicon{width:30px;font-size:30px}.repository .repo-header .ui.huge.breadcrumb{font-weight:400;font-size:1.5rem}.repository .repo-header .fork-flag{margin-left:36px;margin-top:3px;display:block;font-size:12px;white-space:nowrap}.repository .repo-header .octicon.octicon-repo-forked{margin-top:-1px;font-size:15px}.repository .repo-header .button{margin-top:2px;margin-bottom:2px}.repository .tabs .navbar{justify-content:initial}.repository .navbar{display:flex;justify-content:space-between}.repository .navbar .ui.label{margin-left:7px;padding:3px 5px}.repository .owner.dropdown{min-width:40%!important}.repository #file-buttons{margin-left:auto!important;font-weight:400}.repository #file-buttons .ui.button{padding:8px 10px;font-weight:400}.repository .metas .menu{max-height:300px;overflow-x:auto}.repository .metas .ui.list .hide{display:none!important}.repository .metas .ui.list .item{padding:0}.repository .metas .ui.list .label.color{padding:0 8px;margin-right:5px}.repository .metas .ui.list a{margin:2px 0}.repository .metas .ui.list a .text{color:#444}.repository .metas .ui.list a .text:hover{color:#000}.repository .metas #deadlineForm input{width:12.8rem;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap}.repository .header-wrapper{background-color:#FAFAFA;margin-top:-15px;padding-top:15px}.repository .header-wrapper .ui.tabs.divider{border-bottom:none}.repository .header-wrapper .ui.tabular .octicon{margin-right:5px}.repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px}.repository .filter.menu .octicon{float:left;margin:5px -7px 0 -5px;width:16px}.repository .filter.menu.labels .octicon{margin:-2px -7px 0 -5px}.repository .filter.menu .text{margin-left:.9em}.repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}.repository .filter.menu .dropdown.item{margin:1px;padding-right:0}.repository .select-label .item{max-width:250px;overflow:hidden;text-overflow:ellipsis}.repository .select-label .desc{padding-left:16px}.repository .ui.tabs.container{margin-top:14px;margin-bottom:0}.repository .ui.tabs.container .ui.menu{border-bottom:none}.repository .ui.tabs.divider{margin-top:0;margin-bottom:20px}.repository #clone-panel{width:350px}@media only screen and (max-width:768px){.repository #clone-panel{width:100%}}.repository #clone-panel input{border-radius:0;padding:5px 10px;width:50%}.repository #clone-panel .clone.button{font-size:13px;padding:0 5px}.repository #clone-panel .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository #clone-panel .icon.button{padding:0 10px}.repository #clone-panel .dropdown .menu{right:0!important;left:auto!important}.repository.file.list .repo-description{display:flex;justify-content:space-between;align-items:center}.repository.file.list #repo-desc{font-size:1.2em}.repository.file.list .choose.reference .header .icon{font-size:1.4em}.repository.file.list .repo-path .divider,.repository.file.list .repo-path .section{display:inline}.repository.file.list #file-buttons{font-weight:400}.repository.file.list #file-buttons .ui.button{padding:8px 10px;font-weight:400}@media only screen and (max-width:768px){.repository.file.list #file-buttons .ui.tiny.blue.buttons{width:100%}}.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400}.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px}.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777}.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf}.repository.file.list #repo-files-table td{padding-top:8px;padding-bottom:8px;overflow:initial}.repository.file.list #repo-files-table td.name{max-width:150px}.repository.file.list #repo-files-table td.message{max-width:400px}.repository.file.list #repo-files-table td.age{width:120px}.repository.file.list #repo-files-table td .truncate{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap}.repository.file.list #repo-files-table td.message .isSigned{cursor:default}.repository.file.list #repo-files-table tr:hover{background-color:#ffE}.repository.file.list #repo-files-table .jumpable-path{color:#888}.repository.file.list .non-diff-file-content .header .icon{font-size:1em}.repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon{display:inline-block;padding:5px;margin-left:5px;line-height:1;color:#767676;vertical-align:middle;background:0 0;border:0;outline:0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover{color:#4078c0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover{color:#bd2c00}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon.disabled{color:#bbb;cursor:default}.repository.file.list .non-diff-file-content .header .file-actions #delete-file-form{display:inline-block}.repository.file.list .non-diff-file-content .view-raw{padding:5px}.repository.file.list .non-diff-file-content .view-raw *{max-width:100%}.repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px}.repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em}.repository.file.list .non-diff-file-content pre{overflow:auto}.repository.file.list .non-diff-file-content .code-view *{font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px}.repository.file.list .non-diff-file-content .code-view table{width:100%}.repository.file.list .non-diff-file-content .code-view .lines-num{vertical-align:top;text-align:right;color:#999;background:#f5f5f5;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-num span{line-height:20px;padding:0 10px;cursor:pointer;display:block}.repository.file.list .non-diff-file-content .code-view .lines-code,.repository.file.list .non-diff-file-content .code-view .lines-num{padding:0}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs,.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-code pre,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs,.repository.file.list .non-diff-file-content .code-view .lines-num ol,.repository.file.list .non-diff-file-content .code-view .lines-num pre{background-color:#fff;margin:0;padding:0!important}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-code ol li,.repository.file.list .non-diff-file-content .code-view .lines-code pre li,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-num ol li,.repository.file.list .non-diff-file-content .code-view .lines-num pre li{display:block;width:100%}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-code ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-code pre li.active,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-num ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-num pre li.active{background:#ffd}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-code ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-code pre li:before,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-num ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-num pre li:before{content:' '}.repository.file.list .non-diff-file-content .code-view .lines-commit{vertical-align:top;color:#999;padding:0;background:#f5f5f5;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info{width:350px;max-width:350px;display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 0 0 10px}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data{display:flex;font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-message{flex-grow:2;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;line-height:20px}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-avatar,.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-time{flex-shrink:0}.repository.file.list .non-diff-file-content .code-view .lines-commit .ui.avatar.image{height:18px;width:18px}.repository.file.list .non-diff-file-content .code-view .lines-code .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-commit .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-num .bottom-line{border-bottom:1px solid #eaecef}.repository.file.list .non-diff-file-content .code-view .active{background:#ffd}.repository.file.list .sidebar{padding-left:0}.repository.file.list .sidebar .octicon{width:16px}.repository.file.editor .treepath{width:100%}.repository.file.editor .treepath input{vertical-align:middle;box-shadow:rgba(0,0,0,.0745098) 0 1px 2px inset;width:inherit;padding:7px 8px;margin-right:5px}.repository.file.editor .tabular.menu .octicon{margin-right:5px}.repository.file.editor .commit-form-wrapper{padding-left:64px}.repository.file.editor .commit-form-wrapper .commit-avatar{float:left;margin-left:-64px;width:3em;height:auto}.repository.file.editor .commit-form-wrapper .commit-form{position:relative;padding:15px;margin-bottom:10px;border:1px solid #ddd;border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form:after,.repository.file.editor .commit-form-wrapper .commit-form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#fff}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name{display:inline-block;padding:3px 6px;font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.65);background-color:rgba(209,227,237,.45);border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input{position:relative;margin-left:25px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input input{width:240px!important;padding-left:26px!important}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .octicon-git-branch{position:absolute;top:9px;left:10px;color:#b0c4ce}.repository.options #interval{width:100px!important;min-width:100px}.repository.options .danger .item{padding:20px 15px}.repository.options .danger .ui.divider{margin:0}.repository.new.issue .comment.form .comment .avatar{width:3em}.repository.new.issue .comment.form .content{margin-left:4em}.repository.new.issue .comment.form .content:after,.repository.new.issue .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.new.issue .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.new.issue .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.new.issue .comment.form .content:after{border-right-color:#fff}.repository.new.issue .comment.form .content .markdown{font-size:14px}.repository.new.issue .comment.form .metas{min-width:220px}.repository.new.issue .comment.form .metas .filter.menu{max-height:300px;overflow-x:auto}.repository.view.issue .title{padding-bottom:0!important}.repository.view.issue .title h1{font-weight:300;font-size:2.3rem;margin-bottom:5px}.repository.view.issue .title h1 .ui.input{font-size:.5em;vertical-align:top;width:50%;min-width:600px}.repository.view.issue .title h1 .ui.input input{font-size:1.5em;padding:6px 10px}.repository.view.issue .title .index{font-weight:300;color:#aaa;letter-spacing:-1px}.repository.view.issue .title .label{margin-right:10px}.repository.view.issue .title .edit-zone{margin-top:10px}.repository.view.issue .pull-desc code{color:#0166E6}.repository.view.issue .pull.tabular.menu{margin-bottom:10px}.repository.view.issue .pull.tabular.menu .octicon{margin-right:5px}.repository.view.issue .pull.tab.segment{border:none;padding:0;padding-top:10px;box-shadow:none;background-color:inherit}.repository.view.issue .pull .merge.box .avatar{margin-left:10px;margin-top:10px}.repository.view.issue .pull .review-item .avatar,.repository.view.issue .pull .review-item .type-icon{float:none;display:inline-block;text-align:center;vertical-align:middle}.repository.view.issue .pull .review-item .avatar .octicon,.repository.view.issue .pull .review-item .type-icon .octicon{width:23px;font-size:23px;margin-top:.45em}.repository.view.issue .pull .review-item .text{margin:.3em 0 .5em .5em}.repository.view.issue .pull .review-item .type-icon{float:right;margin-right:1em}.repository.view.issue .pull .review-item .divider{margin:.5rem 0}.repository.view.issue .pull .review-item .review-content{padding:1em 0 1em 3.8em}.repository.view.issue .comment-list:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1}.repository.view.issue .comment-list .comment .avatar{width:3em}.repository.view.issue .comment-list .comment .tag{color:#767676;margin-top:3px;padding:2px 5px;font-size:12px;border:1px solid rgba(0,0,0,.1);border-radius:3px}.repository.view.issue .comment-list .comment .actions .item{float:left}.repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px}.repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px}.repository.view.issue .comment-list .comment .content{margin-left:4em}.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px}.repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px}.repository.view.issue .comment-list .comment .content .markdown{font-size:14px}.repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.images::after{clear:both;content:' ';display:block}.repository.view.issue .comment-list .comment .content>.bottom.segment a{display:block;float:left;margin:5px;padding:5px;height:150px;border:solid 1px #eee;border-radius:3px;max-width:150px;background-color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a:before{content:' ';display:inline-block;height:100%;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.image{max-height:100%;width:auto;margin:0;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image{font-size:128px;color:#000}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image:hover{color:#000}.repository.view.issue .comment-list .comment .ui.form .field:first-child{clear:none}.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:none;padding:0;padding-top:10px}.repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px}.repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px}.repository.view.issue .comment-list .event .octicon{width:30px;float:left;text-align:center}.repository.view.issue .comment-list .event .octicon.octicon-circle-slash{margin-top:5px;margin-left:-34.5px;font-size:20px;color:#bd2c00}.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644}.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:3px;margin-left:-31px;margin-right:-1px;font-size:25px}.repository.view.issue .comment-list .event .octicon.octicon-comment{margin-top:4px;margin-left:-35px;font-size:24px}.repository.view.issue .comment-list .event .octicon.octicon-eye{margin-top:3px;margin-left:-35px;margin-right:0;font-size:22px}.repository.view.issue .comment-list .event .octicon.octicon-x{margin-left:-33px;font-size:25px}.repository.view.issue .comment-list .event .detail{font-size:.9rem;margin-top:5px;margin-left:35px}.repository.view.issue .comment-list .event .detail .octicon.octicon-git-commit{margin-top:2px}.repository.view.issue .ui.segment.metas{margin-top:-3px}.repository.view.issue .ui.participants img{margin-top:5px;margin-right:5px}.repository.view.issue .ui.depending .item.is-closed .title{text-decoration:line-through}.repository .comment.form .ui.comments{margin-top:-12px;max-width:100%}.repository .comment.form .content .field:first-child{clear:none}.repository .comment.form .content .form:after,.repository .comment.form .content .form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository .comment.form .content .form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository .comment.form .content .form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository .comment.form .content .form:after{border-right-color:#fff}.repository .comment.form .content .tab.segment{border:none;padding:0;padding-top:10px}.repository .comment.form .content textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository .label.list{list-style:none;padding-top:15px}.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .label.list .item a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .label.list .item a:hover{color:#000}.repository .label.list .item a.open-issues{margin-right:30px}.repository .label.list .item .ui.label{font-size:1em}.repository .milestone.list{list-style:none;padding-top:15px}.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .milestone.list>.item>a{padding-top:5px;padding-right:10px;color:#000}.repository .milestone.list>.item>a:hover{color:#4078c0}.repository .milestone.list>.item .ui.progress{width:40%;padding:0;border:0;margin:0}.repository .milestone.list>.item .ui.progress .bar{height:20px}.repository .milestone.list>.item .meta{color:#999;padding-top:5px}.repository .milestone.list>.item .meta .issue-stats .octicon{padding-left:5px}.repository .milestone.list>.item .meta .overdue{color:red}.repository .milestone.list>.item .operate{margin-top:-15px}.repository .milestone.list>.item .operate>a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .milestone.list>.item .operate>a:hover{color:#000}.repository .milestone.list>.item .content{padding-top:10px}.repository.new.milestone textarea{height:200px}.repository.new.milestone #deadline{width:150px}.repository.compare.pull .choose.branch .octicon{padding-right:10px}.repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.compare.pull .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.compare.pull .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.compare.pull .comment.form .content:after{border-right-color:#fff}.repository .filter.dropdown .menu{margin-top:1px!important}.repository.branches .commit-divergence .bar-group{position:relative;float:left;padding-bottom:6px;width:90px}.repository.branches .commit-divergence .bar-group:last-child{border-left:1px solid #b4b4b4}.repository.branches .commit-divergence .count{margin:0 3px}.repository.branches .commit-divergence .count.count-ahead{text-align:left}.repository.branches .commit-divergence .count.count-behind{text-align:right}.repository.branches .commit-divergence .bar{height:4px;position:absolute;background-color:#d4d4d5}.repository.branches .commit-divergence .bar.bar-behind{right:0}.repository.branches .commit-divergence .bar.bar-ahead{left:0}.repository.commits .header .search input{font-weight:400;padding:5px 10px}.repository #commits-table thead th:first-of-type{padding-left:15px}.repository #commits-table thead .sha{width:140px}.repository #commits-table thead .shatd{text-align:center}.repository #commits-table td.sha .sha.label{margin:0}.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #BBB}.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#FAFAFA;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #BBB;border-top-left-radius:0;border-bottom-left-radius:0}.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21BA45;background:rgba(33,186,69,.1)}.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon{border-left:1px solid rgba(33,186,69,.5)}.repository .diff-detail-box{padding:7px 0;background:#fff;line-height:30px}.repository .diff-detail-box>div:after{clear:both;content:"";display:block}.repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px}.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #DDD;padding-left:6px}.repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle}.repository .diff-detail-box span.status.modify{background-color:#f0db88}.repository .diff-detail-box span.status.add{background-color:#b4e2b4}.repository .diff-detail-box span.status.del{background-color:#e9aeae}.repository .diff-detail-box span.status.rename{background-color:#dad8ff}.repository .diff-detail-box .detail-files{background:#fff;margin:0}.repository .diff-box .header{display:flex;align-items:center}.repository .diff-box .header .count{margin-right:12px;font-size:13px;flex:0 0 auto}.repository .diff-box .header .count .bar{background-color:#bd2c00;height:12px;width:40px;display:inline-block;margin:2px 4px 0 4px;vertical-align:text-top}.repository .diff-box .header .count .bar .add{background-color:#55a532;height:12px}.repository .diff-box .header .file{flex:1;color:#888;word-break:break-all}.repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto}.repository .diff-file-box .header{background-color:#f7f7f7}.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#A7A7A7;background:#fafafa;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top}.repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #DDD}.repository .diff-file-box .code-diff{font-size:12px}.repository .diff-file-box .code-diff td{padding:0;padding-left:10px;border-top:none}.repository .diff-file-box .code-diff pre{margin:0}.repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px}.repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#F0F0F0!important;border-color:#D2CECE!important;padding-top:8px;padding-bottom:8px}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#fafafa}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split tbody tr td:nth-child(3){border-left-width:1px;border-left-style:solid}.repository .diff-file-box.file-content{clear:right}.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}.repository .repo-search-result{padding-top:10px;padding-bottom:10px}.repository .repo-search-result .lines-num a{color:inherit}.repository.quickstart .guide .item{padding:1em}.repository.quickstart .guide .item small{font-weight:400}.repository.quickstart .guide .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository.quickstart .guide .ui.action.small.input{width:100%}.repository.quickstart .guide #repo-clone-url{border-radius:0;padding:5px 10px;font-size:1.2em}.repository.release #release-list{border-top:1px solid #DDD;margin-top:20px;padding-top:15px}.repository.release #release-list>li{list-style:none}.repository.release #release-list>li .detail,.repository.release #release-list>li .meta{padding-top:30px;padding-bottom:40px}.repository.release #release-list>li .meta{text-align:right;position:relative}.repository.release #release-list>li .meta .tag:not(.icon){display:block;margin-top:15px}.repository.release #release-list>li .meta .commit{display:block;margin-top:10px}.repository.release #release-list>li .detail{border-left:1px solid #DDD}.repository.release #release-list>li .detail .author img{margin-bottom:-3px}.repository.release #release-list>li .detail .download{margin-top:20px}.repository.release #release-list>li .detail .download>a .octicon{margin-left:5px;margin-right:5px}.repository.release #release-list>li .detail .download .list{padding-left:0;border-top:1px solid #eee}.repository.release #release-list>li .detail .download .list li{list-style:none;display:block;padding-top:8px;padding-bottom:8px;border-bottom:1px solid #eee}.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #FFF}.repository.new.release .target{min-width:500px}.repository.new.release .target #tag-name{margin-top:-4px}.repository.new.release .target .at{margin-left:-5px;margin-right:5px}.repository.new.release .target .dropdown.icon{margin:0;padding-top:3px}.repository.new.release .target .selection.dropdown{padding-top:10px;padding-bottom:10px}.repository.new.release .prerelease.field{margin-bottom:0}@media only screen and (max-width:438px){.repository.new.release .field button,.repository.new.release .field input{width:100%}}@media only screen and (max-width:768px){.repository.new.release .field button{margin-bottom:1em}}.repository.forks .list{margin-top:0}.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #DDD}.repository.forks .list .item .ui.avatar{float:left;margin-right:5px}.repository.forks .list .item .link{padding-top:5px}.repository.wiki.start .ui.segment{padding-top:70px;padding-bottom:100px}.repository.wiki.start .ui.segment .mega-octicon{font-size:48px}.repository.wiki.new .CodeMirror .CodeMirror-code{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment{background:inherit}.repository.wiki.new .editor-preview{background-color:#fff}.repository.wiki.view .choose.page{margin-top:-5px}.repository.wiki.view .ui.sub.header{text-transform:none}.repository.wiki.view>.markdown{padding:15px 30px}.repository.wiki.view>.markdown h1:first-of-type,.repository.wiki.view>.markdown h2:first-of-type,.repository.wiki.view>.markdown h3:first-of-type,.repository.wiki.view>.markdown h4:first-of-type,.repository.wiki.view>.markdown h5:first-of-type,.repository.wiki.view>.markdown h6:first-of-type{margin-top:0}@media only screen and (max-width:767px){.repository.wiki .dividing.header .stackable.grid .button{margin-top:2px;margin-bottom:2px}}.repository.settings.collaboration .collaborator.list{padding:0}.repository.settings.collaboration .collaborator.list>.item{margin:0;line-height:2em}.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #DDD}.repository.settings.collaboration #repo-collab-form #search-user-box .results{left:7px}.repository.settings.collaboration #repo-collab-form .ui.button{margin-left:5px;margin-top:-3px}.repository.settings.branches .protected-branches .selection.dropdown{width:300px}.repository.settings.branches .protected-branches .item{border:1px solid #eaeaea;padding:10px 15px}.repository.settings.branches .protected-branches .item:not(:last-child){border-bottom:0}.repository.settings.branches .branch-protection .help{margin-left:26px;padding-top:0}.repository.settings.branches .branch-protection .fields{margin-left:20px;display:block}.repository.settings.branches .branch-protection .whitelist{margin-left:26px}.repository.settings.branches .branch-protection .whitelist .dropdown img{display:inline-block}.repository.settings.webhook .events .column{padding-bottom:0}.repository.settings.webhook .events .help{font-size:13px;margin-left:26px;padding-top:0}.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #A3C293;border-right:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #A3C293}.repository .ui.segment.sub-menu{padding:7px;line-height:0}.repository .ui.segment.sub-menu .list{width:100%;display:flex}.repository .ui.segment.sub-menu .list .item{width:100%;border-radius:3px}.repository .ui.segment.sub-menu .list .item a{color:#000}.repository .ui.segment.sub-menu .list .item a:hover{color:#666}.repository .ui.segment.sub-menu .list .item.active{background:rgba(0,0,0,.05)}.repository .segment.reactions.dropdown .menu,.repository .select-reaction.dropdown .menu{right:0!important;left:auto!important}.repository .segment.reactions.dropdown .menu>.header,.repository .select-reaction.dropdown .menu>.header{margin:.75rem 0 .5rem}.repository .segment.reactions.dropdown .menu>.item,.repository .select-reaction.dropdown .menu>.item{float:left;padding:.5rem .5rem!important}.repository .segment.reactions.dropdown .menu>.item img.emoji,.repository .select-reaction.dropdown .menu>.item img.emoji{margin-right:0}.repository .segment.reactions{padding:.3em 1em}.repository .segment.reactions .ui.label{padding:.4em}.repository .segment.reactions .ui.label.disabled{cursor:default}.repository .segment.reactions .ui.label>img{height:1.5em!important}.repository .segment.reactions .select-reaction{float:none}.repository .segment.reactions .select-reaction:not(.active) a{display:none}.repository .segment.reactions:hover .select-reaction a{display:block}.user-cards .list{padding:0}.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}.user-cards .list .item .meta{margin-top:5px}#search-repo-box .results .result .image,#search-user-box .results .result .image{float:left;margin-right:8px;width:2em;height:2em}#search-repo-box .results .result .content,#search-user-box .results .result .content{margin:6px 0}#issue-filters.hide{display:none}#issue-actions{margin-top:-1rem!important}#issue-actions.hide{display:none}.ui.checkbox.issue-checkbox{vertical-align:middle}.issue.list{list-style:none}.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #AAA}.issue.list>.item .title{color:#444;font-size:15px;font-weight:700;margin:0 6px}.issue.list>.item .title:hover{color:#000}.issue.list>.item .comment{padding-right:10px;color:#666}.issue.list>.item .desc{padding-top:5px;color:#999}.issue.list>.item .desc .checklist{padding-left:5px}.issue.list>.item .desc .checklist .progress-bar{margin-left:2px;width:80px;height:6px;display:inline-block;background-color:#eee;overflow:hidden;border-radius:3px;vertical-align:2px!important}.issue.list>.item .desc .checklist .progress-bar .progress{background-color:#ccc;display:block;height:100%}.issue.list>.item .desc a.milestone{padding-left:5px;color:#999!important}.issue.list>.item .desc a.milestone:hover{color:#000!important}.issue.list>.item .desc .assignee{margin-top:-5px;margin-right:5px}.issue.list>.item .desc .overdue{color:red}.page.buttons{padding-top:15px}.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087F7;box-shadow:none!important}.ui.form .dropzone .dz-error-message{top:140px}.settings .content{margin-top:2px}.settings .content .segment,.settings .content>.header{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.settings .list>.item .green{color:#21BA45}.settings .list>.item:not(:first-child){border-top:1px solid #eaeaea;padding:1rem;margin:15px -1rem -1rem -1rem}.settings .list>.item>.mega-octicon{display:table-cell}.settings .list>.item>.mega-octicon+.content{display:table-cell;padding:0 0 0 .5em;vertical-align:top}.settings .list>.item .info{margin-top:10px}.settings .list>.item .info .tab.segment{border:none;padding:10px 0 0}.settings .list.key .meta{padding-top:5px;color:#666}.settings .list.email>.item:not(:first-child){min-height:60px}.settings .list.collaborator>.item{padding:0}.ui.vertical.menu .header.item{font-size:1.1em;background:#f0f0f0}.edit-label.modal .form .column,.new-label.segment .form .column{padding-right:0}.edit-label.modal .form .buttons,.new-label.segment .form .buttons{margin-left:auto;padding-top:15px}.edit-label.modal .form .color.picker.column,.new-label.segment .form .color.picker.column{width:auto}.edit-label.modal .form .color.picker.column .color-picker,.new-label.segment .form .color.picker.column .color-picker{height:35px;width:auto;padding-left:30px}.edit-label.modal .form .minicolors-swatch.minicolors-sprite,.new-label.segment .form .minicolors-swatch.minicolors-sprite{top:10px;left:10px;width:15px;height:15px}.edit-label.modal .form .precolors,.new-label.segment .form .precolors{padding-left:0;padding-right:0;margin:3px 10px auto 10px;width:120px}.edit-label.modal .form .precolors .color,.new-label.segment .form .precolors .color{float:left;width:15px;height:15px}#avatar-arrow:after,#avatar-arrow:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}#avatar-arrow:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}#avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}#delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important}.tab-size-1{-moz-tab-size:1!important;-o-tab-size:1!important;tab-size:1!important}.tab-size-2{-moz-tab-size:2!important;-o-tab-size:2!important;tab-size:2!important}.tab-size-3{-moz-tab-size:3!important;-o-tab-size:3!important;tab-size:3!important}.tab-size-4{-moz-tab-size:4!important;-o-tab-size:4!important;tab-size:4!important}.tab-size-5{-moz-tab-size:5!important;-o-tab-size:5!important;tab-size:5!important}.tab-size-6{-moz-tab-size:6!important;-o-tab-size:6!important;tab-size:6!important}.tab-size-7{-moz-tab-size:7!important;-o-tab-size:7!important;tab-size:7!important}.tab-size-8{-moz-tab-size:8!important;-o-tab-size:8!important;tab-size:8!important}.tab-size-9{-moz-tab-size:9!important;-o-tab-size:9!important;tab-size:9!important}.tab-size-10{-moz-tab-size:10!important;-o-tab-size:10!important;tab-size:10!important}.tab-size-11{-moz-tab-size:11!important;-o-tab-size:11!important;tab-size:11!important}.tab-size-12{-moz-tab-size:12!important;-o-tab-size:12!important;tab-size:12!important}.tab-size-13{-moz-tab-size:13!important;-o-tab-size:13!important;tab-size:13!important}.tab-size-14{-moz-tab-size:14!important;-o-tab-size:14!important;tab-size:14!important}.tab-size-15{-moz-tab-size:15!important;-o-tab-size:15!important;tab-size:15!important}.tab-size-16{-moz-tab-size:16!important;-o-tab-size:16!important;tab-size:16!important}.stats-table{display:table;width:100%}.stats-table .table-cell{display:table-cell}.stats-table .table-cell.tiny{height:.5em}tbody.commit-list{vertical-align:baseline}.commit-body{white-space:pre-wrap}@media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px}.ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0}}#topic_edit{margin-top:5px}#repo-topics{margin-top:5px}.repo-topic{cursor:pointer}#new-dependency-drop-list.ui.selection.dropdown{min-width:0;width:100%;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap}#new-dependency-drop-list .text{width:100%;overflow:hidden}#manage_topic{font-size:12px}.label+#manage_topic{margin-left:5px}.repo-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap}.repo-header .repo-buttons{display:flex;align-items:center}.repo-buttons .disabled-repo-button .label{opacity:.5}.repo-buttons .disabled-repo-button a.button{opacity:.5;cursor:not-allowed}.repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important}.repo-buttons .ui.labeled.button>.label{border-left:none!important;margin:0!important}.CodeMirror{font:14px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.CodeMirror.cm-s-default{border-radius:3px;padding:0!important}.CodeMirror .cm-comment{background:inherit!important}.repository.file.editor .tab[data-tab=write]{padding:0!important}.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:none!important}.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:none;border-right:none;border-bottom:none}.organization{padding-top:15px}.organization .head .ui.header .text{vertical-align:middle;font-size:1.6rem;margin-left:15px}.organization .head .ui.header .ui.right{margin-top:5px}.organization.new.org form{margin:auto}.organization.new.org form .ui.message{text-align:center}@media only screen and (min-width:768px){.organization.new.org form{width:800px!important}.organization.new.org form .header{padding-left:280px!important}.organization.new.org form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.organization.new.org form .help{margin-left:265px!important}.organization.new.org form .optional .title{margin-left:250px!important}.organization.new.org form input,.organization.new.org form textarea{width:50%!important}}@media only screen and (max-width:767px){.organization.new.org form .optional .title{margin-left:15px}.organization.new.org form .inline.field>label{display:block}}.organization.new.org form .header{padding-left:0!important;text-align:center}.organization.options input{min-width:300px}.organization.profile #org-avatar{width:100px;height:100px;margin-right:15px}.organization.profile #org-info .ui.header{font-size:36px;margin-bottom:0}.organization.profile #org-info .desc{font-size:16px;margin-bottom:10px}.organization.profile #org-info .meta .item{display:inline-block;margin-right:10px}.organization.profile #org-info .meta .item .icon{margin-right:5px}.organization.profile .ui.top.header .ui.right{margin-top:0}.organization.profile .teams .item{padding:10px 15px}.organization.profile .members .ui.avatar,.organization.teams .members .ui.avatar{width:48px;height:48px;margin-right:5px}.organization.invite #invite-box{margin:auto;margin-top:50px;width:500px!important}.organization.invite #invite-box #search-user-box input{margin-left:0;width:300px}.organization.invite #invite-box .ui.button{margin-left:5px;margin-top:-3px}.organization.members .list .item{margin-left:0;margin-right:0;border-bottom:1px solid #eee}.organization.members .list .item .ui.avatar{width:48px;height:48px}.organization.members .list .item .meta{line-height:24px}.organization.teams .detail .item{padding:10px 15px}.organization.teams .detail .item:not(:last-child){border-bottom:1px solid #eee}.organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px}.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #DDD}.organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px}.organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0}.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px}.user:not(.icon){padding-top:15px}.user.profile .ui.card .username{display:block}.user.profile .ui.card .extra.content{padding:0}.user.profile .ui.card .extra.content ul{margin:0;padding:0}.user.profile .ui.card .extra.content ul li{padding:10px;list-style:none}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #eaeaea}.user.profile .ui.card .extra.content ul li .octicon{margin-left:1px;margin-right:5px}.user.profile .ui.card .extra.content ul li.follow .ui.button{width:100%}@media only screen and (max-width:768px){.user.profile .ui.card #profile-avatar{height:250px;overflow:hidden}.user.profile .ui.card #profile-avatar img{max-height:768px;max-width:768px}}@media only screen and (max-width:768px){.user.profile .ui.card{width:100%}}.user.profile .ui.repository.list{margin-top:25px}.user.profile #loading-heatmap{margin-bottom:1em}.user.followers .header.name{font-size:20px;line-height:24px;vertical-align:middle}.user.followers .follow .ui.button{padding:8px 15px}.user.notification .octicon{float:left;font-size:2em}.user.notification .content{float:left;margin-left:7px}.user.notification table form{display:inline-block}.user.notification table button{padding:3px 3px 3px 5px}.user.notification table tr{cursor:pointer}.user.notification .octicon.green{color:#21ba45}.user.notification .octicon.red{color:#d01919}.user.notification .octicon.purple{color:#a333c8}.user.notification .octicon.blue{color:#2185d0}.user.link-account:not(.icon){padding-top:15px;padding-bottom:5px}.user.settings .iconFloat{float:left}.dashboard{padding-top:15px}.dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px}.dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none}.dashboard.feeds .filter.menu .item,.dashboard.issues .filter.menu .item{text-align:left}.dashboard.feeds .filter.menu .item .text,.dashboard.issues .filter.menu .item .text{height:16px;vertical-align:middle}.dashboard.feeds .filter.menu .item .text.truncate,.dashboard.issues .filter.menu .item .text.truncate{width:85%}.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:7px;left:90%;width:15%}@media only screen and (max-width:768px){.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:10px;left:auto;width:auto;right:13px}}.dashboard.feeds .filter.menu .jump.item,.dashboard.issues .filter.menu .jump.item{margin:1px;padding-right:0}.dashboard.feeds .filter.menu .menu,.dashboard.issues .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}@media only screen and (max-width:768px){.dashboard.feeds .filter.menu,.dashboard.issues .filter.menu{width:100%}}.dashboard.feeds .right.stackable.menu>.item.active,.dashboard.issues .right.stackable.menu>.item.active{color:#d9453d}.dashboard .dashboard-repos{margin:0 1px}.dashboard .dashboard-navbar{width:100vw;padding:0 .5rem}.feeds .news>.ui.grid{margin-left:auto;margin-right:auto}.feeds .news .ui.avatar{margin-top:13px}.feeds .news .time-since{font-size:13px}.feeds .news .issue.title{width:80%}.feeds .news .push.news .content ul{font-size:13px;list-style:none;padding-left:10px}.feeds .news .push.news .content ul img{margin-bottom:-2px}.feeds .news .push.news .content ul .text.truncate{width:80%;margin-bottom:-5px}.feeds .news .commit-id{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.feeds .news code{padding:1px;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px;word-break:break-all}.feeds .list .header .ui.label{margin-top:-4px;padding:4px 5px;font-weight:400}.feeds .list .header .plus.icon{margin-top:5px}.feeds .list ul{list-style:none;margin:0;padding-left:0}.feeds .list ul li:not(:last-child){border-bottom:1px solid #EAEAEA}.feeds .list ul li.private{background-color:#fcf8e9}.feeds .list ul li a{padding:6px 1.2em;display:block}.feeds .list ul li a .octicon{color:#888}.feeds .list ul li a .octicon.rear{font-size:15px}.feeds .list ul li a .star-num{font-size:12px}.feeds .list .repo-owner-name-list .item-name{max-width:70%;margin-bottom:-4px}.feeds .list #collaborative-repo-list .owner-and-repo{max-width:80%;margin-bottom:-5px}.feeds .list #collaborative-repo-list .owner-name{max-width:120px;margin-bottom:-5px}.admin{padding-top:15px}.admin .table.segment{padding:0;font-size:13px}.admin .table.segment:not(.striped){padding-top:5px}.admin .table.segment:not(.striped) thead th:last-child{padding-right:5px!important}.admin .table.segment th{padding-top:5px;padding-bottom:5px}.admin .table.segment:not(.select) td:first-of-type,.admin .table.segment:not(.select) th:first-of-type{padding-left:15px!important}.admin .ui.header,.admin .ui.segment{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.admin.user .email{max-width:200px}.admin dl.admin-dl-horizontal{padding:20px;margin:0}.admin dl.admin-dl-horizontal dd{margin-left:275px}.admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin.config #test-mail-btn{margin-left:5px}.explore{padding-top:15px}.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}.explore .navbar .octicon{width:16px;text-align:center;margin-right:5px}.ui.repository.list .item{padding-bottom:25px}.ui.repository.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.repository.list .item .ui.header{font-size:1.5rem;padding-bottom:10px}.ui.repository.list .item .ui.header .name{word-break:break-all}.ui.repository.list .item .ui.header .metas{color:#888;font-size:14px;font-weight:400}.ui.repository.list .item .ui.header .metas span:not(:last-child){margin-right:5px}.ui.repository.list .item .time{font-size:12px;color:grey}.ui.repository.list .item .ui.tags{margin-bottom:1em}.ui.repository.branches .time{font-size:12px;color:grey}.ui.user.list .item{padding-bottom:25px}.ui.user.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.user.list .item .ui.avatar.image{width:40px;height:40px}.ui.user.list .item .description{margin-top:5px}.ui.user.list .item .description .octicon:not(:first-child){margin-left:5px}.ui.user.list .item .description a{color:#333}.ui.user.list .item .description a:hover{text-decoration:underline}.ui.button.add-code-comment{font-size:14px;height:16px;padding:2px 0 0;position:relative;width:16px;z-index:5;float:left;margin:-2px -10px -2px -20px;opacity:0;transition:transform .1s ease-in-out;transform:scale(1,1)}.ui.button.add-code-comment:hover{transform:scale(1.2,1.2)}.focus-lines-new .ui.button.add-code-comment.add-code-comment-right,.focus-lines-old .ui.button.add-code-comment.add-code-comment-left{opacity:1}.comment-code-cloud{padding:4px;margin:0 auto;position:relative;border:1px solid #f1f1f1;margin-top:13px;margin-right:10px;margin-bottom:5px}.comment-code-cloud:before{content:" ";width:0;height:0;border-left:13px solid transparent;border-right:13px solid transparent;border-bottom:13px solid #f1f1f1;left:20px;position:absolute;top:-13px}.comment-code-cloud .attached.tab{border:none;padding:0;margin:0}.comment-code-cloud .attached.tab.markdown{padding:1em;min-height:168px}.comment-code-cloud .attached.header{padding:.1rem 1rem}.comment-code-cloud .right.menu.options .item{padding:.85714286em .442857em;cursor:pointer}.comment-code-cloud .ui.form textarea{border:0}.comment-code-cloud .ui.attached.tabular.menu{background:#f7f7f7;border:1px solid #d4d4d5;padding-top:5px;padding-left:5px;margin-top:0}.comment-code-cloud .footer{border-top:1px solid #f1f1f1;margin-top:10px}.comment-code-cloud .footer .markdown-info{display:inline-block;margin:5px 0;font-size:12px;color:rgba(0,0,0,.6)}.comment-code-cloud .footer .ui.right.floated{padding-top:6px}.comment-code-cloud .footer:after{clear:both;content:"";display:block}.comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em}.comment-code-cloud form.comment-form-reply{margin:0 0 0 4em}.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} \ No newline at end of file +.tribute-container{box-shadow:0 1px 3px 1px #c7c7c7}.tribute-container ul{background:#fff}.tribute-container li{padding:8px 12px;border-bottom:1px solid #dcdcdc}.tribute-container li img{display:inline-block;vertical-align:middle;width:28px;height:28px;margin-right:5px}.tribute-container li span.fullname{font-weight:400;font-size:.8rem;margin-left:3px}.tribute-container li.highlight,.tribute-container li:hover{background:#2185D0;color:#fff}.emoji{width:1.5em;height:1.5em;display:inline-block;background-size:contain}.ui.label .emoji{height:1.2em!important}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-regular.eot);src:url(../vendor/assets/lato-fonts/lato-regular.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-regular.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-regular.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-italic.eot);src:url(../vendor/assets/lato-fonts/lato-italic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-italic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-italic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bold.eot);src:url(../vendor/assets/lato-fonts/lato-bold.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bold.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bold.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot);src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bolditalic.ttf) format('truetype');font-weight:700;font-style:italic}@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Medium');font-weight:400}@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Bold');font-weight:700}textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}h1,h2,h3,h4,h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.home .hero h1,.home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.ui.accordion .title:not(.ui),.ui.button,.ui.card>.content>.header.ui.card>.content>.header,.ui.category.search>.results .category>.name,.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=file],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url],.ui.header,.ui.input input,.ui.input>input,.ui.items>.item>.content>.header,.ui.language>.menu>.item,.ui.list .list>.item .header,.ui.list>.item .header,.ui.menu,.ui.message .header,.ui.modal>.header,.ui.popup>.header,.ui.search>.results .result .title,.ui.search>.results>.message .header,.ui.statistic>.label,.ui.statistic>.value,.ui.statistics .statistic>.label,.ui.statistics .statistic>.value,.ui.steps .step .title,.ui.text.container,body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}body{background-color:#fff;overflow-y:auto;-webkit-font-smoothing:antialiased;display:flex;flex-direction:column}:lang(ja) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) h1,:lang(ja) h2,:lang(ja) h3,:lang(ja) h4,:lang(ja) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) .home .hero h1,:lang(ja) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}.ui.language>.menu>.item:lang(ja),:lang(ja) .ui.accordion .title:not(.ui),:lang(ja) .ui.button,:lang(ja) .ui.card>.content>.header.ui.card>.content>.header,:lang(ja) .ui.category.search>.results .category>.name,:lang(ja) .ui.form input:not([type]),:lang(ja) .ui.form input[type=date],:lang(ja) .ui.form input[type=datetime-local],:lang(ja) .ui.form input[type=email],:lang(ja) .ui.form input[type=file],:lang(ja) .ui.form input[type=number],:lang(ja) .ui.form input[type=password],:lang(ja) .ui.form input[type=search],:lang(ja) .ui.form input[type=tel],:lang(ja) .ui.form input[type=text],:lang(ja) .ui.form input[type=time],:lang(ja) .ui.form input[type=url],:lang(ja) .ui.header,:lang(ja) .ui.input input,:lang(ja) .ui.input>input,:lang(ja) .ui.items>.item>.content>.header,:lang(ja) .ui.list .list>.item .header,:lang(ja) .ui.list>.item .header,:lang(ja) .ui.menu,:lang(ja) .ui.message .header,:lang(ja) .ui.modal>.header,:lang(ja) .ui.popup>.header,:lang(ja) .ui.search>.results .result .title,:lang(ja) .ui.search>.results>.message .header,:lang(ja) .ui.statistic>.label,:lang(ja) .ui.statistic>.value,:lang(ja) .ui.statistics .statistic>.label,:lang(ja) .ui.statistics .statistic>.value,:lang(ja) .ui.steps .step .title,:lang(ja) .ui.text.container,:lang(ja) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(zh-CN) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) h1,:lang(zh-CN) h2,:lang(zh-CN) h3,:lang(zh-CN) h4,:lang(zh-CN) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) .home .hero h1,:lang(zh-CN) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}.ui.language>.menu>.item:lang(zh-CN),:lang(zh-CN) .ui.accordion .title:not(.ui),:lang(zh-CN) .ui.button,:lang(zh-CN) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-CN) .ui.category.search>.results .category>.name,:lang(zh-CN) .ui.form input:not([type]),:lang(zh-CN) .ui.form input[type=date],:lang(zh-CN) .ui.form input[type=datetime-local],:lang(zh-CN) .ui.form input[type=email],:lang(zh-CN) .ui.form input[type=file],:lang(zh-CN) .ui.form input[type=number],:lang(zh-CN) .ui.form input[type=password],:lang(zh-CN) .ui.form input[type=search],:lang(zh-CN) .ui.form input[type=tel],:lang(zh-CN) .ui.form input[type=text],:lang(zh-CN) .ui.form input[type=time],:lang(zh-CN) .ui.form input[type=url],:lang(zh-CN) .ui.header,:lang(zh-CN) .ui.input input,:lang(zh-CN) .ui.input>input,:lang(zh-CN) .ui.items>.item>.content>.header,:lang(zh-CN) .ui.list .list>.item .header,:lang(zh-CN) .ui.list>.item .header,:lang(zh-CN) .ui.menu,:lang(zh-CN) .ui.message .header,:lang(zh-CN) .ui.modal>.header,:lang(zh-CN) .ui.popup>.header,:lang(zh-CN) .ui.search>.results .result .title,:lang(zh-CN) .ui.search>.results>.message .header,:lang(zh-CN) .ui.statistic>.label,:lang(zh-CN) .ui.statistic>.value,:lang(zh-CN) .ui.statistics .statistic>.label,:lang(zh-CN) .ui.statistics .statistic>.value,:lang(zh-CN) .ui.steps .step .title,:lang(zh-CN) .ui.text.container,:lang(zh-CN) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-TW) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) h1,:lang(zh-TW) h2,:lang(zh-TW) h3,:lang(zh-TW) h4,:lang(zh-TW) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) .home .hero h1,:lang(zh-TW) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}.ui.language>.menu>.item:lang(zh-TW),:lang(zh-TW) .ui.accordion .title:not(.ui),:lang(zh-TW) .ui.button,:lang(zh-TW) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-TW) .ui.category.search>.results .category>.name,:lang(zh-TW) .ui.form input:not([type]),:lang(zh-TW) .ui.form input[type=date],:lang(zh-TW) .ui.form input[type=datetime-local],:lang(zh-TW) .ui.form input[type=email],:lang(zh-TW) .ui.form input[type=file],:lang(zh-TW) .ui.form input[type=number],:lang(zh-TW) .ui.form input[type=password],:lang(zh-TW) .ui.form input[type=search],:lang(zh-TW) .ui.form input[type=tel],:lang(zh-TW) .ui.form input[type=text],:lang(zh-TW) .ui.form input[type=time],:lang(zh-TW) .ui.form input[type=url],:lang(zh-TW) .ui.header,:lang(zh-TW) .ui.input input,:lang(zh-TW) .ui.input>input,:lang(zh-TW) .ui.items>.item>.content>.header,:lang(zh-TW) .ui.list .list>.item .header,:lang(zh-TW) .ui.list>.item .header,:lang(zh-TW) .ui.menu,:lang(zh-TW) .ui.message .header,:lang(zh-TW) .ui.modal>.header,:lang(zh-TW) .ui.popup>.header,:lang(zh-TW) .ui.search>.results .result .title,:lang(zh-TW) .ui.search>.results>.message .header,:lang(zh-TW) .ui.statistic>.label,:lang(zh-TW) .ui.statistic>.value,:lang(zh-TW) .ui.statistics .statistic>.label,:lang(zh-TW) .ui.statistics .statistic>.value,:lang(zh-TW) .ui.steps .step .title,:lang(zh-TW) .ui.text.container,:lang(zh-TW) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-HK) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) h1,:lang(zh-HK) h2,:lang(zh-HK) h3,:lang(zh-HK) h4,:lang(zh-HK) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) .home .hero h1,:lang(zh-HK) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}.ui.language>.menu>.item:lang(zh-HK),:lang(zh-HK) .ui.accordion .title:not(.ui),:lang(zh-HK) .ui.button,:lang(zh-HK) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-HK) .ui.category.search>.results .category>.name,:lang(zh-HK) .ui.form input:not([type]),:lang(zh-HK) .ui.form input[type=date],:lang(zh-HK) .ui.form input[type=datetime-local],:lang(zh-HK) .ui.form input[type=email],:lang(zh-HK) .ui.form input[type=file],:lang(zh-HK) .ui.form input[type=number],:lang(zh-HK) .ui.form input[type=password],:lang(zh-HK) .ui.form input[type=search],:lang(zh-HK) .ui.form input[type=tel],:lang(zh-HK) .ui.form input[type=text],:lang(zh-HK) .ui.form input[type=time],:lang(zh-HK) .ui.form input[type=url],:lang(zh-HK) .ui.header,:lang(zh-HK) .ui.input input,:lang(zh-HK) .ui.input>input,:lang(zh-HK) .ui.items>.item>.content>.header,:lang(zh-HK) .ui.list .list>.item .header,:lang(zh-HK) .ui.list>.item .header,:lang(zh-HK) .ui.menu,:lang(zh-HK) .ui.message .header,:lang(zh-HK) .ui.modal>.header,:lang(zh-HK) .ui.popup>.header,:lang(zh-HK) .ui.search>.results .result .title,:lang(zh-HK) .ui.search>.results>.message .header,:lang(zh-HK) .ui.statistic>.label,:lang(zh-HK) .ui.statistic>.value,:lang(zh-HK) .ui.statistics .statistic>.label,:lang(zh-HK) .ui.statistics .statistic>.value,:lang(zh-HK) .ui.steps .step .title,:lang(zh-HK) .ui.text.container,:lang(zh-HK) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(ko) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) h1,:lang(ko) h2,:lang(ko) h3,:lang(ko) h4,:lang(ko) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) .home .hero h1,:lang(ko) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}.ui.language>.menu>.item:lang(ko),:lang(ko) .ui.accordion .title:not(.ui),:lang(ko) .ui.button,:lang(ko) .ui.card>.content>.header.ui.card>.content>.header,:lang(ko) .ui.category.search>.results .category>.name,:lang(ko) .ui.form input:not([type]),:lang(ko) .ui.form input[type=date],:lang(ko) .ui.form input[type=datetime-local],:lang(ko) .ui.form input[type=email],:lang(ko) .ui.form input[type=file],:lang(ko) .ui.form input[type=number],:lang(ko) .ui.form input[type=password],:lang(ko) .ui.form input[type=search],:lang(ko) .ui.form input[type=tel],:lang(ko) .ui.form input[type=text],:lang(ko) .ui.form input[type=time],:lang(ko) .ui.form input[type=url],:lang(ko) .ui.header,:lang(ko) .ui.input input,:lang(ko) .ui.input>input,:lang(ko) .ui.items>.item>.content>.header,:lang(ko) .ui.list .list>.item .header,:lang(ko) .ui.list>.item .header,:lang(ko) .ui.menu,:lang(ko) .ui.message .header,:lang(ko) .ui.modal>.header,:lang(ko) .ui.popup>.header,:lang(ko) .ui.search>.results .result .title,:lang(ko) .ui.search>.results>.message .header,:lang(ko) .ui.statistic>.label,:lang(ko) .ui.statistic>.value,:lang(ko) .ui.statistics .statistic>.label,:lang(ko) .ui.statistics .statistic>.value,:lang(ko) .ui.steps .step .title,:lang(ko) .ui.text.container,:lang(ko) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}img{border-radius:3px}table{border-collapse:collapse}a{cursor:pointer}.rounded{border-radius:.28571429rem!important}code,pre{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto}code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word}.dont-break-out{overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.full.height{flex-grow:1;padding-bottom:80px}.following.bar{z-index:900;left:0;margin:0!important}.following.bar.light{background-color:#fff;border-bottom:1px solid #DDD;box-shadow:0 2px 3px rgba(0,0,0,.04)}.following.bar .column .menu{margin-top:0}.following.bar .top.menu a.item.brand{padding-left:0}.following.bar .brand .ui.mini.image{width:30px}.following.bar .top.menu .dropdown.item.active,.following.bar .top.menu .dropdown.item:hover,.following.bar .top.menu a.item:hover{background-color:transparent}.following.bar .top.menu a.item:hover{color:rgba(0,0,0,.45)}.following.bar .top.menu .menu{z-index:900}.following.bar .octicon{margin-right:.75em}.following.bar .octicon.fitted{margin-right:0}.following.bar .searchbox{background-color:#f4f4f4!important}.following.bar .searchbox:focus{background-color:#e9e9e9!important}.following.bar .text .octicon{width:16px;text-align:center}.following.bar #navbar{width:100vw;min-height:52px;padding:0 .5rem}.following.bar #navbar .brand{margin:0}@media only screen and (max-width:767px){.following.bar #navbar:not(.shown)>:not(:first-child){display:none}}.right.stackable.menu{margin-left:auto;display:flex;align-items:inherit;flex-direction:inherit}.ui.left{float:left}.ui.right{float:right}.ui.button,.ui.menu .item{-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto}.ui.container.fluid.padded{padding:0 10px 0 10px}.ui.form .ui.button{font-weight:400}.ui.floating.label{z-index:10}.ui.transparent.label{background-color:transparent}.ui.menu,.ui.segment,.ui.vertical.menu{box-shadow:none}.ui .menu:not(.vertical) .item>.button.compact{padding:.58928571em 1.125em}.ui .menu:not(.vertical) .item>.button.small{font-size:.92857143rem}.ui.menu .ui.dropdown.item .menu .item{margin-right:auto}.ui.dropdown .menu>.item>.floating.label{z-index:11}.ui.dropdown .menu .menu>.item>.floating.label{z-index:21}.ui .text.red{color:#d95c5c!important}.ui .text.red a{color:#d95c5c!important}.ui .text.red a:hover{color:#E67777!important}.ui .text.blue{color:#428bca!important}.ui .text.blue a{color:#15c!important}.ui .text.blue a:hover{color:#428bca!important}.ui .text.black{color:#444}.ui .text.black:hover{color:#000}.ui .text.grey{color:#767676!important}.ui .text.grey a{color:#444!important}.ui .text.grey a:hover{color:#000!important}.ui .text.light.grey{color:#888!important}.ui .text.green{color:#6cc644!important}.ui .text.purple{color:#6e5494!important}.ui .text.yellow{color:#FBBD08!important}.ui .text.gold{color:#a1882b!important}.ui .text.left{text-align:left!important}.ui .text.right{text-align:right!important}.ui .text.small{font-size:.75em}.ui .text.normal{font-weight:400}.ui .text.bold{font-weight:700}.ui .text.italic{font-style:italic}.ui .text.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}.ui .text.thin{font-weight:400}.ui .text.middle{vertical-align:middle}.ui .message{text-align:center}.ui.bottom.attached.message{font-weight:700;text-align:left;color:#000}.ui.bottom.attached.message .pull-right{color:#000}.ui.bottom.attached.message .pull-right>span,.ui.bottom.attached.message>span{color:#21ba45}.ui .header>i+.content{padding-left:.75rem;vertical-align:middle}.ui .warning.header{background-color:#F9EDBE!important;border-color:#F0C36D}.ui .warning.segment{border-color:#F0C36D}.ui .info.segment{border:1px solid #c5d5dd}.ui .info.segment.top{background-color:#e6f1f6!important}.ui .info.segment.top h3,.ui .info.segment.top h4{margin-top:0}.ui .info.segment.top h3:last-child{margin-top:4px}.ui .info.segment.top>:last-child{margin-bottom:0}.ui .normal.header{font-weight:400}.ui .avatar.image{border-radius:3px}.ui .form .fake{display:none!important}.ui .form .sub.field{margin-left:25px}.ui .sha.label{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;font-size:13px;padding:6px 10px 4px 10px;font-weight:400;margin:0 6px}.ui.status.buttons .octicon{margin-right:4px}.ui.inline.delete-button{padding:8px 15px;font-weight:400}.ui .background.red{background-color:#d95c5c!important}.ui .background.blue{background-color:#428bca!important}.ui .background.black{background-color:#444}.ui .background.grey{background-color:#767676!important}.ui .background.light.grey{background-color:#888!important}.ui .background.green{background-color:#6cc644!important}.ui .background.purple{background-color:#6e5494!important}.ui .background.yellow{background-color:#FBBD08!important}.ui .background.gold{background-color:#a1882b!important}.ui .branch-tag-choice{line-height:20px}@media only screen and (max-width:767px){.ui.pagination.menu .item.navigation span.navigation_label,.ui.pagination.menu .item:not(.active):not(.navigation){display:none}}.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)}.ui.floating.dropdown .overflow.menu .scrolling.menu.items{border-radius:0!important;box-shadow:none!important;border-bottom:1px solid rgba(34,36,38,.15)}.user-menu>.item{width:100%;border-radius:0!important}.scrolling.menu .item.selected{font-weight:700!important}footer{background-color:#fff;border-top:1px solid #d6d6d6;width:100%;flex-basis:40px;color:#888}footer .container{width:100vw!important;padding:0 .5rem}footer .container .fa{width:16px;text-align:center;color:#428bca}footer .container .links>*{border-left:1px solid #d6d6d6;padding-left:8px;margin-left:5px}footer .container .links>:first-child{border-left:none}footer .ui.language .menu{max-height:500px;overflow-y:auto;margin-bottom:7px}footer .ui.left,footer .ui.right{line-height:40px}.hide{display:none}.hide.show-outdated{display:none!important}.hide.hide-outdated{display:none!important}.center{text-align:center}.img-1{width:2px!important;height:2px!important}.img-2{width:4px!important;height:4px!important}.img-3{width:6px!important;height:6px!important}.img-4{width:8px!important;height:8px!important}.img-5{width:10px!important;height:10px!important}.img-6{width:12px!important;height:12px!important}.img-7{width:14px!important;height:14px!important}.img-8{width:16px!important;height:16px!important}.img-9{width:18px!important;height:18px!important}.img-10{width:20px!important;height:20px!important}.img-11{width:22px!important;height:22px!important}.img-12{width:24px!important;height:24px!important}.img-13{width:26px!important;height:26px!important}.img-14{width:28px!important;height:28px!important}.img-15{width:30px!important;height:30px!important}.img-16{width:32px!important;height:32px!important}@media only screen and (min-width:768px){.mobile-only,.ui.button.mobile-only{display:none}.sr-mobile-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}}@media only screen and (max-width:767px){.not-mobile{display:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}@media only screen and (max-width:991px) and (min-width:768px){.ui.container{width:95%}}.hljs{background:inherit!important;padding:0!important}.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}@media only screen and (max-width:1200px){.ui.menu.new-menu{overflow-x:auto!important;justify-content:left!important;padding-bottom:5px}.ui.menu.new-menu::-webkit-scrollbar{height:8px;display:none}.ui.menu.new-menu:hover::-webkit-scrollbar{display:block}.ui.menu.new-menu::-webkit-scrollbar-track{background:rgba(0,0,0,.01)}.ui.menu.new-menu::-webkit-scrollbar-thumb{background:rgba(0,0,0,.2)}.ui.menu.new-menu:after{position:absolute;margin-top:-15px;display:block;background-image:linear-gradient(to right,rgba(255,255,255,0),#fff 100%);content:' ';right:0;height:53px;z-index:1000;width:60px;clear:none;visibility:visible}.ui.menu.new-menu a.item:last-child{padding-right:30px!important}}[v-cloak]{display:none!important}.repos-search{padding-bottom:0!important}.repos-filter{margin-top:0!important;border-bottom-width:0!important;margin-bottom:2px!important}#user-heatmap{width:107%;text-align:center}#user-heatmap svg:not(:root){overflow:inherit;padding:0!important}@media only screen and (max-width:1200px){#user-heatmap{display:none}}.heatmap-color-0{background-color:#f4f4f4}.heatmap-color-1{background-color:#d7e5db}.heatmap-color-2{background-color:#adc7ab}.heatmap-color-3{background-color:#83a87b}.heatmap-color-4{background-color:#598a4b}.heatmap-color-5{background-color:#2f6b1b}.archived-icon{color:#b3b3b3!important}.oauth2-authorize-application-box{margin-top:3em!important}.ui.tabular.menu .item{color:rgba(0,0,0,.5)}.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}.markdown:not(code).ui.segment{padding:3em}.markdown:not(code).file-view{padding:2em 2em 2em!important}.markdown:not(code)>:first-child{margin-top:0!important}.markdown:not(code)>:last-child{margin-bottom:0!important}.markdown:not(code) a:not([href]){color:inherit;text-decoration:none}.markdown:not(code) .absent{color:#c00}.markdown:not(code) .anchor{position:absolute;top:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown:not(code) .anchor:focus{outline:0}.markdown:not(code) h1,.markdown:not(code) h2,.markdown:not(code) h3,.markdown:not(code) h4,.markdown:not(code) h5,.markdown:not(code) h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}.markdown:not(code) h1:first-of-type,.markdown:not(code) h2:first-of-type,.markdown:not(code) h3:first-of-type,.markdown:not(code) h4:first-of-type,.markdown:not(code) h5:first-of-type,.markdown:not(code) h6:first-of-type{margin-top:0!important}.markdown:not(code) h1 .octicon-link,.markdown:not(code) h2 .octicon-link,.markdown:not(code) h3 .octicon-link,.markdown:not(code) h4 .octicon-link,.markdown:not(code) h5 .octicon-link,.markdown:not(code) h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown:not(code) h1:hover .anchor,.markdown:not(code) h2:hover .anchor,.markdown:not(code) h3:hover .anchor,.markdown:not(code) h4:hover .anchor,.markdown:not(code) h5:hover .anchor,.markdown:not(code) h6:hover .anchor{padding-left:8px;margin-left:-30px;text-decoration:none}.markdown:not(code) h1:hover .anchor .octicon-link,.markdown:not(code) h2:hover .anchor .octicon-link,.markdown:not(code) h3:hover .anchor .octicon-link,.markdown:not(code) h4:hover .anchor .octicon-link,.markdown:not(code) h5:hover .anchor .octicon-link,.markdown:not(code) h6:hover .anchor .octicon-link{display:inline-block}.markdown:not(code) h1 code,.markdown:not(code) h1 tt,.markdown:not(code) h2 code,.markdown:not(code) h2 tt,.markdown:not(code) h3 code,.markdown:not(code) h3 tt,.markdown:not(code) h4 code,.markdown:not(code) h4 tt,.markdown:not(code) h5 code,.markdown:not(code) h5 tt,.markdown:not(code) h6 code,.markdown:not(code) h6 tt{font-size:inherit}.markdown:not(code) h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee}.markdown:not(code) h1 .anchor{line-height:1}.markdown:not(code) h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee}.markdown:not(code) h2 .anchor{line-height:1}.markdown:not(code) h3{font-size:1.5em;line-height:1.43}.markdown:not(code) h3 .anchor{line-height:1.2}.markdown:not(code) h4{font-size:1.25em}.markdown:not(code) h4 .anchor{line-height:1.2}.markdown:not(code) h5{font-size:1em}.markdown:not(code) h5 .anchor{line-height:1.1}.markdown:not(code) h6{font-size:1em;color:#777}.markdown:not(code) h6 .anchor{line-height:1.1}.markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px}.markdown:not(code) blockquote{margin-left:0}.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none}.markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em}.markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none}.markdown:not(code) ol ol,.markdown:not(code) ol ul,.markdown:not(code) ul ol,.markdown:not(code) ul ul{margin-top:0;margin-bottom:0}.markdown:not(code) ol ol,.markdown:not(code) ul ol{list-style-type:lower-roman}.markdown:not(code) li>p{margin-top:0}.markdown:not(code) dl{padding:0}.markdown:not(code) dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown:not(code) dl dd{padding:0 16px;margin-bottom:16px}.markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown:not(code) blockquote>:first-child{margin-top:0}.markdown:not(code) blockquote>:last-child{margin-bottom:0}.markdown:not(code) table{width:auto;overflow:auto;word-break:normal;word-break:keep-all;display:block}.markdown:not(code) table th{font-weight:700}.markdown:not(code) table td,.markdown:not(code) table th{padding:6px 13px!important;border:1px solid #ddd!important}.markdown:not(code) table tr{background-color:#fff;border-top:1px solid #ccc}.markdown:not(code) table tr:nth-child(2n){background-color:#f8f8f8}.markdown:not(code) img{max-width:100%;box-sizing:border-box}.markdown:not(code) .emoji{max-width:none}.markdown:not(code) span.frame{display:block;overflow:hidden}.markdown:not(code) span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown:not(code) span.frame span img{display:block;float:left}.markdown:not(code) span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown:not(code) span.align-center{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown:not(code) span.align-center span img{margin:0 auto;text-align:center}.markdown:not(code) span.align-right{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown:not(code) span.align-right span img{margin:0;text-align:right}.markdown:not(code) span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown:not(code) span.float-left span{margin:13px 0 0}.markdown:not(code) span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown:not(code) span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown:not(code) code,.markdown:not(code) tt{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown:not(code) code:after,.markdown:not(code) code:before,.markdown:not(code) tt:after,.markdown:not(code) tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown:not(code) code br,.markdown:not(code) tt br{display:none}.markdown:not(code) del code{text-decoration:inherit}.markdown:not(code) pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown:not(code) .highlight{margin-bottom:16px}.markdown:not(code) .highlight pre,.markdown:not(code) pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown:not(code) .highlight pre{margin-bottom:0;word-break:normal}.markdown:not(code) pre{word-wrap:normal}.markdown:not(code) pre code,.markdown:not(code) pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown:not(code) pre code:after,.markdown:not(code) pre code:before,.markdown:not(code) pre tt:after,.markdown:not(code) pre tt:before{content:normal}.markdown:not(code) kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:solid 1px #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown:not(code) input[type=checkbox]{vertical-align:middle!important}.markdown:not(code) .csv-data td,.markdown:not(code) .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown:not(code) .csv-data .blob-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown:not(code) .csv-data tr{border-top:0}.markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em}.home .logo{max-width:220px}@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em}.home .hero h2{font-size:2em}}@media only screen and (min-width:768px){.home .hero h1{font-size:5.5em}.home .hero h2{font-size:3em}}.home .hero .octicon{color:#5aa509;font-size:40px;width:50px}.home .hero.header{font-size:20px}.home p.large{font-size:16px}.home .stackable{padding-top:30px}.home a{color:#5aa509}.signup{padding-top:15px}@media only screen and (max-width:880px){footer .ui.container .left,footer .ui.container .right{display:block;text-align:center;float:none}}.install{padding-top:45px}.install form label{text-align:right;width:320px!important}.install form input{width:35%!important}.install form .field{text-align:left}.install form .field .help{margin-left:335px!important}.install form .field.optional .title{margin-left:38%}.install .ui .checkbox{margin-left:40%!important}.install .ui .checkbox label{width:auto!important}.form .help{color:#999;padding-top:.6em;padding-bottom:.6em;display:inline-block}.ui.attached.header{background:#f0f0f0}.ui.attached.header .right{margin-top:-5px}.ui.attached.header .right .button{padding:8px 10px;font-weight:400}#create-page-form form{margin:auto}#create-page-form form .ui.message{text-align:center}@media only screen and (min-width:768px){#create-page-form form{width:800px!important}#create-page-form form .header{padding-left:280px!important}#create-page-form form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}#create-page-form form .help{margin-left:265px!important}#create-page-form form .optional .title{margin-left:250px!important}#create-page-form form input,#create-page-form form textarea{width:50%!important}}@media only screen and (max-width:767px){#create-page-form form .optional .title{margin-left:15px}#create-page-form form .inline.field>label{display:block}}.signin .oauth2 div{display:inline-block}.signin .oauth2 div p{margin:10px 5px 0 0;float:left}.signin .oauth2 a{margin-right:3px}.signin .oauth2 a:last-child{margin-right:0}.signin .oauth2 img{width:32px;height:32px}.signin .oauth2 img.openidConnect{width:auto}@media only screen and (min-width:768px){.g-recaptcha{margin:0 auto!important;width:304px;padding-left:30px}}@media screen and (max-height:575px){#rc-imageselect,.g-recaptcha{transform:scale(.77);transform-origin:0 0}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{margin:auto}.user.activate form .ui.message,.user.forgot.password form .ui.message,.user.reset.password form .ui.message,.user.signin form .ui.message,.user.signup form .ui.message{text-align:center}@media only screen and (min-width:768px){.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:800px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:280px!important}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.user.activate form .help,.user.forgot.password form .help,.user.reset.password form .help,.user.signin form .help,.user.signup form .help{margin-left:265px!important}.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:250px!important}.user.activate form input,.user.activate form textarea,.user.forgot.password form input,.user.forgot.password form textarea,.user.reset.password form input,.user.reset.password form textarea,.user.signin form input,.user.signin form textarea,.user.signup form input,.user.signup form textarea{width:50%!important}}@media only screen and (max-width:767px){.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:15px}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{display:block}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:700px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:0!important;text-align:center}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{width:200px}@media only screen and (max-width:768px){.user.activate form .inline.field>label,.user.activate form input,.user.forgot.password form .inline.field>label,.user.forgot.password form input,.user.reset.password form .inline.field>label,.user.reset.password form input,.user.signin form .inline.field>label,.user.signin form input,.user.signup form .inline.field>label,.user.signup form input{width:100%!important}}.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{margin:auto}.repository.new.fork form .ui.message,.repository.new.migrate form .ui.message,.repository.new.repo form .ui.message{text-align:center}@media only screen and (min-width:768px){.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{width:800px!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:280px!important}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.repository.new.fork form .help,.repository.new.migrate form .help,.repository.new.repo form .help{margin-left:265px!important}.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:250px!important}.repository.new.fork form input,.repository.new.fork form textarea,.repository.new.migrate form input,.repository.new.migrate form textarea,.repository.new.repo form input,.repository.new.repo form textarea{width:50%!important}}@media only screen and (max-width:767px){.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:15px}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{display:block}}.repository.new.fork form .dropdown .dropdown.icon,.repository.new.migrate form .dropdown .dropdown.icon,.repository.new.repo form .dropdown .dropdown.icon{margin-top:-7px!important;padding-bottom:5px}.repository.new.fork form .dropdown .text,.repository.new.migrate form .dropdown .text,.repository.new.repo form .dropdown .text{margin-right:0!important}.repository.new.fork form .dropdown .text i,.repository.new.migrate form .dropdown .text i,.repository.new.repo form .dropdown .text i{margin-right:0!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:0!important;text-align:center}@media only screen and (max-width:768px){.repository.new.fork form .selection.dropdown,.repository.new.fork form input,.repository.new.fork form label,.repository.new.migrate form .selection.dropdown,.repository.new.migrate form input,.repository.new.migrate form label,.repository.new.repo form .selection.dropdown,.repository.new.repo form input,.repository.new.repo form label{width:100%!important}.repository.new.fork form .field a,.repository.new.fork form .field button,.repository.new.migrate form .field a,.repository.new.migrate form .field button,.repository.new.repo form .field a,.repository.new.repo form .field button{margin-bottom:1em;width:100%}}@media only screen and (min-width:768px){.repository.new.repo .ui.form #auto-init{margin-left:265px!important}}.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:50%!important}@media only screen and (max-width:768px){.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:100%!important}}.new.webhook form .help{margin-left:25px}.new.webhook .events.fields .column{padding-left:40px}.githook textarea{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}@media only screen and (max-width:768px){.new.org .ui.form .field a,.new.org .ui.form .field button{margin-bottom:1em;width:100%}.new.org .ui.form .field input{width:100%!important}}.repository{padding-top:15px}.repository .repo-header .ui.compact.menu{margin-left:1rem}.repository .repo-header .ui.header{margin-top:0}.repository .repo-header .mega-octicon{width:30px;font-size:30px}.repository .repo-header .ui.huge.breadcrumb{font-weight:400;font-size:1.5rem}.repository .repo-header .fork-flag{margin-left:36px;margin-top:3px;display:block;font-size:12px;white-space:nowrap}.repository .repo-header .octicon.octicon-repo-forked{margin-top:-1px;font-size:15px}.repository .repo-header .button{margin-top:2px;margin-bottom:2px}.repository .tabs .navbar{justify-content:initial}.repository .navbar{display:flex;justify-content:space-between}.repository .navbar .ui.label{margin-left:7px;padding:3px 5px}.repository .owner.dropdown{min-width:40%!important}.repository #file-buttons{margin-left:auto!important;font-weight:400}.repository #file-buttons .ui.button{padding:8px 10px;font-weight:400}.repository .metas .menu{max-height:300px;overflow-x:auto}.repository .metas .ui.list .hide{display:none!important}.repository .metas .ui.list .item{padding:0}.repository .metas .ui.list .label.color{padding:0 8px;margin-right:5px}.repository .metas .ui.list a{margin:2px 0}.repository .metas .ui.list a .text{color:#444}.repository .metas .ui.list a .text:hover{color:#000}.repository .metas #deadlineForm input{width:12.8rem;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap}.repository .header-wrapper{background-color:#FAFAFA;margin-top:-15px;padding-top:15px}.repository .header-wrapper .ui.tabs.divider{border-bottom:none}.repository .header-wrapper .ui.tabular .octicon{margin-right:5px}.repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px}.repository .filter.menu .octicon{float:left;margin:5px -7px 0 -5px;width:16px}.repository .filter.menu.labels .octicon{margin:-2px -7px 0 -5px}.repository .filter.menu .text{margin-left:.9em}.repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}.repository .filter.menu .dropdown.item{margin:1px;padding-right:0}.repository .select-label .item{max-width:250px;overflow:hidden;text-overflow:ellipsis}.repository .select-label .desc{padding-left:16px}.repository .ui.tabs.container{margin-top:14px;margin-bottom:0}.repository .ui.tabs.container .ui.menu{border-bottom:none}.repository .ui.tabs.divider{margin-top:0;margin-bottom:20px}.repository #clone-panel{width:350px}@media only screen and (max-width:768px){.repository #clone-panel{width:100%}}.repository #clone-panel input{border-radius:0;padding:5px 10px;width:50%}.repository #clone-panel .clone.button{font-size:13px;padding:0 5px}.repository #clone-panel .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository #clone-panel .icon.button{padding:0 10px}.repository #clone-panel .dropdown .menu{right:0!important;left:auto!important}.repository.file.list .repo-description{display:flex;justify-content:space-between;align-items:center}.repository.file.list #repo-desc{font-size:1.2em}.repository.file.list .choose.reference .header .icon{font-size:1.4em}.repository.file.list .repo-path .divider,.repository.file.list .repo-path .section{display:inline}.repository.file.list #file-buttons{font-weight:400}.repository.file.list #file-buttons .ui.button{padding:8px 10px;font-weight:400}@media only screen and (max-width:768px){.repository.file.list #file-buttons .ui.tiny.blue.buttons{width:100%}}.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400}.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px}.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777}.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf}.repository.file.list #repo-files-table td{padding-top:8px;padding-bottom:8px;overflow:initial}.repository.file.list #repo-files-table td.name{max-width:150px}.repository.file.list #repo-files-table td.message{max-width:400px}.repository.file.list #repo-files-table td.age{width:120px}.repository.file.list #repo-files-table td .truncate{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap}.repository.file.list #repo-files-table td.message .isSigned{cursor:default}.repository.file.list #repo-files-table tr:hover{background-color:#ffE}.repository.file.list #repo-files-table .jumpable-path{color:#888}.repository.file.list .non-diff-file-content .header .icon{font-size:1em}.repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon{display:inline-block;padding:5px;margin-left:5px;line-height:1;color:#767676;vertical-align:middle;background:0 0;border:0;outline:0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover{color:#4078c0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover{color:#bd2c00}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon.disabled{color:#bbb;cursor:default}.repository.file.list .non-diff-file-content .header .file-actions #delete-file-form{display:inline-block}.repository.file.list .non-diff-file-content .view-raw{padding:5px}.repository.file.list .non-diff-file-content .view-raw *{max-width:100%}.repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px}.repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em}.repository.file.list .non-diff-file-content pre{overflow:auto}.repository.file.list .non-diff-file-content .code-view *{font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px}.repository.file.list .non-diff-file-content .code-view table{width:100%}.repository.file.list .non-diff-file-content .code-view .lines-num{vertical-align:top;text-align:right;color:#999;background:#f5f5f5;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-num span{line-height:20px;padding:0 10px;cursor:pointer;display:block}.repository.file.list .non-diff-file-content .code-view .lines-code,.repository.file.list .non-diff-file-content .code-view .lines-num{padding:0}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs,.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-code pre,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs,.repository.file.list .non-diff-file-content .code-view .lines-num ol,.repository.file.list .non-diff-file-content .code-view .lines-num pre{background-color:#fff;margin:0;padding:0!important}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-code ol li,.repository.file.list .non-diff-file-content .code-view .lines-code pre li,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-num ol li,.repository.file.list .non-diff-file-content .code-view .lines-num pre li{display:block;width:100%}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-code ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-code pre li.active,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-num ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-num pre li.active{background:#ffd}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-code ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-code pre li:before,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-num ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-num pre li:before{content:' '}.repository.file.list .non-diff-file-content .code-view .lines-commit{vertical-align:top;color:#999;padding:0;background:#f5f5f5;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info{width:350px;max-width:350px;display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 0 0 10px}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data{display:flex;font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-message{flex-grow:2;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;line-height:20px}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-avatar,.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-time{flex-shrink:0}.repository.file.list .non-diff-file-content .code-view .lines-commit .ui.avatar.image{height:18px;width:18px}.repository.file.list .non-diff-file-content .code-view .lines-code .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-commit .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-num .bottom-line{border-bottom:1px solid #eaecef}.repository.file.list .non-diff-file-content .code-view .active{background:#ffd}.repository.file.list .sidebar{padding-left:0}.repository.file.list .sidebar .octicon{width:16px}.repository.file.editor .treepath{width:100%}.repository.file.editor .treepath input{vertical-align:middle;box-shadow:rgba(0,0,0,.0745098) 0 1px 2px inset;width:inherit;padding:7px 8px;margin-right:5px}.repository.file.editor .tabular.menu .octicon{margin-right:5px}.repository.file.editor .commit-form-wrapper{padding-left:64px}.repository.file.editor .commit-form-wrapper .commit-avatar{float:left;margin-left:-64px;width:3em;height:auto}.repository.file.editor .commit-form-wrapper .commit-form{position:relative;padding:15px;margin-bottom:10px;border:1px solid #ddd;border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form:after,.repository.file.editor .commit-form-wrapper .commit-form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#fff}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name{display:inline-block;padding:3px 6px;font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.65);background-color:rgba(209,227,237,.45);border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input{position:relative;margin-left:25px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input input{width:240px!important;padding-left:26px!important}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .octicon-git-branch{position:absolute;top:9px;left:10px;color:#b0c4ce}.repository.options #interval{width:100px!important;min-width:100px}.repository.options .danger .item{padding:20px 15px}.repository.options .danger .ui.divider{margin:0}.repository.new.issue .comment.form .comment .avatar{width:3em}.repository.new.issue .comment.form .content{margin-left:4em}.repository.new.issue .comment.form .content:after,.repository.new.issue .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.new.issue .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.new.issue .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.new.issue .comment.form .content:after{border-right-color:#fff}.repository.new.issue .comment.form .content .markdown{font-size:14px}.repository.new.issue .comment.form .metas{min-width:220px}.repository.new.issue .comment.form .metas .filter.menu{max-height:300px;overflow-x:auto}.repository.view.issue .title{padding-bottom:0!important}.repository.view.issue .title h1{font-weight:300;font-size:2.3rem;margin-bottom:5px}.repository.view.issue .title h1 .ui.input{font-size:.5em;vertical-align:top;width:50%;min-width:600px}.repository.view.issue .title h1 .ui.input input{font-size:1.5em;padding:6px 10px}.repository.view.issue .title .index{font-weight:300;color:#aaa;letter-spacing:-1px}.repository.view.issue .title .label{margin-right:10px}.repository.view.issue .title .edit-zone{margin-top:10px}.repository.view.issue .pull-desc code{color:#0166E6}.repository.view.issue .pull.tabular.menu{margin-bottom:10px}.repository.view.issue .pull.tabular.menu .octicon{margin-right:5px}.repository.view.issue .pull.tab.segment{border:none;padding:10px 0 0;box-shadow:none;background-color:inherit}.repository.view.issue .pull .merge.box .avatar{margin-left:10px;margin-top:10px}.repository.view.issue .pull .review-item .avatar,.repository.view.issue .pull .review-item .type-icon{float:none;display:inline-block;text-align:center;vertical-align:middle}.repository.view.issue .pull .review-item .avatar .octicon,.repository.view.issue .pull .review-item .type-icon .octicon{width:23px;font-size:23px;margin-top:.45em}.repository.view.issue .pull .review-item .text{margin:.3em 0 .5em .5em}.repository.view.issue .pull .review-item .type-icon{float:right;margin-right:1em}.repository.view.issue .pull .review-item .divider{margin:.5rem 0}.repository.view.issue .pull .review-item .review-content{padding:1em 0 1em 3.8em}.repository.view.issue .comment-list:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1}.repository.view.issue .comment-list .comment .avatar{width:3em}.repository.view.issue .comment-list .comment .tag{color:#767676;margin-top:3px;padding:2px 5px;font-size:12px;border:1px solid rgba(0,0,0,.1);border-radius:3px}.repository.view.issue .comment-list .comment .actions .item{float:left}.repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px}.repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px}.repository.view.issue .comment-list .comment .content{margin-left:4em}.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px}.repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px}.repository.view.issue .comment-list .comment .content .markdown{font-size:14px}.repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.images::after{clear:both;content:' ';display:block}.repository.view.issue .comment-list .comment .content>.bottom.segment a{display:block;float:left;margin:5px;padding:5px;height:150px;border:solid 1px #eee;border-radius:3px;max-width:150px;background-color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a:before{content:' ';display:inline-block;height:100%;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.image{max-height:100%;width:auto;margin:0;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image{font-size:128px;color:#000}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image:hover{color:#000}.repository.view.issue .comment-list .comment .ui.form .field:first-child{clear:none}.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:none;padding:10px 0 0}.repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px}.repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px}.repository.view.issue .comment-list .event .octicon{width:30px;float:left;text-align:center}.repository.view.issue .comment-list .event .octicon.octicon-circle-slash{margin-top:5px;margin-left:-34.5px;font-size:20px;color:#bd2c00}.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644}.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:3px;margin-left:-31px;margin-right:-1px;font-size:25px}.repository.view.issue .comment-list .event .octicon.octicon-comment{margin-top:4px;margin-left:-35px;font-size:24px}.repository.view.issue .comment-list .event .octicon.octicon-eye{margin-top:3px;margin-left:-35px;margin-right:0;font-size:22px}.repository.view.issue .comment-list .event .octicon.octicon-x{margin-left:-33px;font-size:25px}.repository.view.issue .comment-list .event .detail{font-size:.9rem;margin-top:5px;margin-left:35px}.repository.view.issue .comment-list .event .detail .octicon.octicon-git-commit{margin-top:2px}.repository.view.issue .ui.segment.metas{margin-top:-3px}.repository.view.issue .ui.participants img{margin-top:5px;margin-right:5px}.repository.view.issue .ui.depending .item.is-closed .title{text-decoration:line-through}.repository .comment.form .ui.comments{margin-top:-12px;max-width:100%}.repository .comment.form .content .field:first-child{clear:none}.repository .comment.form .content .form:after,.repository .comment.form .content .form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository .comment.form .content .form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository .comment.form .content .form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository .comment.form .content .form:after{border-right-color:#fff}.repository .comment.form .content .tab.segment{border:none;padding:10px 0 0}.repository .comment.form .content textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository .label.list{list-style:none;padding-top:15px}.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .label.list .item a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .label.list .item a:hover{color:#000}.repository .label.list .item a.open-issues{margin-right:30px}.repository .label.list .item .ui.label{font-size:1em}.repository .milestone.list{list-style:none;padding-top:15px}.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .milestone.list>.item>a{padding-top:5px;padding-right:10px;color:#000}.repository .milestone.list>.item>a:hover{color:#4078c0}.repository .milestone.list>.item .ui.progress{width:40%;padding:0;border:0;margin:0}.repository .milestone.list>.item .ui.progress .bar{height:20px}.repository .milestone.list>.item .meta{color:#999;padding-top:5px}.repository .milestone.list>.item .meta .issue-stats .octicon{padding-left:5px}.repository .milestone.list>.item .meta .overdue{color:red}.repository .milestone.list>.item .operate{margin-top:-15px}.repository .milestone.list>.item .operate>a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .milestone.list>.item .operate>a:hover{color:#000}.repository .milestone.list>.item .content{padding-top:10px}.repository.new.milestone textarea{height:200px}.repository.new.milestone #deadline{width:150px}.repository.compare.pull .choose.branch .octicon{padding-right:10px}.repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.compare.pull .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.compare.pull .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.compare.pull .comment.form .content:after{border-right-color:#fff}.repository .filter.dropdown .menu{margin-top:1px!important}.repository.branches .commit-divergence .bar-group{position:relative;float:left;padding-bottom:6px;width:90px}.repository.branches .commit-divergence .bar-group:last-child{border-left:1px solid #b4b4b4}.repository.branches .commit-divergence .count{margin:0 3px}.repository.branches .commit-divergence .count.count-ahead{text-align:left}.repository.branches .commit-divergence .count.count-behind{text-align:right}.repository.branches .commit-divergence .bar{height:4px;position:absolute;background-color:#d4d4d5}.repository.branches .commit-divergence .bar.bar-behind{right:0}.repository.branches .commit-divergence .bar.bar-ahead{left:0}.repository.commits .header .search input{font-weight:400;padding:5px 10px}.repository #commits-table thead th:first-of-type{padding-left:15px}.repository #commits-table thead .sha{width:140px}.repository #commits-table thead .shatd{text-align:center}.repository #commits-table td.sha .sha.label{margin:0}.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #BBB}.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#FAFAFA;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #BBB;border-top-left-radius:0;border-bottom-left-radius:0}.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21BA45;background:rgba(33,186,69,.1)}.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon{border-left:1px solid rgba(33,186,69,.5)}.repository .diff-detail-box{padding:7px 0;background:#fff;line-height:30px}.repository .diff-detail-box>div:after{clear:both;content:"";display:block}.repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px}.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #DDD;padding-left:6px}.repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle}.repository .diff-detail-box span.status.modify{background-color:#f0db88}.repository .diff-detail-box span.status.add{background-color:#b4e2b4}.repository .diff-detail-box span.status.del{background-color:#e9aeae}.repository .diff-detail-box span.status.rename{background-color:#dad8ff}.repository .diff-detail-box .detail-files{background:#fff;margin:0}.repository .diff-box .header{display:flex;align-items:center}.repository .diff-box .header .count{margin-right:12px;font-size:13px;flex:0 0 auto}.repository .diff-box .header .count .bar{background-color:#bd2c00;height:12px;width:40px;display:inline-block;margin:2px 4px 0 4px;vertical-align:text-top}.repository .diff-box .header .count .bar .add{background-color:#55a532;height:12px}.repository .diff-box .header .file{flex:1;color:#888;word-break:break-all}.repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto}.repository .diff-file-box .header{background-color:#f7f7f7}.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#A7A7A7;background:#fafafa;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top}.repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #DDD}.repository .diff-file-box .code-diff{font-size:12px}.repository .diff-file-box .code-diff td{padding:0 0 0 10px;border-top:none}.repository .diff-file-box .code-diff pre{margin:0}.repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px}.repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#F0F0F0!important;border-color:#D2CECE!important;padding-top:8px;padding-bottom:8px}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#fafafa}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split tbody tr td:nth-child(3){border-left-width:1px;border-left-style:solid}.repository .diff-file-box.file-content{clear:right}.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}.repository .repo-search-result{padding-top:10px;padding-bottom:10px}.repository .repo-search-result .lines-num a{color:inherit}.repository.quickstart .guide .item{padding:1em}.repository.quickstart .guide .item small{font-weight:400}.repository.quickstart .guide .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository.quickstart .guide .ui.action.small.input{width:100%}.repository.quickstart .guide #repo-clone-url{border-radius:0;padding:5px 10px;font-size:1.2em}.repository.release #release-list{border-top:1px solid #DDD;margin-top:20px;padding-top:15px}.repository.release #release-list>li{list-style:none}.repository.release #release-list>li .detail,.repository.release #release-list>li .meta{padding-top:30px;padding-bottom:40px}.repository.release #release-list>li .meta{text-align:right;position:relative}.repository.release #release-list>li .meta .tag:not(.icon){display:block;margin-top:15px}.repository.release #release-list>li .meta .commit{display:block;margin-top:10px}.repository.release #release-list>li .detail{border-left:1px solid #DDD}.repository.release #release-list>li .detail .author img{margin-bottom:-3px}.repository.release #release-list>li .detail .download{margin-top:20px}.repository.release #release-list>li .detail .download>a .octicon{margin-left:5px;margin-right:5px}.repository.release #release-list>li .detail .download .list{padding-left:0;border-top:1px solid #eee}.repository.release #release-list>li .detail .download .list li{list-style:none;display:block;padding-top:8px;padding-bottom:8px;border-bottom:1px solid #eee}.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #FFF}.repository.new.release .target{min-width:500px}.repository.new.release .target #tag-name{margin-top:-4px}.repository.new.release .target .at{margin-left:-5px;margin-right:5px}.repository.new.release .target .dropdown.icon{margin:0;padding-top:3px}.repository.new.release .target .selection.dropdown{padding-top:10px;padding-bottom:10px}.repository.new.release .prerelease.field{margin-bottom:0}@media only screen and (max-width:438px){.repository.new.release .field button,.repository.new.release .field input{width:100%}}@media only screen and (max-width:768px){.repository.new.release .field button{margin-bottom:1em}}.repository.forks .list{margin-top:0}.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #DDD}.repository.forks .list .item .ui.avatar{float:left;margin-right:5px}.repository.forks .list .item .link{padding-top:5px}.repository.wiki.start .ui.segment{padding-top:70px;padding-bottom:100px}.repository.wiki.start .ui.segment .mega-octicon{font-size:48px}.repository.wiki.new .CodeMirror .CodeMirror-code{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment{background:inherit}.repository.wiki.new .editor-preview{background-color:#fff}.repository.wiki.view .choose.page{margin-top:-5px}.repository.wiki.view .ui.sub.header{text-transform:none}.repository.wiki.view>.markdown{padding:15px 30px}.repository.wiki.view>.markdown h1:first-of-type,.repository.wiki.view>.markdown h2:first-of-type,.repository.wiki.view>.markdown h3:first-of-type,.repository.wiki.view>.markdown h4:first-of-type,.repository.wiki.view>.markdown h5:first-of-type,.repository.wiki.view>.markdown h6:first-of-type{margin-top:0}@media only screen and (max-width:767px){.repository.wiki .dividing.header .stackable.grid .button{margin-top:2px;margin-bottom:2px}}.repository.settings.collaboration .collaborator.list{padding:0}.repository.settings.collaboration .collaborator.list>.item{margin:0;line-height:2em}.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #DDD}.repository.settings.collaboration #repo-collab-form #search-user-box .results{left:7px}.repository.settings.collaboration #repo-collab-form .ui.button{margin-left:5px;margin-top:-3px}.repository.settings.branches .protected-branches .selection.dropdown{width:300px}.repository.settings.branches .protected-branches .item{border:1px solid #eaeaea;padding:10px 15px}.repository.settings.branches .protected-branches .item:not(:last-child){border-bottom:0}.repository.settings.branches .branch-protection .help{margin-left:26px;padding-top:0}.repository.settings.branches .branch-protection .fields{margin-left:20px;display:block}.repository.settings.branches .branch-protection .whitelist{margin-left:26px}.repository.settings.branches .branch-protection .whitelist .dropdown img{display:inline-block}.repository.settings.webhook .events .column{padding-bottom:0}.repository.settings.webhook .events .help{font-size:13px;margin-left:26px;padding-top:0}.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #A3C293;border-right:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #A3C293}.repository .ui.segment.sub-menu{padding:7px;line-height:0}.repository .ui.segment.sub-menu .list{width:100%;display:flex}.repository .ui.segment.sub-menu .list .item{width:100%;border-radius:3px}.repository .ui.segment.sub-menu .list .item a{color:#000}.repository .ui.segment.sub-menu .list .item a:hover{color:#666}.repository .ui.segment.sub-menu .list .item.active{background:rgba(0,0,0,.05)}.repository .segment.reactions.dropdown .menu,.repository .select-reaction.dropdown .menu{right:0!important;left:auto!important}.repository .segment.reactions.dropdown .menu>.header,.repository .select-reaction.dropdown .menu>.header{margin:.75rem 0 .5rem}.repository .segment.reactions.dropdown .menu>.item,.repository .select-reaction.dropdown .menu>.item{float:left;padding:.5rem .5rem!important}.repository .segment.reactions.dropdown .menu>.item img.emoji,.repository .select-reaction.dropdown .menu>.item img.emoji{margin-right:0}.repository .segment.reactions{padding:.3em 1em}.repository .segment.reactions .ui.label{padding:.4em}.repository .segment.reactions .ui.label.disabled{cursor:default}.repository .segment.reactions .ui.label>img{height:1.5em!important}.repository .segment.reactions .select-reaction{float:none}.repository .segment.reactions .select-reaction:not(.active) a{display:none}.repository .segment.reactions:hover .select-reaction a{display:block}.user-cards .list{padding:0}.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}.user-cards .list .item .meta{margin-top:5px}#search-repo-box .results .result .image,#search-user-box .results .result .image{float:left;margin-right:8px;width:2em;height:2em}#search-repo-box .results .result .content,#search-user-box .results .result .content{margin:6px 0}#issue-filters.hide{display:none}#issue-actions{margin-top:-1rem!important}#issue-actions.hide{display:none}.ui.checkbox.issue-checkbox{vertical-align:middle}.issue.list{list-style:none}.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #AAA}.issue.list>.item .title{color:#444;font-size:15px;font-weight:700;margin:0 6px}.issue.list>.item .title:hover{color:#000}.issue.list>.item .comment{padding-right:10px;color:#666}.issue.list>.item .desc{padding-top:5px;color:#999}.issue.list>.item .desc .checklist{padding-left:5px}.issue.list>.item .desc .checklist .progress-bar{margin-left:2px;width:80px;height:6px;display:inline-block;background-color:#eee;overflow:hidden;border-radius:3px;vertical-align:2px!important}.issue.list>.item .desc .checklist .progress-bar .progress{background-color:#ccc;display:block;height:100%}.issue.list>.item .desc a.milestone{padding-left:5px;color:#999!important}.issue.list>.item .desc a.milestone:hover{color:#000!important}.issue.list>.item .desc .assignee{margin-top:-5px;margin-right:5px}.issue.list>.item .desc .overdue{color:red}.page.buttons{padding-top:15px}.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087F7;box-shadow:none!important}.ui.form .dropzone .dz-error-message{top:140px}.settings .content{margin-top:2px}.settings .content .segment,.settings .content>.header{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.settings .list>.item .green{color:#21BA45}.settings .list>.item:not(:first-child){border-top:1px solid #eaeaea;padding:1rem;margin:15px -1rem -1rem -1rem}.settings .list>.item>.mega-octicon{display:table-cell}.settings .list>.item>.mega-octicon+.content{display:table-cell;padding:0 0 0 .5em;vertical-align:top}.settings .list>.item .info{margin-top:10px}.settings .list>.item .info .tab.segment{border:none;padding:10px 0 0}.settings .list.key .meta{padding-top:5px;color:#666}.settings .list.email>.item:not(:first-child){min-height:60px}.settings .list.collaborator>.item{padding:0}.ui.vertical.menu .header.item{font-size:1.1em;background:#f0f0f0}.edit-label.modal .form .column,.new-label.segment .form .column{padding-right:0}.edit-label.modal .form .buttons,.new-label.segment .form .buttons{margin-left:auto;padding-top:15px}.edit-label.modal .form .color.picker.column,.new-label.segment .form .color.picker.column{width:auto}.edit-label.modal .form .color.picker.column .color-picker,.new-label.segment .form .color.picker.column .color-picker{height:35px;width:auto;padding-left:30px}.edit-label.modal .form .minicolors-swatch.minicolors-sprite,.new-label.segment .form .minicolors-swatch.minicolors-sprite{top:10px;left:10px;width:15px;height:15px}.edit-label.modal .form .precolors,.new-label.segment .form .precolors{padding-left:0;padding-right:0;margin:3px 10px auto 10px;width:120px}.edit-label.modal .form .precolors .color,.new-label.segment .form .precolors .color{float:left;width:15px;height:15px}#avatar-arrow:after,#avatar-arrow:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}#avatar-arrow:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}#avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}#delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important}.tab-size-1{-moz-tab-size:1!important;-o-tab-size:1!important;tab-size:1!important}.tab-size-2{-moz-tab-size:2!important;-o-tab-size:2!important;tab-size:2!important}.tab-size-3{-moz-tab-size:3!important;-o-tab-size:3!important;tab-size:3!important}.tab-size-4{-moz-tab-size:4!important;-o-tab-size:4!important;tab-size:4!important}.tab-size-5{-moz-tab-size:5!important;-o-tab-size:5!important;tab-size:5!important}.tab-size-6{-moz-tab-size:6!important;-o-tab-size:6!important;tab-size:6!important}.tab-size-7{-moz-tab-size:7!important;-o-tab-size:7!important;tab-size:7!important}.tab-size-8{-moz-tab-size:8!important;-o-tab-size:8!important;tab-size:8!important}.tab-size-9{-moz-tab-size:9!important;-o-tab-size:9!important;tab-size:9!important}.tab-size-10{-moz-tab-size:10!important;-o-tab-size:10!important;tab-size:10!important}.tab-size-11{-moz-tab-size:11!important;-o-tab-size:11!important;tab-size:11!important}.tab-size-12{-moz-tab-size:12!important;-o-tab-size:12!important;tab-size:12!important}.tab-size-13{-moz-tab-size:13!important;-o-tab-size:13!important;tab-size:13!important}.tab-size-14{-moz-tab-size:14!important;-o-tab-size:14!important;tab-size:14!important}.tab-size-15{-moz-tab-size:15!important;-o-tab-size:15!important;tab-size:15!important}.tab-size-16{-moz-tab-size:16!important;-o-tab-size:16!important;tab-size:16!important}.stats-table{display:table;width:100%}.stats-table .table-cell{display:table-cell}.stats-table .table-cell.tiny{height:.5em}tbody.commit-list{vertical-align:baseline}.commit-body{white-space:pre-wrap}@media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px}.ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0}}#topic_edit{margin-top:5px}#repo-topics{margin-top:5px}.repo-topic{cursor:pointer}#new-dependency-drop-list.ui.selection.dropdown{min-width:0;width:100%;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap}#new-dependency-drop-list .text{width:100%;overflow:hidden}#manage_topic{font-size:12px}.label+#manage_topic{margin-left:5px}.repo-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap}.repo-header .repo-buttons{display:flex;align-items:center}.repo-buttons .disabled-repo-button .label{opacity:.5}.repo-buttons .disabled-repo-button a.button{opacity:.5;cursor:not-allowed}.repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important}.repo-buttons .ui.labeled.button>.label{border-left:none!important;margin:0!important}.CodeMirror{font:14px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.CodeMirror.cm-s-default{border-radius:3px;padding:0!important}.CodeMirror .cm-comment{background:inherit!important}.repository.file.editor .tab[data-tab=write]{padding:0!important}.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:none!important}.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:none;border-right:none;border-bottom:none}.organization{padding-top:15px}.organization .head .ui.header .text{vertical-align:middle;font-size:1.6rem;margin-left:15px}.organization .head .ui.header .ui.right{margin-top:5px}.organization.new.org form{margin:auto}.organization.new.org form .ui.message{text-align:center}@media only screen and (min-width:768px){.organization.new.org form{width:800px!important}.organization.new.org form .header{padding-left:280px!important}.organization.new.org form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.organization.new.org form .help{margin-left:265px!important}.organization.new.org form .optional .title{margin-left:250px!important}.organization.new.org form input,.organization.new.org form textarea{width:50%!important}}@media only screen and (max-width:767px){.organization.new.org form .optional .title{margin-left:15px}.organization.new.org form .inline.field>label{display:block}}.organization.new.org form .header{padding-left:0!important;text-align:center}.organization.options input{min-width:300px}.organization.profile #org-avatar{width:100px;height:100px;margin-right:15px}.organization.profile #org-info .ui.header{font-size:36px;margin-bottom:0}.organization.profile #org-info .desc{font-size:16px;margin-bottom:10px}.organization.profile #org-info .meta .item{display:inline-block;margin-right:10px}.organization.profile #org-info .meta .item .icon{margin-right:5px}.organization.profile .ui.top.header .ui.right{margin-top:0}.organization.profile .teams .item{padding:10px 15px}.organization.profile .members .ui.avatar,.organization.teams .members .ui.avatar{width:48px;height:48px;margin-right:5px}.organization.invite #invite-box{margin:50px auto auto;width:500px!important}.organization.invite #invite-box #search-user-box input{margin-left:0;width:300px}.organization.invite #invite-box .ui.button{margin-left:5px;margin-top:-3px}.organization.members .list .item{margin-left:0;margin-right:0;border-bottom:1px solid #eee}.organization.members .list .item .ui.avatar{width:48px;height:48px}.organization.members .list .item .meta{line-height:24px}.organization.teams .detail .item{padding:10px 15px}.organization.teams .detail .item:not(:last-child){border-bottom:1px solid #eee}.organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px}.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #DDD}.organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px}.organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0}.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px}.user:not(.icon){padding-top:15px}.user.profile .ui.card .username{display:block}.user.profile .ui.card .extra.content{padding:0}.user.profile .ui.card .extra.content ul{margin:0;padding:0}.user.profile .ui.card .extra.content ul li{padding:10px;list-style:none}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #eaeaea}.user.profile .ui.card .extra.content ul li .octicon{margin-left:1px;margin-right:5px}.user.profile .ui.card .extra.content ul li.follow .ui.button{width:100%}@media only screen and (max-width:768px){.user.profile .ui.card #profile-avatar{height:250px;overflow:hidden}.user.profile .ui.card #profile-avatar img{max-height:768px;max-width:768px}}@media only screen and (max-width:768px){.user.profile .ui.card{width:100%}}.user.profile .ui.repository.list{margin-top:25px}.user.profile #loading-heatmap{margin-bottom:1em}.user.followers .header.name{font-size:20px;line-height:24px;vertical-align:middle}.user.followers .follow .ui.button{padding:8px 15px}.user.notification .octicon{float:left;font-size:2em}.user.notification .content{float:left;margin-left:7px}.user.notification table form{display:inline-block}.user.notification table button{padding:3px 3px 3px 5px}.user.notification table tr{cursor:pointer}.user.notification .octicon.green{color:#21ba45}.user.notification .octicon.red{color:#d01919}.user.notification .octicon.purple{color:#a333c8}.user.notification .octicon.blue{color:#2185d0}.user.link-account:not(.icon){padding-top:15px;padding-bottom:5px}.user.settings .iconFloat{float:left}.dashboard{padding-top:15px}.dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px}.dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none}.dashboard.feeds .filter.menu .item,.dashboard.issues .filter.menu .item{text-align:left}.dashboard.feeds .filter.menu .item .text,.dashboard.issues .filter.menu .item .text{height:16px;vertical-align:middle}.dashboard.feeds .filter.menu .item .text.truncate,.dashboard.issues .filter.menu .item .text.truncate{width:85%}.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:7px;left:90%;width:15%}@media only screen and (max-width:768px){.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:10px;left:auto;width:auto;right:13px}}.dashboard.feeds .filter.menu .jump.item,.dashboard.issues .filter.menu .jump.item{margin:1px;padding-right:0}.dashboard.feeds .filter.menu .menu,.dashboard.issues .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}@media only screen and (max-width:768px){.dashboard.feeds .filter.menu,.dashboard.issues .filter.menu{width:100%}}.dashboard.feeds .right.stackable.menu>.item.active,.dashboard.issues .right.stackable.menu>.item.active{color:#d9453d}.dashboard .dashboard-repos{margin:0 1px}.dashboard .dashboard-navbar{width:100vw;padding:0 .5rem}.feeds .news>.ui.grid{margin-left:auto;margin-right:auto}.feeds .news .ui.avatar{margin-top:13px}.feeds .news .time-since{font-size:13px}.feeds .news .issue.title{width:80%}.feeds .news .push.news .content ul{font-size:13px;list-style:none;padding-left:10px}.feeds .news .push.news .content ul img{margin-bottom:-2px}.feeds .news .push.news .content ul .text.truncate{width:80%;margin-bottom:-5px}.feeds .news .commit-id{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.feeds .news code{padding:1px;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px;word-break:break-all}.feeds .list .header .ui.label{margin-top:-4px;padding:4px 5px;font-weight:400}.feeds .list .header .plus.icon{margin-top:5px}.feeds .list ul{list-style:none;margin:0;padding-left:0}.feeds .list ul li:not(:last-child){border-bottom:1px solid #EAEAEA}.feeds .list ul li.private{background-color:#fcf8e9}.feeds .list ul li a{padding:6px 1.2em;display:block}.feeds .list ul li a .octicon{color:#888}.feeds .list ul li a .octicon.rear{font-size:15px}.feeds .list ul li a .star-num{font-size:12px}.feeds .list .repo-owner-name-list .item-name{max-width:70%;margin-bottom:-4px}.feeds .list #collaborative-repo-list .owner-and-repo{max-width:80%;margin-bottom:-5px}.feeds .list #collaborative-repo-list .owner-name{max-width:120px;margin-bottom:-5px}.admin{padding-top:15px}.admin .table.segment{padding:0;font-size:13px}.admin .table.segment:not(.striped){padding-top:5px}.admin .table.segment:not(.striped) thead th:last-child{padding-right:5px!important}.admin .table.segment th{padding-top:5px;padding-bottom:5px}.admin .table.segment:not(.select) td:first-of-type,.admin .table.segment:not(.select) th:first-of-type{padding-left:15px!important}.admin .ui.header,.admin .ui.segment{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.admin.user .email{max-width:200px}.admin dl.admin-dl-horizontal{padding:20px;margin:0}.admin dl.admin-dl-horizontal dd{margin-left:275px}.admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin.config #test-mail-btn{margin-left:5px}.explore{padding-top:15px}.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}.explore .navbar .octicon{width:16px;text-align:center;margin-right:5px}.ui.repository.list .item{padding-bottom:25px}.ui.repository.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.repository.list .item .ui.header{font-size:1.5rem;padding-bottom:10px}.ui.repository.list .item .ui.header .name{word-break:break-all}.ui.repository.list .item .ui.header .metas{color:#888;font-size:14px;font-weight:400}.ui.repository.list .item .ui.header .metas span:not(:last-child){margin-right:5px}.ui.repository.list .item .time{font-size:12px;color:grey}.ui.repository.list .item .ui.tags{margin-bottom:1em}.ui.repository.branches .time{font-size:12px;color:grey}.ui.user.list .item{padding-bottom:25px}.ui.user.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.user.list .item .ui.avatar.image{width:40px;height:40px}.ui.user.list .item .description{margin-top:5px}.ui.user.list .item .description .octicon:not(:first-child){margin-left:5px}.ui.user.list .item .description a{color:#333}.ui.user.list .item .description a:hover{text-decoration:underline}.ui.button.add-code-comment{font-size:14px;height:16px;padding:2px 0 0;position:relative;width:16px;z-index:5;float:left;margin:-2px -10px -2px -20px;opacity:0;transition:transform .1s ease-in-out;transform:scale(1,1)}.ui.button.add-code-comment:hover{transform:scale(1.2,1.2)}.focus-lines-new .ui.button.add-code-comment.add-code-comment-right,.focus-lines-old .ui.button.add-code-comment.add-code-comment-left{opacity:1}.comment-code-cloud{padding:4px;position:relative;border:1px solid #f1f1f1;margin:13px 10px 5px auto}.comment-code-cloud:before{content:" ";width:0;height:0;border-left:13px solid transparent;border-right:13px solid transparent;border-bottom:13px solid #f1f1f1;left:20px;position:absolute;top:-13px}.comment-code-cloud .attached.tab{border:none;padding:0;margin:0}.comment-code-cloud .attached.tab.markdown{padding:1em;min-height:168px}.comment-code-cloud .attached.header{padding:.1rem 1rem}.comment-code-cloud .right.menu.options .item{padding:.85714286em .442857em;cursor:pointer}.comment-code-cloud .ui.form textarea{border:0}.comment-code-cloud .ui.attached.tabular.menu{background:#f7f7f7;border:1px solid #d4d4d5;padding-top:5px;padding-left:5px;margin-top:0}.comment-code-cloud .footer{border-top:1px solid #f1f1f1;margin-top:10px}.comment-code-cloud .footer .markdown-info{display:inline-block;margin:5px 0;font-size:12px;color:rgba(0,0,0,.6)}.comment-code-cloud .footer .ui.right.floated{padding-top:6px}.comment-code-cloud .footer:after{clear:both;content:"";display:block}.comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em}.comment-code-cloud form.comment-form-reply{margin:0 0 0 4em}.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} \ No newline at end of file diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index 84adf72359..d17a06aebf 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -1 +1 @@ -.hljs{display:block;overflow-x:auto;padding:.5em;color:#bababa}.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-num{background-color:#2b2b2b!important}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#6896ba}.hljs-code,.hljs-selector-class{color:#a6e22e}.hljs-emphasis{font-style:italic}.hljs-attribute,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-variable{color:#cb7832}.hljs-params{color:#b9b9b9}.hljs-string{color:#6a8759}.hljs-addition,.hljs-built_in,.hljs-builtin-name,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-subst,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-type{color:#e0c46c}.hljs-comment,.hljs-deletion,.hljs-meta{color:#7f7f7f}.repository .ui.segment.sub-menu .list .item a{color:#dbdbdb}.ui.horizontal.segments>.segment{background-color:#383c4a}body{background:#383c4a;color:#9e9e9e}a{color:#87ab63}a:hover{color:#a0cc75}.ui.card>.extra a:not(.ui):hover,.ui.cards>.card>.extra a:not(.ui):hover{color:#a0cc75}.ui.breadcrumb a:hover{color:#a0cc75}.ui.breadcrumb a{color:#87ab63}.repository .metas .ui.list a .text{color:#87ab63}.repository .metas .ui.list a .text:hover{color:#a0cc75}.repository .label.list .item a{color:#87ab63}.repository .label.list .item a:hover{color:#a0cc75}.repository .milestone.list>.item>a{color:#87ab63}.repository .milestone.list>.item>a:hover{color:#a0cc75}.repository.release #release-list{border-top:1px solid #4c505c}.repository .milestone.list>.item .operate>a{color:#87ab63}.repository .milestone.list>.item .operate>a:hover{color:#a0cc75}.ui.green.progress .bar{background-color:#684}.ui.progress.success .bar{background-color:#7b9e57!important}.following.bar.light{background:#2e323e}.ui.secondary.menu .active.item{color:#dbdbdb}.ui.secondary.menu .item{color:#9e9e9e}.following.bar .top.menu a.item:hover{color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a{border:solid 1px #353945;background-color:#353945}.following.bar.light{border-bottom:1px solid #313131}.ui.attached.header{background:#404552;border:1px solid #404552;color:#dbdbdb}.ui.attached.table{border:1px solid #304251;background:#304251}.feeds .list ul li:not(:last-child){border-bottom:1px solid #333640}.feeds .list ul li.private{background:#353945;border:1px solid #333640}.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff}.ui.menu .ui.dropdown .menu>.item{background:#2c303a!important;color:#9e9e9e!important}.ui.secondary.menu .dropdown.item>.menu,.ui.text.menu .dropdown.item>.menu{border:1px solid #434444}footer{background:#2e323e;border-top:1px solid #313131}.ui.menu .dropdown.item .menu{background:#2c303a}.ui.menu .ui.dropdown .menu>.item:hover,.ui.menu .ui.dropdown .menu>.selected.item{color:#fff!important}.ui.dropdown .menu>.header{color:#dbdbdb}.ui.red.label,.ui.red.labels .label{background-color:#7d3434!important;border-color:#8a2121!important}.ui.menu{background:#404552;border:1px solid #353945}.ui.menu .active.item:hover,.ui.vertical.menu .active.item:hover{color:#dbdbdb;background:#4B5162}.ui.link.menu .item:hover,.ui.menu .dropdown.item:hover,.ui.menu .link.item:hover,.ui.menu a.item:hover{color:#dbdbdb;background:#454b5a}.ui.menu .active.item{background:#4B5162;color:#dbdbdb}.ui.input input{background:#404552;border:2px solid #353945;color:#dbdbdb}.ui.input input:focus,.ui.input.focus input{background:#404552;border:2px solid #353945;color:#dbdbdb}.ui.accordion .title:not(.ui){color:#dbdbdb}.ui.label{color:#dbdbdb;background-color:#404552}.issue.list>.item .title{color:#87ab63}.issue.list>.item .title:hover{color:#a0cc75}.issue.list>.item{border-bottom:1px dashed #475767}.ui.basic.green.label,.ui.green.label,.ui.green.labels .label{background-color:#2d693b!important;border-color:#2d693b!important}.ui.basic.green.labels a.label:hover,a.ui.basic.green.label:hover{background-color:#16ab39!important;border-color:#16ab39!important;color:#fff!important}.issue.list>.item .comment{color:#129c92}.ui.basic.button,.ui.basic.buttons .button{color:#797979!important}.ui.basic.red.active.button,.ui.basic.red.buttons .active.button{box-shadow:0 0 0 1px #c75252 inset!important;color:#c75252!important}.ui.basic.button:focus,.ui.basic.button:hover,.ui.basic.buttons .button:focus,.ui.basic.buttons .button:hover{background:0 0!important;color:#dbdbdb!important}.ui.menu .item{background:#404552;color:#9e9e9e}.ui.menu .item.disabled,.ui.menu .item.disabled:hover{color:#626773}.ui.pagination.menu .active.item{color:#dbdbdb;background-color:#87ab63}.repository .header-wrapper{background-color:#2a2e3a}.ui.tabular.menu .active.item{background:#383c4a;color:#dbdbdb;border-left:1px solid transparent;border-right:1px solid transparent;border-top:none}.ui.tabular.menu .item{color:#9e9e9e}.ui.tabular.menu .item:hover{color:#dbdbdb}.ui.breadcrumb .divider,.ui.header{color:#9e9e9e}.ui.blue.label,.ui.blue.labels .label{background-color:#26577b!important;border-color:#26577b!important}.ui.menu .item>.label{background:#565454}.ui.blue.button,.ui.blue.buttons .button{background-color:#87ab63}.ui.blue.button:hover,.ui.blue.buttons .button:hover{background-color:#a0cc75}.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{background:#404552;border:2px solid #353945}.ui.form input:not([type]):focus,.ui.form input[type=date]:focus,.ui.form input[type=datetime-local]:focus,.ui.form input[type=email]:focus,.ui.form input[type=number]:focus,.ui.form input[type=password]:focus,.ui.form input[type=search]:focus,.ui.form input[type=tel]:focus,.ui.form input[type=text]:focus,.ui.form input[type=time]:focus,.ui.form input[type=url]:focus{background:#404552;border:2px solid #4b505f;color:#dbdbdb}.ui.action.input:not([class*="left action"]) input:focus{border-right-color:#4b505f!important}.ui.green.button,.ui.green.buttons .button{background-color:#87ab63}.ui.green.button:hover,.ui.green.buttons .button:hover{background-color:#a0cc75}.ui.button{background:#383c4a;border:1px solid #4c505c;color:#dbdbdb}.ui.labeled.button:not([class*="left labeled"])>.label,.ui[class*="left labeled"].button>.button{background:#404552;border:1px solid #4c505c;color:#87ab63}.ui.button:hover{background-color:#404552;color:#dbdbdb}.ui.table thead th{background:#404552;color:#dbdbdb}.repository.file.list #repo-files-table tr:hover{background-color:#393d4a}.ui.table{color:#a5a5a5!important;border:1px solid #4c505c;background:#353945}.ui.table tbody tr{border-bottom:1px solid #333640;background:#2a2e3a}.ui .text.grey{color:#808084!important}.ui.attached.table.segment{background:#353945;color:#dbdbdb!important}.markdown:not(code) h2{border-bottom:1px solid #304251}.hljs,.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#9daccc}.markdown:not(code) .highlight pre,.markdown:not(code) pre{background-color:#2a2e3a;border:1px solid #404552}.markdown:not(code) table tr:nth-child(2n){background-color:#474d61}.ui.dropdown .menu{background:#2c303a}.ui.dropdown .menu>.message:not(.ui){color:#636363}.ui.input{color:#dbdbdb}.overflow.menu .items .item{color:#9d9d9d}.overflow.menu .items .item:hover{color:#dbdbdb}.ui.segment{background:#353945;color:#9e9e9e!important;border:1px solid #404552}.ui.active.button:active,.ui.button:active,.ui.button:focus{background-color:#2e3e4e;color:#dbdbdb}.ui.dropdown .menu .selected.item,.ui.dropdown.selected{color:#dbdbdb}.ui.dropdown .menu>.item:hover{color:#dbdbdb}.ui.dropdown .menu>.item{color:#9e9e9e}.ui.attached.segment{border:1px solid #404552}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#353945}.repository.view.issue .comment-list .comment .content .header{color:#dbdbdb;background-color:#404552;border-bottom:1px solid #353944}.ui .text.grey a{color:#b3b3b3!important}.ui.comments .comment .actions a{color:#dbdbdb}.repository.view.issue .comment-list .comment .content .header:after{border-right-color:#404552}.repository.new.issue .comment.form .content:after{border-right-color:#353945}.repository.view.issue .comment-list .comment .content .header:before{border-right-color:#404552}.repository.new.issue .comment.form .content:before{border-right-color:#353945}.repository.view.issue .comment-list:before{background-color:#313c47}.repository .comment.form .content .form:after{border-right-color:#313c47}.repository .comment.form .content .form:before{border-right-color:#313c47}.ui .text.grey a{color:#dbdbdb!important}.ui .text.grey a:hover{color:#dbdbdb!important}.ui.basic.green.active.button,.ui.basic.green.buttons .active.button{color:#13ae38!important}.ui.form textarea,.ui.form textarea:focus{background:#1a2632;border:1px solid #313c47;color:#dbdbdb}.ui.form textarea:focus{border:1px solid #456580}.ui .info.segment.top{background-color:#404552!important}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#3c2626!important;border-color:#634343!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#283e2d!important;border-color:#314a37!important}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#3a523a}.repository .diff-file-box .code-diff .lines-num{border-right:1px solid #2d2d2d}.repository .diff-file-box .file-body.file-code .lines-num{color:#9e9e9e;background:#2e323e}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{border-color:#2d2d2d!important}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #2d2d2d}.hljs-section,.hljs-selector-id,.hljs-title{color:#986c88}.hljs-doctag,.hljs-string{color:#949494}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#5f3737}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#292727!important}.ui.vertical.menu .active.item{background:#4B5162}.ui.vertical.menu .item{background:#353945}.ui.vertical.menu .header.item{background:#404552}.ui.vertical.menu{background:#353945;border:1px solid #333640}.ui.repository.list .item:not(:first-child){border-top:1px solid #4c505c}.ui .text.blue{color:#87ab63!important}.ui.selection.active.dropdown,.ui.selection.active.dropdown .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)}.ui.selection.active.dropdown:hover,.ui.selection.active.dropdown:hover .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)}.ui.selection.dropdown{background:#404552;border:1px solid #404552;color:#9e9e9e}.ui.menu .ui.dropdown .menu>.active.item{color:#dbdbdb!important}.ui.tabular.menu{border-bottom:1px solid #313c47}.ui.card,.ui.cards>.card{background:#353945;box-shadow:0 1px 3px 0 #4c505c,0 0 0 1px #4c505c}.ui.card>.content>.header,.ui.cards>.card>.content>.header{color:#dbdbdb}.ui.card>.extra a:not(.ui),.ui.cards>.card>.extra a:not(.ui){color:#87ab63}.ui .text.black{color:#9e9e9e}.ui .text.black:hover{color:#dbdbdb}.ui.secondary.segment{background:#353945}.ui.secondary.pointing.menu .active.item{border-color:#87ab63;color:#dbdbdb;background:#404552}.ui.user.list .item:not(:first-child){border-top:1px solid #4c505c}.ui.secondary.pointing.menu .active.item:hover{border-color:#af8b4c;color:#dbdbdb;background:#4b5162}.ui.secondary.pointing.menu .dropdown.item:hover,.ui.secondary.pointing.menu .link.item:hover,.ui.secondary.pointing.menu a.item:hover{color:#dbdbdb}.ui.checkbox label,.ui.checkbox+label,.ui.form .field>label{color:#9e9e9e}.ui.form .inline.field>label,.ui.form .inline.field>p,.ui.form .inline.fields .field>label,.ui.form .inline.fields .field>p,.ui.form .inline.fields>label{color:#9e9e9e}.user.settings .email.list .item:not(:first-child){border-top:1px solid #3f4451}.explore .navbar{background-color:#2a2e3a!important}.ui.menu.new-menu{background-color:#2a2e3a!important}@media only screen and (max-width:1200px){.ui.menu.new-menu:after{background-image:linear-gradient(to right,rgba(42,46,42,0),#2a2e2a 100%)}}input{background:#2e323e}.ui.secondary.pointing.menu .active.item{border:none;background:#383c4a}.settings .key.list .item:not(:first-child){border-top:1px solid #404552}.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{color:#9e9e9e}.ui.attached.info.message,.ui.info.message{box-shadow:0 0 0 1px #4b5e71 inset,0 0 0 0 transparent}.ui.bottom.attached.message{background-color:#2c662d;color:#87ab63}.ui.bottom.attached.message .pull-right{color:#87ab63}.ui.info.message{background-color:#2c3b4a;color:#9ebcc5}.CodeMirror div.CodeMirror-cursor{border-left:1px solid #9e9e9e}.ui .warning.header{background-color:#5d3a22!important;border-color:#794f31}.ui.red.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent}.ui.red.button,.ui.red.buttons .button{background-color:#7d3434}.ui.red.button:hover,.ui.red.buttons .button:hover{background-color:#984646}.ui.checkbox label:hover,.ui.checkbox+label:hover{color:#dbdbdb!important}.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{color:#7f98ad}.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{background:#304251}.ui.checkbox .box:hover::before,.ui.checkbox label:hover::before{background:#304251}.ui.checkbox .box:before,.ui.checkbox label:before{background:#304251;border:1px solid #304251}.ui.checkbox .box:active::before,.ui.checkbox label:active::before{background:#304251;border-color:rgba(34,36,38,.35)}.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{border-color:#304251;background:#304251}.ui.checkbox input:focus~.box:before,.ui.checkbox input:focus~label:before{border-color:#304251;background:#304251}.ui.checkbox input:checked:focus~.box:before,.ui.checkbox input:checked:focus~label:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:before{border-color:#304251;background:#304251}.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{opacity:1;color:#7f98ad}.ui.checkbox input:checked:focus~.box:after,.ui.checkbox input:checked:focus~label:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:after{color:#7f98ad}.ui.checkbox input:focus~.box:after,.ui.checkbox input:focus~label,.ui.checkbox input:focus~label:after{color:#9a9a9a}.ui.selection.dropdown:hover{border-color:rgba(34,36,38,.35);border:1px solid #456580}.ui.selection.dropdown .menu>.item{border-top:1px solid #313c47}.ui.selection.visible.dropdown>.text:not(.default){color:#9e9e9e}.ui.negative.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent}.hljs-attribute,.hljs-name,.hljs-tag{color:#ef5e77}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #4c505c}.ui.form textarea,.ui.form textarea:focus{background:#404552;border:2px solid #353945}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:#bd84bf}.hljs-doctag,.hljs-string{color:#8ab398}.ui.form .dropzone{border:2px dashed #4c505c}.ui.basic.red.button,.ui.basic.red.buttons .button{box-shadow:0 0 0 1px #a04141 inset!important;color:#a04141!important}.ui.list .list>.item .header,.ui.list>.item .header{color:#dedede}.ui.list .list>.item .description,.ui.list>.item .description{color:#9e9e9e}.ui.user.list .item .description a{color:#668cb1}.repository.file.list #file-content .code-view .lines-num{background:#2e323e}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e}.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#87ab63}.ui.basic.blue.button:hover,.ui.basic.blue.buttons .button:hover{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.ui.basic.blue.button:focus,.ui.basic.blue.buttons .button:focus{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb}.repository .label.list .item{border-bottom:1px dashed #4c505c}.repository.file.list #file-content .code-view .lines-num{background:#2e323e}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e}.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #a27558 inset!important;color:#a27558!important}.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#2a2e3a}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#283e2d!important;border-color:#314a37!important}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#3c2626!important;border-color:#634343!important}.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#a27558}.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}#git-graph-container li a{color:#c79575}#git-graph-container li .author{color:#c79575}.ui.header .sub.header{color:#9e9e9e}.ui.dividing.header{border-bottom:1px solid #4c505c}.ui.modal>.header{background:#404552;color:#dbdbdb}.ui.modal>.actions{background:#404552;border-top:1px solid #404552}.ui.modal>.content{background:#383c4a}.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.editor-toolbar{background-color:#404552}.editor-toolbar a{color:#87ab63!important}.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:none}.CodeMirror-gutters{background-color:#2b2b2b}.repository .diff-detail-box{background-color:#383c4a}.repository .diff-detail-box .detail-files{background-color:inherit}.comment-code-cloud .ui.attached.tabular.menu{background:none transparent;border:none}.comment-code-cloud .footer .markdown-info{color:inherit}.file-comment{color:#888}.ui.comments .comment .author{color:#dbdbdb}.ui.comments .comment .metadata{color:#808084}.ui.comments .comment .text{color:#9e9e9e}.heatmap-color-0{background-color:#2d303b} \ No newline at end of file +.hljs{display:block;overflow-x:auto;padding:.5em;color:#bababa}.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-num{background-color:#2b2b2b!important}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#6896ba}.hljs-code,.hljs-selector-class{color:#a6e22e}.hljs-emphasis{font-style:italic}.hljs-attribute,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-variable{color:#cb7832}.hljs-params{color:#b9b9b9}.hljs-string{color:#6a8759}.hljs-addition,.hljs-built_in,.hljs-builtin-name,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-subst,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-type{color:#e0c46c}.hljs-comment,.hljs-deletion,.hljs-meta{color:#7f7f7f}.repository .ui.segment.sub-menu .list .item a{color:#dbdbdb}.ui.horizontal.segments>.segment{background-color:#383c4a}body{background:#383c4a;color:#9e9e9e}a{color:#87ab63}a:hover{color:#a0cc75}.ui.card>.extra a:not(.ui):hover,.ui.cards>.card>.extra a:not(.ui):hover{color:#a0cc75}.ui.breadcrumb a:hover{color:#a0cc75}.ui.breadcrumb a{color:#87ab63}.repository .metas .ui.list a .text{color:#87ab63}.repository .metas .ui.list a .text:hover{color:#a0cc75}.repository .label.list .item a{color:#87ab63}.repository .label.list .item a:hover{color:#a0cc75}.repository .milestone.list>.item>a{color:#87ab63}.repository .milestone.list>.item>a:hover{color:#a0cc75}.repository.release #release-list{border-top:1px solid #4c505c}.repository .milestone.list>.item .operate>a{color:#87ab63}.repository .milestone.list>.item .operate>a:hover{color:#a0cc75}.ui.green.progress .bar{background-color:#684}.ui.progress.success .bar{background-color:#7b9e57!important}.following.bar.light{background:#2e323e}.ui.secondary.menu .active.item{color:#dbdbdb}.ui.secondary.menu .item{color:#9e9e9e}.following.bar .top.menu a.item:hover{color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a{border:solid 1px #353945;background-color:#353945}.following.bar.light{border-bottom:1px solid #313131}.ui.attached.header{background:#404552;border:1px solid #404552;color:#dbdbdb}.ui.attached.table{border:1px solid #304251;background:#304251}.feeds .list ul li:not(:last-child){border-bottom:1px solid #333640}.feeds .list ul li.private{background:#353945;border:1px solid #333640}.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff}.ui.menu .ui.dropdown .menu>.item{background:#2c303a!important;color:#9e9e9e!important}.ui.secondary.menu .dropdown.item>.menu,.ui.text.menu .dropdown.item>.menu{border:1px solid #434444}footer{background:#2e323e;border-top:1px solid #313131}.ui.menu .dropdown.item .menu{background:#2c303a}.ui.menu .ui.dropdown .menu>.item:hover,.ui.menu .ui.dropdown .menu>.selected.item{color:#fff!important}.ui.dropdown .menu>.header{color:#dbdbdb}.ui.red.label,.ui.red.labels .label{background-color:#7d3434!important;border-color:#8a2121!important}.ui.menu{background:#404552;border:1px solid #353945}.ui.menu .active.item:hover,.ui.vertical.menu .active.item:hover{color:#dbdbdb;background:#4B5162}.ui.link.menu .item:hover,.ui.menu .dropdown.item:hover,.ui.menu .link.item:hover,.ui.menu a.item:hover{color:#dbdbdb;background:#454b5a}.ui.menu .active.item{background:#4B5162;color:#dbdbdb}.ui.input input{background:#404552;border:2px solid #353945;color:#dbdbdb}.ui.input input:focus,.ui.input.focus input{background:#404552;border:2px solid #353945;color:#dbdbdb}.ui.accordion .title:not(.ui){color:#dbdbdb}.ui.label{color:#dbdbdb;background-color:#404552}.issue.list>.item .title{color:#87ab63}.issue.list>.item .title:hover{color:#a0cc75}.issue.list>.item{border-bottom:1px dashed #475767}.ui.basic.green.label,.ui.green.label,.ui.green.labels .label{background-color:#2d693b!important;border-color:#2d693b!important}.ui.basic.green.labels a.label:hover,a.ui.basic.green.label:hover{background-color:#16ab39!important;border-color:#16ab39!important;color:#fff!important}.issue.list>.item .comment{color:#129c92}.ui.basic.button,.ui.basic.buttons .button{color:#797979!important}.ui.basic.red.active.button,.ui.basic.red.buttons .active.button{box-shadow:0 0 0 1px #c75252 inset!important;color:#c75252!important}.ui.basic.button:focus,.ui.basic.button:hover,.ui.basic.buttons .button:focus,.ui.basic.buttons .button:hover{background:0 0!important;color:#dbdbdb!important}.ui.menu .item{background:#404552;color:#9e9e9e}.ui.menu .item.disabled,.ui.menu .item.disabled:hover{color:#626773}.ui.pagination.menu .active.item{color:#dbdbdb;background-color:#87ab63}.repository .header-wrapper{background-color:#2a2e3a}.ui.tabular.menu .active.item{background:#383c4a;color:#dbdbdb;border-left:1px solid transparent;border-right:1px solid transparent;border-top:none}.ui.tabular.menu .item{color:#9e9e9e}.ui.tabular.menu .item:hover{color:#dbdbdb}.ui.breadcrumb .divider,.ui.header{color:#9e9e9e}.ui.blue.label,.ui.blue.labels .label{background-color:#26577b!important;border-color:#26577b!important}.ui.menu .item>.label{background:#565454}.ui.blue.button,.ui.blue.buttons .button{background-color:#87ab63}.ui.blue.button:hover,.ui.blue.buttons .button:hover{background-color:#a0cc75}.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{background:#404552;border:2px solid #353945}.ui.form input:not([type]):focus,.ui.form input[type=date]:focus,.ui.form input[type=datetime-local]:focus,.ui.form input[type=email]:focus,.ui.form input[type=number]:focus,.ui.form input[type=password]:focus,.ui.form input[type=search]:focus,.ui.form input[type=tel]:focus,.ui.form input[type=text]:focus,.ui.form input[type=time]:focus,.ui.form input[type=url]:focus{background:#404552;border:2px solid #4b505f;color:#dbdbdb}.ui.action.input:not([class*="left action"]) input:focus{border-right-color:#4b505f!important}.ui.green.button,.ui.green.buttons .button{background-color:#87ab63}.ui.green.button:hover,.ui.green.buttons .button:hover{background-color:#a0cc75}.ui.button{background:#383c4a;border:1px solid #4c505c;color:#dbdbdb}.ui.labeled.button:not([class*="left labeled"])>.label,.ui[class*="left labeled"].button>.button{background:#404552;border:1px solid #4c505c;color:#87ab63}.ui.button:hover{background-color:#404552;color:#dbdbdb}.ui.table thead th{background:#404552;color:#dbdbdb}.repository.file.list #repo-files-table tr:hover{background-color:#393d4a}.ui.table{color:#a5a5a5!important;border:1px solid #4c505c;background:#353945}.ui.table tbody tr{border-bottom:1px solid #333640;background:#2a2e3a}.ui .text.grey{color:#808084!important}.ui.attached.table.segment{background:#353945;color:#dbdbdb!important}.markdown:not(code) h2{border-bottom:1px solid #304251}.hljs,.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#9daccc}.markdown:not(code) .highlight pre,.markdown:not(code) pre{background-color:#2a2e3a;border:1px solid #404552}.markdown:not(code) table tr:nth-child(2n){background-color:#474d61}.ui.dropdown .menu{background:#2c303a}.ui.dropdown .menu>.message:not(.ui){color:#636363}.ui.input{color:#dbdbdb}.overflow.menu .items .item{color:#9d9d9d}.overflow.menu .items .item:hover{color:#dbdbdb}.ui.segment{background:#353945;color:#9e9e9e!important;border:1px solid #404552}.ui.active.button:active,.ui.button:active,.ui.button:focus{background-color:#2e3e4e;color:#dbdbdb}.ui.dropdown .menu .selected.item,.ui.dropdown.selected{color:#dbdbdb}.ui.dropdown .menu>.item:hover{color:#dbdbdb}.ui.dropdown .menu>.item{color:#9e9e9e}.ui.attached.segment{border:1px solid #404552}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#353945}.repository.view.issue .comment-list .comment .content .header{color:#dbdbdb;background-color:#404552;border-bottom:1px solid #353944}.ui .text.grey a{color:#b3b3b3!important}.ui.comments .comment .actions a{color:#dbdbdb}.repository.view.issue .comment-list .comment .content .header:after{border-right-color:#404552}.repository.new.issue .comment.form .content:after{border-right-color:#353945}.repository.view.issue .comment-list .comment .content .header:before{border-right-color:#404552}.repository.new.issue .comment.form .content:before{border-right-color:#353945}.repository.view.issue .comment-list:before{background-color:#313c47}.repository .comment.form .content .form:after{border-right-color:#313c47}.repository .comment.form .content .form:before{border-right-color:#313c47}.ui .text.grey a{color:#dbdbdb!important}.ui .text.grey a:hover{color:#dbdbdb!important}.ui.basic.green.active.button,.ui.basic.green.buttons .active.button{color:#13ae38!important}.ui.form textarea,.ui.form textarea:focus{background:#1a2632;border:1px solid #313c47;color:#dbdbdb}.ui.form textarea:focus{border:1px solid #456580}.ui .info.segment.top{background-color:#404552!important}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#3c2626!important;border-color:#634343!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#283e2d!important;border-color:#314a37!important}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#3a523a}.repository .diff-file-box .code-diff .lines-num{border-right:1px solid #2d2d2d}.repository .diff-file-box .file-body.file-code .lines-num{color:#9e9e9e;background:#2e323e}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{border-color:#2d2d2d!important}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #2d2d2d}.hljs-section,.hljs-selector-id,.hljs-title{color:#986c88}.hljs-doctag,.hljs-string{color:#949494}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#5f3737}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#292727!important}.ui.vertical.menu .active.item{background:#4B5162}.ui.vertical.menu .item{background:#353945}.ui.vertical.menu .header.item{background:#404552}.ui.vertical.menu{background:#353945;border:1px solid #333640}.ui.repository.list .item:not(:first-child){border-top:1px solid #4c505c}.ui .text.blue{color:#87ab63!important}.ui.selection.active.dropdown,.ui.selection.active.dropdown .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)}.ui.selection.active.dropdown:hover,.ui.selection.active.dropdown:hover .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)}.ui.selection.dropdown{background:#404552;border:1px solid #404552;color:#9e9e9e}.ui.menu .ui.dropdown .menu>.active.item{color:#dbdbdb!important}.ui.tabular.menu{border-bottom:1px solid #313c47}.ui.card,.ui.cards>.card{background:#353945;box-shadow:0 1px 3px 0 #4c505c,0 0 0 1px #4c505c}.ui.card>.content>.header,.ui.cards>.card>.content>.header{color:#dbdbdb}.ui.card>.extra a:not(.ui),.ui.cards>.card>.extra a:not(.ui){color:#87ab63}.ui .text.black{color:#9e9e9e}.ui .text.black:hover{color:#dbdbdb}.ui.secondary.segment{background:#353945}.ui.secondary.pointing.menu .active.item{border-color:#87ab63;color:#dbdbdb;background:#404552}.ui.user.list .item:not(:first-child){border-top:1px solid #4c505c}.ui.secondary.pointing.menu .active.item:hover{border-color:#af8b4c;color:#dbdbdb;background:#4b5162}.ui.secondary.pointing.menu .dropdown.item:hover,.ui.secondary.pointing.menu .link.item:hover,.ui.secondary.pointing.menu a.item:hover{color:#dbdbdb}.ui.checkbox label,.ui.checkbox+label,.ui.form .field>label{color:#9e9e9e}.ui.form .inline.field>label,.ui.form .inline.field>p,.ui.form .inline.fields .field>label,.ui.form .inline.fields .field>p,.ui.form .inline.fields>label{color:#9e9e9e}.user.settings .email.list .item:not(:first-child){border-top:1px solid #3f4451}.explore .navbar{background-color:#2a2e3a!important}.ui.menu.new-menu{background-color:#2a2e3a!important}@media only screen and (max-width:1200px){.ui.menu.new-menu:after{background-image:linear-gradient(to right,rgba(42,46,42,0),#2a2e2a 100%)}}input{background:#2e323e}.ui.secondary.pointing.menu .active.item{border:none;background:#383c4a}.settings .key.list .item:not(:first-child){border-top:1px solid #404552}.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{color:#9e9e9e}.ui.attached.info.message,.ui.info.message{box-shadow:0 0 0 1px #4b5e71 inset,0 0 0 0 transparent}.ui.bottom.attached.message{background-color:#2c662d;color:#87ab63}.ui.bottom.attached.message .pull-right{color:#87ab63}.ui.info.message{background-color:#2c3b4a;color:#9ebcc5}.CodeMirror div.CodeMirror-cursor{border-left:1px solid #9e9e9e}.ui .warning.header{background-color:#5d3a22!important;border-color:#794f31}.ui.red.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent}.ui.red.button,.ui.red.buttons .button{background-color:#7d3434}.ui.red.button:hover,.ui.red.buttons .button:hover{background-color:#984646}.ui.checkbox label:hover,.ui.checkbox+label:hover{color:#dbdbdb!important}.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{color:#7f98ad}.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{background:#304251}.ui.checkbox .box:hover::before,.ui.checkbox label:hover::before{background:#304251}.ui.checkbox .box:before,.ui.checkbox label:before{background:#304251;border:1px solid #304251}.ui.checkbox .box:active::before,.ui.checkbox label:active::before{background:#304251;border-color:rgba(34,36,38,.35)}.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{border-color:#304251;background:#304251}.ui.checkbox input:focus~.box:before,.ui.checkbox input:focus~label:before{border-color:#304251;background:#304251}.ui.checkbox input:checked:focus~.box:before,.ui.checkbox input:checked:focus~label:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:before{border-color:#304251;background:#304251}.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{opacity:1;color:#7f98ad}.ui.checkbox input:checked:focus~.box:after,.ui.checkbox input:checked:focus~label:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:after{color:#7f98ad}.ui.checkbox input:focus~.box:after,.ui.checkbox input:focus~label,.ui.checkbox input:focus~label:after{color:#9a9a9a}.ui.selection.dropdown:hover{border:1px solid #456580}.ui.selection.dropdown .menu>.item{border-top:1px solid #313c47}.ui.selection.visible.dropdown>.text:not(.default){color:#9e9e9e}.ui.negative.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent}.hljs-attribute,.hljs-name,.hljs-tag{color:#ef5e77}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #4c505c}.ui.form textarea,.ui.form textarea:focus{background:#404552;border:2px solid #353945}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:#bd84bf}.hljs-doctag,.hljs-string{color:#8ab398}.ui.form .dropzone{border:2px dashed #4c505c}.ui.basic.red.button,.ui.basic.red.buttons .button{box-shadow:0 0 0 1px #a04141 inset!important;color:#a04141!important}.ui.list .list>.item .header,.ui.list>.item .header{color:#dedede}.ui.list .list>.item .description,.ui.list>.item .description{color:#9e9e9e}.ui.user.list .item .description a{color:#668cb1}.repository.file.list #file-content .code-view .lines-num{background:#2e323e}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e}.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#87ab63}.ui.basic.blue.button:hover,.ui.basic.blue.buttons .button:hover{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.ui.basic.blue.button:focus,.ui.basic.blue.buttons .button:focus{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb}.repository .label.list .item{border-bottom:1px dashed #4c505c}.repository.file.list #file-content .code-view .lines-num{background:#2e323e}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e}.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #a27558 inset!important;color:#a27558!important}.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#2a2e3a}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#283e2d!important;border-color:#314a37!important}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#3c2626!important;border-color:#634343!important}.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#a27558}.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}#git-graph-container li a{color:#c79575}#git-graph-container li .author{color:#c79575}.ui.header .sub.header{color:#9e9e9e}.ui.dividing.header{border-bottom:1px solid #4c505c}.ui.modal>.header{background:#404552;color:#dbdbdb}.ui.modal>.actions{background:#404552;border-top:1px solid #404552}.ui.modal>.content{background:#383c4a}.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.editor-toolbar{background-color:#404552}.editor-toolbar a{color:#87ab63!important}.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:none}.CodeMirror-gutters{background-color:#2b2b2b}.repository .diff-detail-box{background-color:#383c4a}.repository .diff-detail-box .detail-files{background-color:inherit}.comment-code-cloud .ui.attached.tabular.menu{background:none transparent;border:none}.comment-code-cloud .footer .markdown-info{color:inherit}.file-comment{color:#888}.ui.comments .comment .author{color:#dbdbdb}.ui.comments .comment .metadata{color:#808084}.ui.comments .comment .text{color:#9e9e9e}.heatmap-color-0{background-color:#2d303b} \ No newline at end of file diff --git a/public/less/_admin.less b/public/less/_admin.less index 7eb7be0d9e..24d5af159c 100644 --- a/public/less/_admin.less +++ b/public/less/_admin.less @@ -28,9 +28,10 @@ } } } + .ui.header, .ui.segment { - box-shadow: 0 1px 2px 0 rgba(34,36,38,.15); + box-shadow: 0 1px 2px 0 rgba(34, 36, 38, .15); } &.user { @@ -46,6 +47,7 @@ dd { margin-left: 275px; } + dt { font-weight: bolder; float: left; diff --git a/public/less/_base.less b/public/less/_base.less index 998a95c404..1dd17541bb 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -1,4 +1,3 @@ - @font-face { font-family: 'Lato'; src: url('../vendor/assets/lato-fonts/lato-regular.eot'); @@ -80,15 +79,14 @@ .ui.search > .results .result .title, .ui.search > .results > .message .header, body, - .ui.input>input, .ui.input input, + .ui.input > input, .ui.input input, .ui.statistics .statistic > .value, .ui.statistic > .value, .ui.statistics .statistic > .label, .ui.statistic > .label, .ui.steps .step .title, .ui.text.container, - .ui.language > .menu > .item& - { + .ui.language > .menu > .item& { font-family: Lato, @fonts, sans-serif; } } @@ -131,17 +129,22 @@ body { img { border-radius: 3px; } + table { border-collapse: collapse; } + a { cursor: pointer; } + .rounded { border-radius: .28571429rem !important; } + pre, code { font: 12px @monospaced-fonts, monospace; + &.raw { padding: 7px 12px; margin: 10px 0; @@ -152,6 +155,7 @@ pre, code { line-height: 1.5; overflow: auto; } + &.wrap { white-space: pre-wrap; word-break: break-all; @@ -159,69 +163,87 @@ pre, code { word-wrap: break-word; } } + .dont-break-out { overflow-wrap: break-word; word-wrap: break-word; word-break: break-all; hyphens: auto; } + .full.height { flex-grow: 1; padding-bottom: 80px; } + .following.bar { z-index: 900; left: 0; margin: 0 !important; + &.light { background-color: white; border-bottom: 1px solid #DDDDDD; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.04); } + .column .menu { margin-top: 0; } + .top.menu a.item.brand { padding-left: 0; } + .brand .ui.mini.image { width: 30px; } + .top.menu a.item:hover, .top.menu .dropdown.item:hover, .top.menu .dropdown.item.active { background-color: transparent; } + .top.menu a.item:hover { - color: rgba(0,0,0,.45); + color: rgba(0, 0, 0, .45); } + .top.menu .menu { z-index: 900; } + .octicon { &.fitted { margin-right: 0; } + margin-right: .75em; } + .searchbox { background-color: rgb(244, 244, 244) !important; + &:focus { background-color: rgb(233, 233, 233) !important; } } + .text .octicon { width: 16px; text-align: center; } + #navbar { width: 100vw; min-height: 52px; padding: 0 .5rem; } + #navbar .brand { margin: 0; } + @media only screen and (max-width: 767px) { #navbar:not(.shown) > *:not(:first-child) { display: none; @@ -243,6 +265,7 @@ pre, code { &.left { float: left; } + &.right { float: right; } @@ -281,9 +304,11 @@ pre, code { /* Overide semantic selector '.ui.menu:not(.vertical) .item > .button' */ /* This fixes the commit graph button on the commits page */ + .menu:not(.vertical) .item > .button.compact { padding: .58928571em 1.125em; } + .menu:not(.vertical) .item > .button.small { font-size: .92857143rem; } @@ -292,60 +317,75 @@ pre, code { margin-right: auto; } - &.dropdown .menu>.item>.floating.label { + &.dropdown .menu > .item > .floating.label { z-index: 11; } - &.dropdown .menu .menu>.item>.floating.label { + &.dropdown .menu .menu > .item > .floating.label { z-index: 21; } .text { &.red { color: #d95c5c !important; + a { color: #d95c5c !important; + &:hover { color: #E67777 !important; } } } + &.blue { color: #428bca !important; + a { color: #15c !important; + &:hover { color: #428bca !important; } } } + &.black { color: #444; + &:hover { color: #000; } } + &.grey { color: #767676 !important; + a { color: #444 !important; + &:hover { color: #000 !important; } } } + &.light.grey { color: #888 !important; } + &.green { color: #6cc644 !important; } + &.purple { color: #6e5494 !important; } + &.yellow { color: #FBBD08 !important; } + &.gold { color: #a1882b !important; } @@ -353,18 +393,23 @@ pre, code { &.left { text-align: left !important; } + &.right { text-align: right !important; } + &.small { font-size: 0.75em; } + &.normal { font-weight: normal; } + &.bold { font-weight: bold; } + &.italic { font-style: italic; } @@ -393,11 +438,13 @@ pre, code { font-weight: bold; text-align: left; color: black; + .pull-right { color: black; } - &>span, .pull-right>span{ - color:#21ba45; + + & > span, .pull-right > span { + color: #21ba45; } } @@ -405,26 +452,33 @@ pre, code { padding-left: 0.75rem; vertical-align: middle; } + .warning { &.header { background-color: #F9EDBE !important; border-color: #F0C36D; } + &.segment { border-color: #F0C36D; } } + .info { &.segment { border: 1px solid #c5d5dd; + &.top { background-color: #e6f1f6 !important; + h3, h4 { margin-top: 0; } + h3:last-child { margin-top: 4px; } + > :last-child { margin-bottom: 0; } @@ -473,27 +527,35 @@ pre, code { &.red { background-color: #d95c5c !important; } + &.blue { background-color: #428bca !important; } + &.black { background-color: #444; } + &.grey { background-color: #767676 !important; } + &.light.grey { background-color: #888 !important; } + &.green { background-color: #6cc644 !important; } + &.purple { background-color: #6e5494 !important; } + &.yellow { background-color: #FBBD08 !important; } + &.gold { background-color: #a1882b !important; } @@ -504,9 +566,9 @@ pre, code { } &.pagination.menu { - @media only screen and (max-width:767px) { + @media only screen and (max-width: 767px) { .item:not(.active):not(.navigation), - .item.navigation span.navigation_label{ + .item.navigation span.navigation_label { display: none; } } @@ -515,14 +577,14 @@ pre, code { .file-comment { font: 12px @monospaced-fonts, monospace; - color: rgba(0,0,0,.87); + color: rgba(0, 0, 0, .87); } .ui.floating.dropdown { .overflow.menu { .scrolling.menu.items { - border-radius: 0px !important; + border-radius: 0 !important; box-shadow: none !important; border-bottom: 1px solid rgba(34, 36, 38, 0.15); } @@ -546,18 +608,22 @@ footer { width: 100%; flex-basis: 40px; color: #888888; + .container { width: 100vw !important; padding: 0 .5rem; + .fa { width: 16px; text-align: center; color: #428bca; } - .links >* { + + .links > * { border-left: 1px solid #d6d6d6; padding-left: 8px; margin-left: 5px; + &:first-child { border-left: none; } @@ -579,13 +645,16 @@ footer { .hide { display: none; + &.show-outdated { display: none !important; } + &.hide-outdated { display: none !important; } } + .center { text-align: center; } @@ -602,14 +671,16 @@ footer { // Conditional display @media only screen and (min-width: 768px) { .mobile-only, .ui.button.mobile-only { - display: none; + display: none; } + // has the same behaviour of sr-only, hiding the content for // non-screenreaders, but is shown on mobile devices. .sr-mobile-only { .sr-only(); } } + @media only screen and (max-width: 767px) { .not-mobile { display: none; @@ -627,6 +698,7 @@ footer { clip: rect(0, 0, 0, 0); border: 0; } + .sr-only-focusable:active, .sr-only-focusable:focus { position: static; @@ -664,19 +736,24 @@ footer { justify-content: left !important; padding-bottom: 5px; } + .ui.menu.new-menu::-webkit-scrollbar { height: 8px; display: none; } + .ui.menu.new-menu:hover::-webkit-scrollbar { display: block; } + .ui.menu.new-menu::-webkit-scrollbar-track { - background: rgba(0,0,0,0.01); + background: rgba(0, 0, 0, 0.01); } + .ui.menu.new-menu::-webkit-scrollbar-thumb { - background:rgba(0,0,0,0.2); + background: rgba(0, 0, 0, 0.2); } + .ui.menu.new-menu:after { position: absolute; margin-top: -15px; @@ -690,6 +767,7 @@ footer { clear: none; visibility: visible; } + .ui.menu.new-menu a.item:last-child { padding-right: 30px !important; } @@ -749,11 +827,7 @@ footer { background-color: #2f6b1b; } -.archived-icon{ - color: lighten(#000, 70%) !important; -} - -.archived-icon{ +.archived-icon { color: lighten(#000, 70%) !important; } @@ -763,11 +837,13 @@ footer { /* Tab color tweaks */ .ui.tabular.menu .item { - color: rgba(0,0,0,.5); + color: rgba(0, 0, 0, .5); } + .ui.tabular.menu .item:hover { - color: rgba(0,0,0,.8); + color: rgba(0, 0, 0, .8); } + .ui.tabular.menu .item.active { - color: rgba(0,0,0,.9); + color: rgba(0, 0, 0, .9); } diff --git a/public/less/_dashboard.less b/public/less/_dashboard.less index 227771f305..f59daf49d2 100644 --- a/public/less/_dashboard.less +++ b/public/less/_dashboard.less @@ -6,21 +6,26 @@ .context.user.menu { z-index: 101; min-width: 200px; + .ui.header { font-size: 1rem; text-transform: none; } } + .filter.menu { .item { text-align: left; + .text { height: 16px; vertical-align: middle; + &.truncate { width: 85%; } } + .floating.label { top: 7px; left: 90%; @@ -35,28 +40,31 @@ } } - // Sort - .jump.item { - margin: 1px; - padding-right: 0; - } - .menu { - max-height: 300px; - overflow-x: auto; - right: 0!important; - left: auto!important; - } + // Sort + .jump.item { + margin: 1px; + padding-right: 0; + } - @media only screen and (max-width: 768px) { - width: 100%; - } - } - .right.stackable.menu > .item.active { - color: #d9453d; - } + .menu { + max-height: 300px; + overflow-x: auto; + right: 0 !important; + left: auto !important; + } + + @media only screen and (max-width: 768px) { + width: 100%; + } + } + + .right.stackable.menu > .item.active { + color: #d9453d; + } } /* Accomodate for Semantic's 1px hacks on .attached elements */ + .dashboard-repos { margin: 0 1px; } @@ -73,15 +81,19 @@ margin-left: auto; margin-right: auto; } + .ui.avatar { margin-top: 13px; } + .time-since { font-size: 13px; } + .issue.title { width: 80%; } + .push.news .content ul { font-size: 13px; list-style: none; @@ -90,14 +102,17 @@ img { margin-bottom: -2px; } + .text.truncate { width: 80%; margin-bottom: -5px; } } + .commit-id { font-family: @monospaced-fonts, monospace; } + code { padding: 1px; font-size: 85%; @@ -119,6 +134,7 @@ margin-top: 5px; } } + ul { list-style: none; margin: 0; @@ -141,9 +157,10 @@ color: #888; &.rear { - font-size: 15px; + font-size: 15px; } } + .star-num { font-size: 12px; } @@ -154,18 +171,19 @@ .repo-owner-name-list { .item-name { max-width: 70%; - margin-bottom: -4px; + margin-bottom: -4px; } } #collaborative-repo-list { .owner-and-repo { max-width: 80%; - margin-bottom: -5px; + margin-bottom: -5px; } + .owner-name { max-width: 120px; - margin-bottom: -5px; + margin-bottom: -5px; } } } diff --git a/public/less/_editor.less b/public/less/_editor.less index 0457cf1483..ee671d8b4b 100644 --- a/public/less/_editor.less +++ b/public/less/_editor.less @@ -1,19 +1,24 @@ .CodeMirror { font: 14px @monospaced-fonts, monospace; + &.cm-s-default { - border-radius: 3px; - padding: 0 !important; + border-radius: 3px; + padding: 0 !important; } + .cm-comment { background: inherit !important; } } + .repository.file.editor .tab[data-tab="write"] { padding: 0 !important; } + .repository.file.editor .tab[data-tab="write"] .editor-toolbar { border: none !important; } + .repository.file.editor .tab[data-tab="write"] .CodeMirror { border-left: none; border-right: none; diff --git a/public/less/_explore.less b/public/less/_explore.less index a7a939850b..1d635c8b45 100644 --- a/public/less/_explore.less +++ b/public/less/_explore.less @@ -9,12 +9,12 @@ background-color: #FAFAFA !important; border-width: 1px !important; - .octicon { - width: 16px; - text-align: center; - margin-right: 5px; - } - } + .octicon { + width: 16px; + text-align: center; + margin-right: 5px; + } + } } .ui.repository.list { @@ -38,23 +38,26 @@ color: #888; font-size: 14px; font-weight: normal; + span:not(:last-child) { margin-right: 5px; } } } + .time { font-size: 12px; color: #808080; } + .ui.tags { margin-bottom: 1em; } } } -.ui.repository.branches { - .time{ +.ui.repository.branches { + .time { font-size: 12px; color: #808080; } @@ -83,6 +86,7 @@ a { color: #333; + &:hover { text-decoration: underline; } diff --git a/public/less/_form.less b/public/less/_form.less index ee5b0aa4e1..641df7caaf 100644 --- a/public/less/_form.less +++ b/public/less/_form.less @@ -6,10 +6,13 @@ display: inline-block; } } + .ui.attached.header { background: #f0f0f0; + .right { margin-top: -5px; + .button { padding: 8px 10px; font-weight: normal; @@ -19,64 +22,76 @@ @create-page-form-input-padding: 250px !important; #create-page-form { - form { - margin: auto; - .ui.message { - text-align: center; - } - @media only screen and (min-width: 768px) { - width: 800px!important; - .header { - padding-left: @create-page-form-input-padding+30px; - } - .inline.field > label { - text-align: right; - width: @create-page-form-input-padding; - word-wrap: break-word; - } - .help { - margin-left: @create-page-form-input-padding+15px; - } - .optional .title { - margin-left: @create-page-form-input-padding; - } - input, - textarea { - width: 50%!important; - } - } - @media only screen and (max-width: 767px) { - .optional .title { - margin-left: 15px; - } - .inline.field > label { - display: block; - } - } - } + form { + margin: auto; + + .ui.message { + text-align: center; + } + + @media only screen and (min-width: 768px) { + width: 800px !important; + .header { + padding-left: @create-page-form-input-padding+30px; + } + + .inline.field > label { + text-align: right; + width: @create-page-form-input-padding; + word-wrap: break-word; + } + + .help { + margin-left: @create-page-form-input-padding+15px; + } + + .optional .title { + margin-left: @create-page-form-input-padding; + } + + input, + textarea { + width: 50% !important; + } + } + @media only screen and (max-width: 767px) { + .optional .title { + margin-left: 15px; + } + + .inline.field > label { + display: block; + } + } + } } .signin { - .oauth2{ + .oauth2 { div { - display: inline-block; + display: inline-block; + p { - margin: 10px 5px 0 0; - float: left; + margin: 10px 5px 0 0; + float: left; } } + a { - margin-right: 3px; + margin-right: 3px; + &:last-child { - margin-right: 0px; + margin-right: 0; } } + img { - width: 32px; - height: 32px; - &.openidConnect { - width: auto; - } + width: 32px; + height: 32px; + + &.openidConnect { + width: auto; + } } } } @@ -88,10 +103,11 @@ padding-left: 30px; } } -@media screen and (max-height: 575px){ + +@media screen and (max-height: 575px) { #rc-imageselect, .g-recaptcha { - transform:scale(0.77); - transform-origin:0 0; + transform: scale(0.77); + transform-origin: 0 0; } } @@ -102,12 +118,15 @@ .user.signup { @input-padding: 200px; #create-page-form; + form { - width: 700px!important; + width: 700px !important; + .header { padding-left: 0 !important; text-align: center; } + .inline.field > label { width: @input-padding; } @@ -125,19 +144,23 @@ &.new.migrate, &.new.fork { #create-page-form; + form { .dropdown { .dropdown.icon { - margin-top: -7px!important; + margin-top: -7px !important; padding-bottom: 5px; } + .text { - margin-right: 0!important; + margin-right: 0 !important; + i { - margin-right: 0!important; + margin-right: 0 !important; } } } + .header { padding-left: 0 !important; text-align: center; @@ -156,23 +179,23 @@ } } - &.new.repo { - .ui.form { - @media only screen and (min-width: 768px) { - #auto-init { - margin-left: @create-page-form-input-padding+15px; - } - } + &.new.repo { + .ui.form { + @media only screen and (min-width: 768px) { + #auto-init { + margin-left: @create-page-form-input-padding+15px; + } + } - .selection.dropdown:not(.owner) { - width: 50%!important; + .selection.dropdown:not(.owner) { + width: 50% !important; - @media only screen and (max-width: 768px) { - width: 100% !important; - } - } - } - } + @media only screen and (max-width: 768px) { + width: 100% !important; + } + } + } + } } .new.webhook { @@ -198,14 +221,14 @@ } .new.org .ui.form { - @media only screen and (max-width: 768px) { - .field button, .field a{ - margin-bottom: 1em; - width: 100%; - } + @media only screen and (max-width: 768px) { + .field button, .field a { + margin-bottom: 1em; + width: 100%; + } - .field input { - width: 100% !important; - } - } + .field input { + width: 100% !important; + } + } } diff --git a/public/less/_home.less b/public/less/_home.less index 93c7dd82ea..7ea8a9a6f3 100644 --- a/public/less/_home.less +++ b/public/less/_home.less @@ -1,42 +1,50 @@ .home { - .logo { - max-width: 220px; - } - .hero { - @media only screen and (max-width: 767px) { - h1 { - font-size: 3.5em; - } - h2 { - font-size: 2em; - } - } - @media only screen and (min-width: 768px) { - h1 { - font-size: 5.5em; - } - h2 { - font-size: 3em; - } - } - .octicon { - color: #5aa509; - font-size: 40px; - width: 50px; - } - &.header { - font-size: 20px; - } - } - p.large { - font-size: 16px - } - .stackable { - padding-top: 30px; - } - a { - color: #5aa509; - } + .logo { + max-width: 220px; + } + + .hero { + @media only screen and (max-width: 767px) { + h1 { + font-size: 3.5em; + } + + h2 { + font-size: 2em; + } + } + @media only screen and (min-width: 768px) { + h1 { + font-size: 5.5em; + } + + h2 { + font-size: 3em; + } + } + + .octicon { + color: #5aa509; + font-size: 40px; + width: 50px; + } + + &.header { + font-size: 20px; + } + } + + p.large { + font-size: 16px + } + + .stackable { + padding-top: 30px; + } + + a { + color: #5aa509; + } } .signup { @@ -44,11 +52,11 @@ } footer { - .ui.container .left, .ui.container .right { - @media only screen and (max-width: 880px) { - display: block; - text-align: center; - float: none; - } - } + .ui.container .left, .ui.container .right { + @media only screen and (max-width: 880px) { + display: block; + text-align: center; + float: none; + } + } } diff --git a/public/less/_install.less b/public/less/_install.less index 3463370446..b38ec87b76 100644 --- a/public/less/_install.less +++ b/public/less/_install.less @@ -1,27 +1,35 @@ .install { padding-top: 45px; + form { @input-padding: 320px !important; + label { text-align: right; width: @input-padding; } + input { width: 35% !important; } + .field { text-align: left; + .help { margin-left: @input-padding+15px; } + &.optional .title { margin-left: 38%; } } } + .ui { .checkbox { margin-left: 40% !important; + label { width: auto !important; } diff --git a/public/less/_markdown.less b/public/less/_markdown.less index 445bf75b62..d8a616919d 100644 --- a/public/less/_markdown.less +++ b/public/less/_markdown.less @@ -12,11 +12,11 @@ padding: 2em 2em 2em !important; } - >*:first-child { + > *:first-child { margin-top: 0 !important; } - >*:last-child { + > *:last-child { margin-bottom: 0 !important; } @@ -66,9 +66,9 @@ h4 .octicon-link, h5 .octicon-link, h6 .octicon-link { - display:none; - color:#000; - vertical-align:middle; + display: none; + color: #000; + vertical-align: middle; } h1:hover .anchor, @@ -77,9 +77,9 @@ h4:hover .anchor, h5:hover .anchor, h6:hover .anchor { - padding-left:8px; - margin-left:-30px; - text-decoration:none; + padding-left: 8px; + margin-left: -30px; + text-decoration: none; } h1:hover .anchor .octicon-link, @@ -88,7 +88,7 @@ h4:hover .anchor .octicon-link, h5:hover .anchor .octicon-link, h6:hover .anchor .octicon-link { - display:inline-block; + display: inline-block; } h1 tt, @@ -103,62 +103,63 @@ h5 code, h6 tt, h6 code { - font-size:inherit; + font-size: inherit; } h1 { - padding-bottom:0.3em; - font-size:2.25em; - line-height:1.2; - border-bottom:1px solid #eee; + padding-bottom: 0.3em; + font-size: 2.25em; + line-height: 1.2; + border-bottom: 1px solid #eee; } h1 .anchor { - line-height:1; + line-height: 1; } h2 { - padding-bottom:0.3em; - font-size:1.75em; - line-height:1.225; - border-bottom:1px solid #eee; + padding-bottom: 0.3em; + font-size: 1.75em; + line-height: 1.225; + border-bottom: 1px solid #eee; } h2 .anchor { - line-height:1; + line-height: 1; } h3 { - font-size:1.5em; - line-height:1.43; + font-size: 1.5em; + line-height: 1.43; } h3 .anchor { - line-height:1.2; + line-height: 1.2; } h4 { - font-size:1.25em; + font-size: 1.25em; } h4 .anchor { - line-height:1.2; + line-height: 1.2; } h5 { - font-size:1em; + font-size: 1em; } h5 .anchor { - line-height:1.1; + line-height: 1.1; } h6 { - font-size:1em;color:#777; + font-size: 1em; + color: #777; } h6 .anchor { - line-height:1.1; + line-height: 1.1; } p, @@ -171,35 +172,36 @@ margin-top: 0; margin-bottom: 16px; } + blockquote { margin-left: 0; } hr { - height:4px; - padding:0; - margin:16px 0; - background-color:#e7e7e7; - border:0 none; + height: 4px; + padding: 0; + margin: 16px 0; + background-color: #e7e7e7; + border: 0 none; } ul, ol { - padding-left:2em; + padding-left: 2em; } ul.no-list, ol.no-list { - padding:0; - list-style-type:none; + padding: 0; + list-style-type: none; } ul ul, ul ol, ol ol, ol ul { - margin-top:0; - margin-bottom:0; + margin-top: 0; + margin-bottom: 0; } ol ol, @@ -207,51 +209,51 @@ list-style-type: lower-roman; } - li>p { - margin-top:0; + li > p { + margin-top: 0; } dl { - padding:0; + padding: 0; } dl dt { - padding:0; - margin-top:16px; - font-size:1em; - font-style:italic; - font-weight:bold; + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: bold; } dl dd { - padding:0 16px; - margin-bottom:16px; + padding: 0 16px; + margin-bottom: 16px; } blockquote { - padding:0 15px; - color:#777; - border-left:4px solid #ddd; + padding: 0 15px; + color: #777; + border-left: 4px solid #ddd; } - blockquote>:first-child { - margin-top:0; + blockquote > :first-child { + margin-top: 0; } - blockquote>:last-child { - margin-bottom:0; + blockquote > :last-child { + margin-bottom: 0; } table { - width:auto; - overflow:auto; - word-break:normal; - word-break:keep-all; - display:block; + width: auto; + overflow: auto; + word-break: normal; + word-break: keep-all; + display: block; } table th { - font-weight:bold; + font-weight: bold; } table th, @@ -261,204 +263,202 @@ } table tr { - background-color:#fff; - border-top:1px solid #ccc; + background-color: #fff; + border-top: 1px solid #ccc; } table tr:nth-child(2n) { - background-color:#f8f8f8; + background-color: #f8f8f8; } img { - max-width:100%; - box-sizing:border-box; + max-width: 100%; + box-sizing: border-box; } .emoji { - max-width:none; + max-width: none; } span.frame { - display:block; - overflow:hidden; + display: block; + overflow: hidden; } - span.frame>span { - display:block; - float:left; - width:auto; - padding:7px; - margin:13px 0 0; - overflow:hidden; - border:1px solid #ddd; + span.frame > span { + display: block; + float: left; + width: auto; + padding: 7px; + margin: 13px 0 0; + overflow: hidden; + border: 1px solid #ddd; } span.frame span img { - display:block; - float:left; + display: block; + float: left; } span.frame span span { - display:block; - padding:5px 0 0; - clear:both; - color:#333; + display: block; + padding: 5px 0 0; + clear: both; + color: #333; } span.align-center { - display:block; - overflow:hidden; - clear:both; + display: block; + overflow: hidden; + clear: both; } - span.align-center>span { - display:block; - margin:13px auto 0; - overflow:hidden; - text-align:center; + span.align-center > span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: center; } span.align-center span img { - margin:0 auto; - text-align:center; + margin: 0 auto; + text-align: center; } span.align-right { - display:block; - overflow:hidden; - clear:both; + display: block; + overflow: hidden; + clear: both; } - span.align-right>span { - display:block; - margin:13px 0 0; - overflow:hidden; - text-align:right; + span.align-right > span { + display: block; + margin: 13px 0 0; + overflow: hidden; + text-align: right; } span.align-right span img { - margin:0; - text-align:right; + margin: 0; + text-align: right; } span.float-left { - display:block; - float:left; - margin-right:13px; - overflow:hidden; + display: block; + float: left; + margin-right: 13px; + overflow: hidden; } span.float-left span { - margin:13px 0 0; + margin: 13px 0 0; } span.float-right { - display:block; - float:right; - margin-left:13px; - overflow:hidden; + display: block; + float: right; + margin-left: 13px; + overflow: hidden; } - span.float-right>span { - display:block; - margin:13px auto 0; - overflow:hidden; - text-align:right; + span.float-right > span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: right; } code, tt { - padding:0; - padding-top:0.2em; - padding-bottom:0.2em; - margin:0; - font-size:85%; - background-color:rgba(0,0,0,0.04); - border-radius:3px; + padding: 0.2em 0; + margin: 0; + font-size: 85%; + background-color: rgba(0, 0, 0, 0.04); + border-radius: 3px; } code:before, code:after, tt:before, tt:after { - letter-spacing:-0.2em; - content:"\00a0"; + letter-spacing: -0.2em; + content: "\00a0"; } code br, tt br { - display:none; + display: none; } del code { - text-decoration:inherit; + text-decoration: inherit; } - pre>code { - padding:0; - margin:0; - font-size:100%; - word-break:normal; - white-space:pre; - background:transparent; - border:0; + pre > code { + padding: 0; + margin: 0; + font-size: 100%; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; } .highlight { - margin-bottom:16px; + margin-bottom: 16px; } .highlight pre, pre { - padding:16px; - overflow:auto; - font-size:85%; - line-height:1.45; - background-color:#f7f7f7; - border-radius:3px; + padding: 16px; + overflow: auto; + font-size: 85%; + line-height: 1.45; + background-color: #f7f7f7; + border-radius: 3px; } .highlight pre { - margin-bottom:0; - word-break:normal; + margin-bottom: 0; + word-break: normal; } pre { - word-wrap:normal; + word-wrap: normal; } pre code, pre tt { - display:inline; - max-width:initial; - padding:0; - margin:0; - overflow:initial; - line-height:inherit; - word-wrap:normal; - background-color:transparent; - border:0; + display: inline; + max-width: initial; + padding: 0; + margin: 0; + overflow: initial; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; } pre code:before, pre code:after, pre tt:before, pre tt:after { - content:normal; + content: normal; } kbd { - display:inline-block; - padding:3px 5px; - font-size:11px; - line-height:10px; - color:#555; - vertical-align:middle; - background-color:#fcfcfc; - border:solid 1px #ccc; - border-bottom-color:#bbb; - border-radius:3px; - box-shadow:inset 0 -1px 0 #bbb; + display: inline-block; + padding: 3px 5px; + font-size: 11px; + line-height: 10px; + color: #555; + vertical-align: middle; + background-color: #fcfcfc; + border: solid 1px #ccc; + border-bottom-color: #bbb; + border-radius: 3px; + box-shadow: inset 0 -1px 0 #bbb; } input[type="checkbox"] { @@ -467,27 +467,29 @@ .csv-data td, .csv-data th { - padding:5px; - overflow:hidden; - font-size:12px; - line-height:1; - text-align:left; - white-space:nowrap; + padding: 5px; + overflow: hidden; + font-size: 12px; + line-height: 1; + text-align: left; + white-space: nowrap; } .csv-data .blob-num { - padding:10px 8px 9px; - text-align:right; - background:#fff;border:0; + padding: 10px 8px 9px; + text-align: right; + background: #fff; + border: 0; } .csv-data tr { - border-top:0; + border-top: 0; } .csv-data th { - font-weight:bold; - background:#f8f8f8;border-top:0; + font-weight: bold; + background: #f8f8f8; + border-top: 0; } .ui.list .list, ol.ui.list ol, ul.ui.list ul { diff --git a/public/less/_organization.less b/public/less/_organization.less index 02c5f1f2ee..f7e855edec 100644 --- a/public/less/_organization.less +++ b/public/less/_organization.less @@ -8,6 +8,7 @@ font-size: 1.6rem; margin-left: 15px; } + .ui.right { margin-top: 5px; } @@ -16,6 +17,7 @@ &.new.org { #create-page-form; + form { .header { padding-left: 0 !important; @@ -42,10 +44,12 @@ font-size: 36px; margin-bottom: 0; } + .desc { font-size: 16px; margin-bottom: 10px; } + .meta { .item { display: inline-block; @@ -84,8 +88,7 @@ &.invite { #invite-box { - margin: auto; - margin-top: 50px; + margin: 50px auto auto; width: 500px !important; #search-user-box { @@ -94,6 +97,7 @@ width: 300px; } } + .ui.button { margin-left: 5px; margin-top: -3px; @@ -112,6 +116,7 @@ width: 48px; height: 48px; } + .meta { line-height: 24px; } diff --git a/public/less/_repository.less b/public/less/_repository.less index c746f5bbcf..e31bc89642 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -89,7 +89,7 @@ } .item { - padding: 0px; + padding: 0; } .label.color { @@ -181,7 +181,7 @@ .ui.tabs { &.container { margin-top: 14px; - margin-bottom: 0px; + margin-bottom: 0; .ui.menu { border-bottom: none; @@ -524,7 +524,7 @@ input { vertical-align: middle; - box-shadow: rgba(0, 0, 0, 0.0745098) 0px 1px 2px inset; + box-shadow: rgba(0, 0, 0, 0.0745098) 0 1px 2px inset; width: inherit; padding: 7px 8px; margin-right: 5px; @@ -696,8 +696,7 @@ &.tab.segment { border: none; - padding: 0; - padding-top: 10px; + padding: 10px 0 0; box-shadow: none; background-color: inherit; } @@ -791,7 +790,7 @@ .content { margin-left: 4em; - >.header { + > .header { #avatar-arrow; font-weight: normal; padding: auto 15px; @@ -818,7 +817,7 @@ font-style: italic; } - >.bottom.segment { + > .bottom.segment { background: #f3f4f5; .ui.images::after { @@ -871,8 +870,7 @@ .tab.segment { border: none; - padding: 0; - padding-top: 10px; + padding: 10px 0 0; } textarea { @@ -926,7 +924,7 @@ &.octicon-eye { margin-top: 3px; margin-left: -35px; - margin-right: 0px; + margin-right: 0; font-size: 22px; } @@ -991,8 +989,7 @@ .tab.segment { border: none; - padding: 0; - padding-top: 10px; + padding: 10px 0 0; } textarea { @@ -1036,12 +1033,12 @@ list-style: none; padding-top: 15px; - >.item { + > .item { padding-top: 10px; padding-bottom: 10px; border-bottom: 1px dashed #AAA; - >a { + > a { padding-top: 5px; padding-right: 10px; color: #000; @@ -1078,7 +1075,7 @@ .operate { margin-top: -15px; - >a { + > a { font-size: 15px; padding-top: 5px; padding-right: 10px; @@ -1234,7 +1231,7 @@ background: #fff; line-height: 30px; - >div:after { + > div:after { clear: both; content: ""; display: block; @@ -1281,7 +1278,7 @@ .detail-files { background: #fff; - margin: 0px; + margin: 0; } } @@ -1351,8 +1348,7 @@ font-size: 12px; td { - padding: 0; - padding-left: 10px; + padding: 0 0 0 10px; border-top: none; } @@ -1509,7 +1505,7 @@ margin-top: 20px; padding-top: 15px; - >li { + > li { list-style: none; .meta, @@ -1545,7 +1541,7 @@ .download { margin-top: 20px; - >a { + > a { .octicon { margin-left: 5px; margin-right: 5px; @@ -1686,7 +1682,7 @@ text-transform: none; } - >.markdown { + > .markdown { padding: 15px 30px; h1, @@ -1715,7 +1711,7 @@ .collaborator.list { padding: 0; - >.item { + > .item { margin: 0; line-height: 2em; @@ -1839,11 +1835,11 @@ right: 0 !important; left: auto !important; - >.header { + > .header { margin: 0.75rem 0 .5rem; } - >.item { + > .item { float: left; padding: .5rem .5rem !important; @@ -1864,7 +1860,7 @@ cursor: default; } - >img { + > img { height: 1.5em !important; } } @@ -1954,7 +1950,7 @@ .issue.list { list-style: none; - >.item { + > .item { padding-top: 15px; padding-bottom: 10px; border-bottom: 1px dashed #AAA; @@ -2042,14 +2038,14 @@ .content { margin-top: 2px; - >.header, + > .header, .segment { box-shadow: 0 1px 2px 0 rgba(34, 36, 38, .15); } } .list { - >.item { + > .item { .green { color: #21BA45; } @@ -2060,11 +2056,11 @@ margin: 15px -1rem -1rem -1rem; } - >.mega-octicon { + > .mega-octicon { display: table-cell; } - >.mega-octicon+.content { + > .mega-octicon + .content { display: table-cell; padding: 0 0 0 .5em; vertical-align: top; @@ -2088,13 +2084,13 @@ } &.email { - >.item:not(:first-child) { + > .item:not(:first-child) { min-height: 60px; } } &.collaborator { - >.item { + > .item { padding: 0; } } @@ -2191,7 +2187,7 @@ .generate-tab-size(@n, @i: 1) when (@i =< @n) { .tab-size-@{i} { - tab-size: @i !important; + tab-size: @i !important; } .generate-tab-size(@n, (@i + 1)); @@ -2220,7 +2216,7 @@ tbody.commit-list { @media only screen and (max-width: 767px) { .ui.stackable.menu { - &.mobile--margin-between-items>.item { + &.mobile--margin-between-items > .item { margin-top: 5px; margin-bottom: 5px; } @@ -2247,7 +2243,7 @@ tbody.commit-list { #new-dependency-drop-list { &.ui.selection.dropdown { min-width: 0; - width: 100%; + width: 100%; border-radius: 4px 0 0 4px; border-right: 0; white-space: nowrap; @@ -2263,7 +2259,7 @@ tbody.commit-list { font-size: 12px; } -.label+#manage_topic { +.label + #manage_topic { margin-left: 5px; } @@ -2294,7 +2290,7 @@ tbody.commit-list { box-shadow: 0 0 0 1px rgba(34, 36, 38, .15) inset !important; } -.repo-buttons .ui.labeled.button>.label { +.repo-buttons .ui.labeled.button > .label { border-left: none !important; margin: 0 !important; } diff --git a/public/less/_review.less b/public/less/_review.less index bb2e85b155..a4a813cfd8 100644 --- a/public/less/_review.less +++ b/public/less/_review.less @@ -12,7 +12,7 @@ transform: scale(1, 1); &:hover { - transform: scale(1.2, 1.2); + transform: scale(1.2, 1.2); } } @@ -23,12 +23,9 @@ .comment-code-cloud { padding: 4px; - margin: 0 auto; position: relative; border: 1px solid #f1f1f1; - margin-top: 13px; - margin-right: 10px; - margin-bottom: 5px; + margin: 13px 10px 5px auto; &:before { content: " "; @@ -42,8 +39,7 @@ top: -13px; } - .attached - { + .attached { &.tab { border: none; padding: 0; @@ -66,7 +62,7 @@ } .ui.form textarea { - border: 0px; + border: 0; } .ui.attached.tabular.menu { @@ -74,7 +70,7 @@ border: 1px solid #d4d4d5; padding-top: 5px; padding-left: 5px; - margin-top: 0px; + margin-top: 0; } .footer { @@ -85,14 +81,14 @@ display: inline-block; margin: 5px 0; font-size: 12px; - color: rgba(0,0,0,.6) + color: rgba(0, 0, 0, .6) } .ui.right.floated { padding-top: 6px; } - &:after{ + &:after { clear: both; content: ""; display: block; @@ -110,5 +106,5 @@ .file-comment { font: 12px @monospaced-fonts, monospace; - color: rgba(0,0,0,.87); + color: rgba(0, 0, 0, .87); } diff --git a/public/less/_tribute.less b/public/less/_tribute.less index 06e57d238d..4db85a2cb6 100644 --- a/public/less/_tribute.less +++ b/public/less/_tribute.less @@ -1,26 +1,31 @@ .tribute-container { - box-shadow: 0px 1px 3px 1px #c7c7c7; - ul { - background: #ffffff; - } - li { - padding: 8px 12px; - border-bottom: 1px solid #dcdcdc; - img { - display: inline-block; - vertical-align: middle; - width: 28px; - height: 28px; - margin-right: 5px; - } - span.fullname { - font-weight: normal; - font-size: 0.8rem; - margin-left: 3px; - } - } - li.highlight, li:hover { - background: #2185D0; - color: #ffffff; - } + box-shadow: 0 1px 3px 1px #c7c7c7; + + ul { + background: #ffffff; + } + + li { + padding: 8px 12px; + border-bottom: 1px solid #dcdcdc; + + img { + display: inline-block; + vertical-align: middle; + width: 28px; + height: 28px; + margin-right: 5px; + } + + span.fullname { + font-weight: normal; + font-size: 0.8rem; + margin-left: 3px; + } + } + + li.highlight, li:hover { + background: #2185D0; + color: #ffffff; + } } diff --git a/public/less/_user.less b/public/less/_user.less index fe8fbe2e8d..4b9be47269 100644 --- a/public/less/_user.less +++ b/public/less/_user.less @@ -8,6 +8,7 @@ .username { display: block; } + .extra.content { padding: 0; @@ -58,7 +59,7 @@ margin-top: 25px; } - #loading-heatmap{ + #loading-heatmap { margin-bottom: 1em; } } @@ -82,6 +83,7 @@ float: left; font-size: 2em; } + .content { float: left; margin-left: 7px; @@ -105,21 +107,26 @@ &.green { color: #21ba45; } + &.red { color: #d01919; } + &.purple { color: #a333c8; } + &.blue { color: #2185d0; } } } + &.link-account:not(.icon) { padding-top: 15px; padding-bottom: 5px; } + &.settings { .iconFloat { float: left; diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index c753e775f4..7a6fb64150 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -1,796 +1,1024 @@ @import "_base"; .hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - color: #bababa; + display: block; + overflow-x: auto; + padding: 0.5em; + color: #bababa; } - .repository.file.list .non-diff-file-content .code-view .lines-num, .repository.file.list .non-diff-file-content .code-view .lines-code ol { + +.repository.file.list .non-diff-file-content .code-view .lines-num, .repository.file.list .non-diff-file-content .code-view .lines-code ol { background-color: #2b2b2b !important; } - .hljs-strong, .hljs-emphasis { - color: #a8a8a2; -} - .hljs-bullet, .hljs-quote, .hljs-link, .hljs-number, .hljs-regexp, .hljs-literal { - color: #6896ba; -} - .hljs-code, .hljs-selector-class { - color: #a6e22e; -} - .hljs-emphasis { - font-style: italic; -} - .hljs-keyword, .hljs-selector-tag, .hljs-section, .hljs-attribute, .hljs-name, .hljs-variable { - color: #cb7832; -} - .hljs-params { - color: #b9b9b9; -} - .hljs-string { - color: #6a8759; -} - .hljs-subst, .hljs-type, .hljs-built_in, .hljs-builtin-name, .hljs-symbol, .hljs-selector-id, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-template-tag, .hljs-template-variable, .hljs-addition { - color: #e0c46c; -} - .hljs-comment, .hljs-deletion, .hljs-meta { - color: #7f7f7f; -} - .repository .ui.segment.sub-menu .list .item a { - color:#dbdbdb; -} - .ui.horizontal.segments > .segment { - background-color: #383c4a; -} - body { - background: #383c4a; - color: #9e9e9e; -} - a { - color: #87ab63; -} - a:hover { - color: #a0cc75; -} - .ui.card>.extra a:not(.ui):hover, .ui.cards>.card>.extra a:not(.ui):hover { - color: #a0cc75; -} - .ui.breadcrumb a:hover { - color: #a0cc75; -} - .ui.breadcrumb a { - color: #87ab63; -} - .repository .metas .ui.list a .text { - color: #87ab63; -} - .repository .metas .ui.list a .text:hover { - color: #a0cc75; -} - .repository .label.list .item a { - color: #87ab63; -} - .repository .label.list .item a:hover { - color: #a0cc75; -} - .repository .milestone.list > .item > a { - color: #87ab63; -} - .repository .milestone.list > .item > a:hover { - color: #a0cc75; -} - .repository.release #release-list { - border-top: 1px solid #4c505c; -} - .repository .milestone.list > .item .operate > a { - color: #87ab63; -} - .repository .milestone.list > .item .operate > a:hover { - color: #a0cc75; -} - .ui.green.progress .bar { - background-color: #668844; -} - .ui.progress.success .bar { - background-color: #7b9e57!important; -} - .following.bar.light { - background: #2e323e; -} - .ui.secondary.menu .active.item { - color: #dbdbdb; -} - .ui.secondary.menu .item { - color: #9e9e9e; -} - .following.bar .top.menu a.item:hover { - color: #fff; -} - .repository.view.issue .comment-list .comment .content > .bottom.segment a { - border: solid 1px #353945; - background-color: #353945; -} - .following.bar.light { - border-bottom: 1px solid #313131; -} - .ui.attached.header { - background: #404552; - border: 1px solid #404552; - color: #dbdbdb; -} - .ui.attached.table { - border: 1px solid #304251; - background: #304251; -} - .feeds .list ul li:not(:last-child) { - border-bottom: 1px solid #333640; -} - .feeds .list ul li.private { - background: #353945; - border: 1px solid #333640; -} - .ui.secondary.menu .dropdown.item:hover, .ui.secondary.menu .link.item:hover, .ui.secondary.menu a.item:hover { - color: #fff; -} - .ui.menu .ui.dropdown .menu>.item { - background: #2c303a !important; - color: #9e9e9e !important; -} - .ui.secondary.menu .dropdown.item>.menu, .ui.text.menu .dropdown.item>.menu { - border: 1px solid #434444; -} - footer { - background: #2e323e; - border-top: 1px solid #313131; -} - .ui.menu .dropdown.item .menu { - background: #2c303a; -} - .ui.menu .ui.dropdown .menu>.item:hover, .ui.menu .ui.dropdown .menu>.selected.item { - color: #fff!important; -} - .ui.dropdown .menu>.header { - color: #dbdbdb; -} - .ui.red.label, .ui.red.labels .label { - background-color: #7d3434!important; - border-color: #8a2121!important; -} - .ui.menu { - background: #404552; - border: 1px solid #353945; -} - .ui.menu .active.item:hover, .ui.vertical.menu .active.item:hover { - color: #dbdbdb; - background: #4B5162; -} - .ui.link.menu .item:hover, .ui.menu .dropdown.item:hover, .ui.menu .link.item:hover, .ui.menu a.item:hover { - color: #dbdbdb; - background: #454b5a; -} - .ui.menu .active.item { - background: #4B5162; - color: #dbdbdb; -} - .ui.input input { - background: #404552; - border: 2px solid #353945; - color: #dbdbdb; -} - .ui.input input:focus, .ui.input.focus input { - background: #404552; - border: 2px solid #353945; - color: #dbdbdb; -} - .ui.accordion .title:not(.ui) { - color: #dbdbdb; -} - .ui.label { - color: #dbdbdb; - background-color: #404552; -} - .issue.list > .item .title { - color: #87ab63; -} - .issue.list > .item .title:hover { - color: #a0cc75; -} - .issue.list > .item { - border-bottom: 1px dashed #475767; -} - .ui.green.label, .ui.green.labels .label, .ui.basic.green.label { - background-color: #2d693b!important; - border-color: #2d693b!important; -} - .ui.basic.green.labels a.label:hover, a.ui.basic.green.label:hover { - background-color: #16ab39 !important; - border-color: #16ab39 !important; - color: #fff !important; -} - .issue.list > .item .comment { - color: #129c92; -} - .ui.basic.button, .ui.basic.buttons .button { - color: #797979!important; -} - .ui.basic.red.active.button, .ui.basic.red.buttons .active.button { - box-shadow: 0 0 0 1px #c75252 inset!important; - color: #c75252!important; -} - .ui.basic.button:focus, .ui.basic.button:hover, .ui.basic.buttons .button:focus, .ui.basic.buttons .button:hover { - background: transparent!important; - color: #dbdbdb!important; -} - .ui.menu .item { - background: #404552; - color: #9e9e9e; -} - .ui.menu .item.disabled, .ui.menu .item.disabled:hover { - color: #626773; -} - .ui.pagination.menu .active.item { - color: #dbdbdb; - background-color: #87ab63; -} - .repository .header-wrapper { - background-color: #2a2e3a; -} - .ui.tabular.menu .active.item { - background: #383c4a; - color: #dbdbdb; - border-left: 1px solid transparent; - border-right: 1px solid transparent; - border-top: none; -} - .ui.tabular.menu .item { - color: #9e9e9e; -} - .ui.tabular.menu .item:hover { - color: #dbdbdb; -} - .ui.header, .ui.breadcrumb .divider { - color: #9e9e9e; -} - .ui.blue.label, .ui.blue.labels .label { - background-color: #26577b!important; - border-color: #26577b!important; -} - .ui.menu .item>.label { - background: #565454; -} - .ui.blue.button, .ui.blue.buttons .button { - background-color: #87ab63; -} - .ui.blue.button:hover, .ui.blue.buttons .button:hover { - background-color: #a0cc75; -} - .ui.form input:not([type]), .ui.form input[type=text], .ui.form input[type=email], .ui.form input[type=search], .ui.form input[type=password], .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=tel], .ui.form input[type=time], .ui.form input[type=url], .ui.form input[type=number] { - background: #404552; - border: 2px solid #353945; -} - .ui.form input:not([type]):focus, .ui.form input[type=text]:focus, .ui.form input[type=email]:focus, .ui.form input[type=search]:focus, .ui.form input[type=password]:focus, .ui.form input[type=date]:focus, .ui.form input[type=datetime-local]:focus, .ui.form input[type=tel]:focus, .ui.form input[type=time]:focus, .ui.form input[type=url]:focus, .ui.form input[type=number]:focus { - background: #404552; - border: 2px solid #4b505f; - color: #dbdbdb; -} - .ui.action.input:not([class*="left action"]) input:focus { - border-right-color: #4b505f!important; -} - .ui.green.button, .ui.green.buttons .button { - background-color: #87ab63; -} - .ui.green.button:hover, .ui.green.buttons .button:hover { - background-color: #a0cc75; -} - .ui.button { - background: #383c4a; - border: 1px solid #4c505c; - color: #dbdbdb; -} - .ui.labeled.button:not([class*="left labeled"])>.label, .ui[class*="left labeled"].button>.button { - background: #404552; - border: 1px solid #4c505c; - color: #87ab63; -} - .ui.button:hover { - background-color: #404552; - color: #dbdbdb; -} - .ui.table thead th { - background: #404552; - color: #dbdbdb; -} - .repository.file.list #repo-files-table tr:hover { - background-color: #393d4a; -} - .ui.table { - color: #a5a5a5!important; - border: 1px solid #4c505c; - background: #353945; -} - .ui.table tbody tr { - border-bottom: 1px solid #333640; - background: #2a2e3a; -} - .ui .text.grey { - color: #808084 !important; -} - .ui.attached.table.segment { - background: #353945; - color: #dbdbdb!important; -} - .markdown:not(code) h2 { - border-bottom: 1px solid #304251; -} - .hljs, .hljs-keyword, .hljs-selector-tag, .hljs-subst { - color: #9daccc; -} - .markdown:not(code) .highlight pre, .markdown:not(code) pre { - background-color: #2a2e3a; - border: 1px solid #404552; -} - .markdown:not(code) table tr:nth-child(2n) { - background-color: #474d61; -} - .ui.dropdown .menu { - background: #2c303a; -} - .ui.dropdown .menu>.message:not(.ui) { - color: rgb(99, 99, 99); -} - .ui.input { - color: #dbdbdb; -} - .overflow.menu .items .item { - color: #9d9d9d; -} - .overflow.menu .items .item:hover { - color: #dbdbdb; -} - .ui.segment { - background: #353945; - color: #9e9e9e!important; - border: 1px solid #404552; -} - .ui.active.button:active, .ui.button:active, .ui.button:focus { - background-color: #2e3e4e; - color: #dbdbdb; -} - .ui.dropdown .menu .selected.item, .ui.dropdown.selected { - color: #dbdbdb; -} - .ui.dropdown .menu>.item:hover { - color: #dbdbdb; -} - .ui.dropdown .menu>.item { - color: #9e9e9e; -} - .ui.attached.segment { - border: 1px solid #404552; -} - .repository.view.issue .comment-list .comment .content > .bottom.segment { - background: #353945; -} - .repository.view.issue .comment-list .comment .content .header { - color: #dbdbdb; - background-color: #404552; - border-bottom: 1px solid #353944; -} - .ui .text.grey a { - color: #b3b3b3 !important; -} - .ui.comments .comment .actions a { - color: #dbdbdb; -} - .repository.view.issue .comment-list .comment .content .header:after { - border-right-color: #404552; -} - .repository.new.issue .comment.form .content:after { - border-right-color: #353945; -} - .repository.view.issue .comment-list .comment .content .header:before { - border-right-color: #404552; -} - .repository.new.issue .comment.form .content:before { - border-right-color: #353945; -} - .repository.view.issue .comment-list:before { - background-color: #313c47; -} - .repository .comment.form .content .form:after { - border-right-color: #313c47; -} - .repository .comment.form .content .form:before { - border-right-color: #313c47; -} - .ui .text.grey a { - color: #dbdbdb !important; -} - .ui .text.grey a:hover { - color: #dbdbdb !important; -} - .ui.basic.green.active.button, .ui.basic.green.buttons .active.button { - color: #13ae38!important; -} - .ui.form textarea, .ui.form textarea:focus { - background: #1a2632; - border: 1px solid #313c47; - color: #dbdbdb; -} - .ui.form textarea:focus { - border: 1px solid #456580; -} - .ui .info.segment.top { - background-color: #404552 !important; -} - .repository .diff-file-box .code-diff-unified tbody tr.del-code td { - background-color: #3c2626 !important; - border-color: #634343 !important; -} - .repository .diff-file-box .code-diff-unified tbody tr.add-code td { - background-color: rgb(40, 62, 45) !important; - border-color: #314a37 !important; -} - .repository .diff-file-box .code-diff tbody tr .added-code { - background-color: #3a523a; -} - .repository .diff-file-box .code-diff .lines-num { - border-right: 1px solid #2d2d2d; -} - .repository .diff-file-box .file-body.file-code .lines-num { - color: #9e9e9e; - background: #2e323e; -} - .repository .diff-file-box .code-diff tbody tr.tag-code td, .repository .diff-file-box .code-diff tbody tr td.tag-code { - border-color: #2d2d2d !important; -} - .repository .diff-file-box .file-body.file-code .lines-num-old { - border-right: 1px solid #2d2d2d; -} - .hljs-title, .hljs-section, .hljs-selector-id { - color: #986c88; -} - .hljs-string, .hljs-doctag { - color: #949494; -} - .repository .diff-file-box .code-diff tbody tr .removed-code { - background-color: #5f3737; -} - .repository .diff-file-box .code-diff tbody tr.tag-code td, .repository .diff-file-box .code-diff tbody tr td.tag-code { - background-color: #292727 !important; -} - .ui.vertical.menu .active.item { - background: #4B5162; -} - .ui.vertical.menu .item { - background: #353945; -} - .ui.vertical.menu .header.item { - background: #404552; -} - .ui.vertical.menu { - background: #353945; - border: 1px solid #333640; -} - .ui.repository.list .item:not(:first-child) { - border-top: 1px solid #4c505c; -} - .ui .text.blue { - color: #87ab63 !important; -} - .ui.selection.active.dropdown, .ui.selection.active.dropdown .menu { - border-color: #4e5361; - box-shadow: 0 2px 3px 0 rgba(34,36,38,.15); -} - .ui.selection.active.dropdown:hover, .ui.selection.active.dropdown:hover .menu { - border-color: #4e5361; - box-shadow: 0 2px 3px 0 rgba(34,36,38,.15); -} - .ui.selection.dropdown { - background: #404552; - border: 1px solid rgb(64, 69, 82); - color: #9e9e9e; -} - .ui.menu .ui.dropdown .menu>.active.item { - color: #dbdbdb !important; -} - .ui.tabular.menu { - border-bottom: 1px solid #313c47; -} - .ui.card, .ui.cards>.card { - background: #353945; - box-shadow: 0 1px 3px 0 #4c505c, 0 0 0 1px #4c505c; -} - .ui.card>.content>.header, .ui.cards>.card>.content>.header { - color: #dbdbdb; -} - .ui.card>.extra a:not(.ui), .ui.cards>.card>.extra a:not(.ui) { - color: #87ab63; -} - .ui .text.black { - color: #9e9e9e; -} - .ui .text.black:hover { - color: #dbdbdb; -} - .ui.secondary.segment { - background: #353945; -} - .ui.secondary.pointing.menu .active.item { - border-color: #87ab63; - color: #dbdbdb; - background: #404552; -} - .ui.user.list .item:not(:first-child) { - border-top: 1px solid #4c505c; -} - .ui.secondary.pointing.menu .active.item:hover { - border-color: #af8b4c; - color: #dbdbdb; - background: #4b5162; -} - .ui.secondary.pointing.menu .dropdown.item:hover, .ui.secondary.pointing.menu .link.item:hover, .ui.secondary.pointing.menu a.item:hover { - color: #dbdbdb; -} - .ui.checkbox label, .ui.checkbox+label, .ui.form .field>label { - color: #9e9e9e; -} - .ui.form .inline.field>label, .ui.form .inline.field>p, .ui.form .inline.fields .field>label, .ui.form .inline.fields .field>p, .ui.form .inline.fields>label { - color: #9e9e9e; -} - .user.settings .email.list .item:not(:first-child) { - border-top: 1px solid #3f4451; -} - .explore .navbar { - background-color: #2a2e3a!important; -} - .ui.menu.new-menu { - background-color: #2a2e3a!important; - @media only screen and (max-width: 1200px) { - &:after { - background-image: linear-gradient(to right, rgba(42, 46, 42, 0), rgba(42, 46, 42, 1) 100%); - } - } -} - input { - background: #2e323e; -} - .ui.secondary.pointing.menu .active.item { - border: none; - background: #383c4a; -} - .settings .key.list .item:not(:first-child) { - border-top: 1px solid #404552; -} - .ui.form input:not([type]), .ui.form input[type=text], .ui.form input[type=email], .ui.form input[type=search], .ui.form input[type=password], .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=tel], .ui.form input[type=time], .ui.form input[type=url], .ui.form input[type=number] { - color: #9e9e9e; -} - .ui.attached.info.message, .ui.info.message { - box-shadow: 0 0 0 1px #4b5e71 inset, 0 0 0 0 transparent; -} - .ui.bottom.attached.message { - background-color: #2c662d; - color: #87ab63; -} + +.hljs-strong, .hljs-emphasis { + color: #a8a8a2; +} + +.hljs-bullet, .hljs-quote, .hljs-link, .hljs-number, .hljs-regexp, .hljs-literal { + color: #6896ba; +} + +.hljs-code, .hljs-selector-class { + color: #a6e22e; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-keyword, .hljs-selector-tag, .hljs-section, .hljs-attribute, .hljs-name, .hljs-variable { + color: #cb7832; +} + +.hljs-params { + color: #b9b9b9; +} + +.hljs-string { + color: #6a8759; +} + +.hljs-subst, .hljs-type, .hljs-built_in, .hljs-builtin-name, .hljs-symbol, .hljs-selector-id, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-template-tag, .hljs-template-variable, .hljs-addition { + color: #e0c46c; +} + +.hljs-comment, .hljs-deletion, .hljs-meta { + color: #7f7f7f; +} + +.repository .ui.segment.sub-menu .list .item a { + color: #dbdbdb; +} + +.ui.horizontal.segments > .segment { + background-color: #383c4a; +} + +body { + background: #383c4a; + color: #9e9e9e; +} + +a { + color: #87ab63; +} + +a:hover { + color: #a0cc75; +} + +.ui.card > .extra a:not(.ui):hover, .ui.cards > .card > .extra a:not(.ui):hover { + color: #a0cc75; +} + +.ui.breadcrumb a:hover { + color: #a0cc75; +} + +.ui.breadcrumb a { + color: #87ab63; +} + +.repository .metas .ui.list a .text { + color: #87ab63; +} + +.repository .metas .ui.list a .text:hover { + color: #a0cc75; +} + +.repository .label.list .item a { + color: #87ab63; +} + +.repository .label.list .item a:hover { + color: #a0cc75; +} + +.repository .milestone.list > .item > a { + color: #87ab63; +} + +.repository .milestone.list > .item > a:hover { + color: #a0cc75; +} + +.repository.release #release-list { + border-top: 1px solid #4c505c; +} + +.repository .milestone.list > .item .operate > a { + color: #87ab63; +} + +.repository .milestone.list > .item .operate > a:hover { + color: #a0cc75; +} + +.ui.green.progress .bar { + background-color: #668844; +} + +.ui.progress.success .bar { + background-color: #7b9e57 !important; +} + +.following.bar.light { + background: #2e323e; +} + +.ui.secondary.menu .active.item { + color: #dbdbdb; +} + +.ui.secondary.menu .item { + color: #9e9e9e; +} + +.following.bar .top.menu a.item:hover { + color: #fff; +} + +.repository.view.issue .comment-list .comment .content > .bottom.segment a { + border: solid 1px #353945; + background-color: #353945; +} + +.following.bar.light { + border-bottom: 1px solid #313131; +} + +.ui.attached.header { + background: #404552; + border: 1px solid #404552; + color: #dbdbdb; +} + +.ui.attached.table { + border: 1px solid #304251; + background: #304251; +} + +.feeds .list ul li:not(:last-child) { + border-bottom: 1px solid #333640; +} + +.feeds .list ul li.private { + background: #353945; + border: 1px solid #333640; +} + +.ui.secondary.menu .dropdown.item:hover, .ui.secondary.menu .link.item:hover, .ui.secondary.menu a.item:hover { + color: #fff; +} + +.ui.menu .ui.dropdown .menu > .item { + background: #2c303a !important; + color: #9e9e9e !important; +} + +.ui.secondary.menu .dropdown.item > .menu, .ui.text.menu .dropdown.item > .menu { + border: 1px solid #434444; +} + +footer { + background: #2e323e; + border-top: 1px solid #313131; +} + +.ui.menu .dropdown.item .menu { + background: #2c303a; +} + +.ui.menu .ui.dropdown .menu > .item:hover, .ui.menu .ui.dropdown .menu > .selected.item { + color: #fff !important; +} + +.ui.dropdown .menu > .header { + color: #dbdbdb; +} + +.ui.red.label, .ui.red.labels .label { + background-color: #7d3434 !important; + border-color: #8a2121 !important; +} + +.ui.menu { + background: #404552; + border: 1px solid #353945; +} + +.ui.menu .active.item:hover, .ui.vertical.menu .active.item:hover { + color: #dbdbdb; + background: #4B5162; +} + +.ui.link.menu .item:hover, .ui.menu .dropdown.item:hover, .ui.menu .link.item:hover, .ui.menu a.item:hover { + color: #dbdbdb; + background: #454b5a; +} + +.ui.menu .active.item { + background: #4B5162; + color: #dbdbdb; +} + +.ui.input input { + background: #404552; + border: 2px solid #353945; + color: #dbdbdb; +} + +.ui.input input:focus, .ui.input.focus input { + background: #404552; + border: 2px solid #353945; + color: #dbdbdb; +} + +.ui.accordion .title:not(.ui) { + color: #dbdbdb; +} + +.ui.label { + color: #dbdbdb; + background-color: #404552; +} + +.issue.list > .item .title { + color: #87ab63; +} + +.issue.list > .item .title:hover { + color: #a0cc75; +} + +.issue.list > .item { + border-bottom: 1px dashed #475767; +} + +.ui.green.label, .ui.green.labels .label, .ui.basic.green.label { + background-color: #2d693b !important; + border-color: #2d693b !important; +} + +.ui.basic.green.labels a.label:hover, a.ui.basic.green.label:hover { + background-color: #16ab39 !important; + border-color: #16ab39 !important; + color: #fff !important; +} + +.issue.list > .item .comment { + color: #129c92; +} + +.ui.basic.button, .ui.basic.buttons .button { + color: #797979 !important; +} + +.ui.basic.red.active.button, .ui.basic.red.buttons .active.button { + box-shadow: 0 0 0 1px #c75252 inset !important; + color: #c75252 !important; +} + +.ui.basic.button:focus, .ui.basic.button:hover, .ui.basic.buttons .button:focus, .ui.basic.buttons .button:hover { + background: transparent !important; + color: #dbdbdb !important; +} + +.ui.menu .item { + background: #404552; + color: #9e9e9e; +} + +.ui.menu .item.disabled, .ui.menu .item.disabled:hover { + color: #626773; +} + +.ui.pagination.menu .active.item { + color: #dbdbdb; + background-color: #87ab63; +} + +.repository .header-wrapper { + background-color: #2a2e3a; +} + +.ui.tabular.menu .active.item { + background: #383c4a; + color: #dbdbdb; + border-left: 1px solid transparent; + border-right: 1px solid transparent; + border-top: none; +} + +.ui.tabular.menu .item { + color: #9e9e9e; +} + +.ui.tabular.menu .item:hover { + color: #dbdbdb; +} + +.ui.header, .ui.breadcrumb .divider { + color: #9e9e9e; +} + +.ui.blue.label, .ui.blue.labels .label { + background-color: #26577b !important; + border-color: #26577b !important; +} + +.ui.menu .item > .label { + background: #565454; +} + +.ui.blue.button, .ui.blue.buttons .button { + background-color: #87ab63; +} + +.ui.blue.button:hover, .ui.blue.buttons .button:hover { + background-color: #a0cc75; +} + +.ui.form input:not([type]), .ui.form input[type=text], .ui.form input[type=email], .ui.form input[type=search], .ui.form input[type=password], .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=tel], .ui.form input[type=time], .ui.form input[type=url], .ui.form input[type=number] { + background: #404552; + border: 2px solid #353945; +} + +.ui.form input:not([type]):focus, .ui.form input[type=text]:focus, .ui.form input[type=email]:focus, .ui.form input[type=search]:focus, .ui.form input[type=password]:focus, .ui.form input[type=date]:focus, .ui.form input[type=datetime-local]:focus, .ui.form input[type=tel]:focus, .ui.form input[type=time]:focus, .ui.form input[type=url]:focus, .ui.form input[type=number]:focus { + background: #404552; + border: 2px solid #4b505f; + color: #dbdbdb; +} + +.ui.action.input:not([class*="left action"]) input:focus { + border-right-color: #4b505f !important; +} + +.ui.green.button, .ui.green.buttons .button { + background-color: #87ab63; +} + +.ui.green.button:hover, .ui.green.buttons .button:hover { + background-color: #a0cc75; +} + +.ui.button { + background: #383c4a; + border: 1px solid #4c505c; + color: #dbdbdb; +} + +.ui.labeled.button:not([class*="left labeled"]) > .label, .ui[class*="left labeled"].button > .button { + background: #404552; + border: 1px solid #4c505c; + color: #87ab63; +} + +.ui.button:hover { + background-color: #404552; + color: #dbdbdb; +} + +.ui.table thead th { + background: #404552; + color: #dbdbdb; +} + +.repository.file.list #repo-files-table tr:hover { + background-color: #393d4a; +} + +.ui.table { + color: #a5a5a5 !important; + border: 1px solid #4c505c; + background: #353945; +} + +.ui.table tbody tr { + border-bottom: 1px solid #333640; + background: #2a2e3a; +} + +.ui .text.grey { + color: #808084 !important; +} + +.ui.attached.table.segment { + background: #353945; + color: #dbdbdb !important; +} + +.markdown:not(code) h2 { + border-bottom: 1px solid #304251; +} + +.hljs, .hljs-keyword, .hljs-selector-tag, .hljs-subst { + color: #9daccc; +} + +.markdown:not(code) .highlight pre, .markdown:not(code) pre { + background-color: #2a2e3a; + border: 1px solid #404552; +} + +.markdown:not(code) table tr:nth-child(2n) { + background-color: #474d61; +} + +.ui.dropdown .menu { + background: #2c303a; +} + +.ui.dropdown .menu > .message:not(.ui) { + color: rgb(99, 99, 99); +} + +.ui.input { + color: #dbdbdb; +} + +.overflow.menu .items .item { + color: #9d9d9d; +} + +.overflow.menu .items .item:hover { + color: #dbdbdb; +} + +.ui.segment { + background: #353945; + color: #9e9e9e !important; + border: 1px solid #404552; +} + +.ui.active.button:active, .ui.button:active, .ui.button:focus { + background-color: #2e3e4e; + color: #dbdbdb; +} + +.ui.dropdown .menu .selected.item, .ui.dropdown.selected { + color: #dbdbdb; +} + +.ui.dropdown .menu > .item:hover { + color: #dbdbdb; +} + +.ui.dropdown .menu > .item { + color: #9e9e9e; +} + +.ui.attached.segment { + border: 1px solid #404552; +} + +.repository.view.issue .comment-list .comment .content > .bottom.segment { + background: #353945; +} + +.repository.view.issue .comment-list .comment .content .header { + color: #dbdbdb; + background-color: #404552; + border-bottom: 1px solid #353944; +} + +.ui .text.grey a { + color: #b3b3b3 !important; +} + +.ui.comments .comment .actions a { + color: #dbdbdb; +} + +.repository.view.issue .comment-list .comment .content .header:after { + border-right-color: #404552; +} + +.repository.new.issue .comment.form .content:after { + border-right-color: #353945; +} + +.repository.view.issue .comment-list .comment .content .header:before { + border-right-color: #404552; +} + +.repository.new.issue .comment.form .content:before { + border-right-color: #353945; +} + +.repository.view.issue .comment-list:before { + background-color: #313c47; +} + +.repository .comment.form .content .form:after { + border-right-color: #313c47; +} + +.repository .comment.form .content .form:before { + border-right-color: #313c47; +} + +.ui .text.grey a { + color: #dbdbdb !important; +} + +.ui .text.grey a:hover { + color: #dbdbdb !important; +} + +.ui.basic.green.active.button, .ui.basic.green.buttons .active.button { + color: #13ae38 !important; +} + +.ui.form textarea, .ui.form textarea:focus { + background: #1a2632; + border: 1px solid #313c47; + color: #dbdbdb; +} + +.ui.form textarea:focus { + border: 1px solid #456580; +} + +.ui .info.segment.top { + background-color: #404552 !important; +} + +.repository .diff-file-box .code-diff-unified tbody tr.del-code td { + background-color: #3c2626 !important; + border-color: #634343 !important; +} + +.repository .diff-file-box .code-diff-unified tbody tr.add-code td { + background-color: rgb(40, 62, 45) !important; + border-color: #314a37 !important; +} + +.repository .diff-file-box .code-diff tbody tr .added-code { + background-color: #3a523a; +} + +.repository .diff-file-box .code-diff .lines-num { + border-right: 1px solid #2d2d2d; +} + +.repository .diff-file-box .file-body.file-code .lines-num { + color: #9e9e9e; + background: #2e323e; +} + +.repository .diff-file-box .code-diff tbody tr.tag-code td, .repository .diff-file-box .code-diff tbody tr td.tag-code { + border-color: #2d2d2d !important; +} + +.repository .diff-file-box .file-body.file-code .lines-num-old { + border-right: 1px solid #2d2d2d; +} + +.hljs-title, .hljs-section, .hljs-selector-id { + color: #986c88; +} + +.hljs-string, .hljs-doctag { + color: #949494; +} + +.repository .diff-file-box .code-diff tbody tr .removed-code { + background-color: #5f3737; +} + +.repository .diff-file-box .code-diff tbody tr.tag-code td, .repository .diff-file-box .code-diff tbody tr td.tag-code { + background-color: #292727 !important; +} + +.ui.vertical.menu .active.item { + background: #4B5162; +} + +.ui.vertical.menu .item { + background: #353945; +} + +.ui.vertical.menu .header.item { + background: #404552; +} + +.ui.vertical.menu { + background: #353945; + border: 1px solid #333640; +} + +.ui.repository.list .item:not(:first-child) { + border-top: 1px solid #4c505c; +} + +.ui .text.blue { + color: #87ab63 !important; +} + +.ui.selection.active.dropdown, .ui.selection.active.dropdown .menu { + border-color: #4e5361; + box-shadow: 0 2px 3px 0 rgba(34, 36, 38, .15); +} + +.ui.selection.active.dropdown:hover, .ui.selection.active.dropdown:hover .menu { + border-color: #4e5361; + box-shadow: 0 2px 3px 0 rgba(34, 36, 38, .15); +} + +.ui.selection.dropdown { + background: #404552; + border: 1px solid rgb(64, 69, 82); + color: #9e9e9e; +} + +.ui.menu .ui.dropdown .menu > .active.item { + color: #dbdbdb !important; +} + +.ui.tabular.menu { + border-bottom: 1px solid #313c47; +} + +.ui.card, .ui.cards > .card { + background: #353945; + box-shadow: 0 1px 3px 0 #4c505c, 0 0 0 1px #4c505c; +} + +.ui.card > .content > .header, .ui.cards > .card > .content > .header { + color: #dbdbdb; +} + +.ui.card > .extra a:not(.ui), .ui.cards > .card > .extra a:not(.ui) { + color: #87ab63; +} + +.ui .text.black { + color: #9e9e9e; +} + +.ui .text.black:hover { + color: #dbdbdb; +} + +.ui.secondary.segment { + background: #353945; +} + +.ui.secondary.pointing.menu .active.item { + border-color: #87ab63; + color: #dbdbdb; + background: #404552; +} + +.ui.user.list .item:not(:first-child) { + border-top: 1px solid #4c505c; +} + +.ui.secondary.pointing.menu .active.item:hover { + border-color: #af8b4c; + color: #dbdbdb; + background: #4b5162; +} + +.ui.secondary.pointing.menu .dropdown.item:hover, .ui.secondary.pointing.menu .link.item:hover, .ui.secondary.pointing.menu a.item:hover { + color: #dbdbdb; +} + +.ui.checkbox label, .ui.checkbox + label, .ui.form .field > label { + color: #9e9e9e; +} + +.ui.form .inline.field > label, .ui.form .inline.field > p, .ui.form .inline.fields .field > label, .ui.form .inline.fields .field > p, .ui.form .inline.fields > label { + color: #9e9e9e; +} + +.user.settings .email.list .item:not(:first-child) { + border-top: 1px solid #3f4451; +} + +.explore .navbar { + background-color: #2a2e3a !important; +} + +.ui.menu.new-menu { + background-color: #2a2e3a !important; + @media only screen and (max-width: 1200px) { + &:after { + background-image: linear-gradient(to right, rgba(42, 46, 42, 0), rgba(42, 46, 42, 1) 100%); + } + } +} + +input { + background: #2e323e; +} + +.ui.secondary.pointing.menu .active.item { + border: none; + background: #383c4a; +} + +.settings .key.list .item:not(:first-child) { + border-top: 1px solid #404552; +} + +.ui.form input:not([type]), .ui.form input[type=text], .ui.form input[type=email], .ui.form input[type=search], .ui.form input[type=password], .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=tel], .ui.form input[type=time], .ui.form input[type=url], .ui.form input[type=number] { + color: #9e9e9e; +} + +.ui.attached.info.message, .ui.info.message { + box-shadow: 0 0 0 1px #4b5e71 inset, 0 0 0 0 transparent; +} + +.ui.bottom.attached.message { + background-color: #2c662d; + color: #87ab63; +} + .ui.bottom.attached.message .pull-right { color: #87ab63; } - .ui.info.message { - background-color: #2c3b4a; - color: #9ebcc5; + +.ui.info.message { + background-color: #2c3b4a; + color: #9ebcc5; } - .CodeMirror div.CodeMirror-cursor { - border-left: 1px solid #9e9e9e; + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid #9e9e9e; } - .ui .warning.header { - background-color: #5d3a22 !important; - border-color: #794f31; + +.ui .warning.header { + background-color: #5d3a22 !important; + border-color: #794f31; } - .ui.red.message { - background-color: rgba(80, 23, 17, 0.6); - color: #f9cbcb; - box-shadow: 0 0 0 1px rgba(121, 71, 66, 0.5) inset, 0 0 0 0 transparent; + +.ui.red.message { + background-color: rgba(80, 23, 17, 0.6); + color: #f9cbcb; + box-shadow: 0 0 0 1px rgba(121, 71, 66, 0.5) inset, 0 0 0 0 transparent; } - .ui.red.button, .ui.red.buttons .button { - background-color: #7d3434; + +.ui.red.button, .ui.red.buttons .button { + background-color: #7d3434; } - .ui.red.button:hover, .ui.red.buttons .button:hover { - background-color: #984646; + +.ui.red.button:hover, .ui.red.buttons .button:hover { + background-color: #984646; } - .ui.checkbox label:hover, .ui.checkbox+label:hover { - color: #dbdbdb !important; + +.ui.checkbox label:hover, .ui.checkbox + label:hover { + color: #dbdbdb !important; } - .ui.checkbox input:checked~.box:after, .ui.checkbox input:checked~label:after { - color: rgb(127, 152, 173); + +.ui.checkbox input:checked ~ .box:after, .ui.checkbox input:checked ~ label:after { + color: rgb(127, 152, 173); } - .ui.checkbox input:checked~.box:before, .ui.checkbox input:checked~label:before { - background: #304251; + +.ui.checkbox input:checked ~ .box:before, .ui.checkbox input:checked ~ label:before { + background: #304251; } - .ui.checkbox .box:hover::before, .ui.checkbox label:hover::before { - background: #304251; + +.ui.checkbox .box:hover::before, .ui.checkbox label:hover::before { + background: #304251; } - .ui.checkbox .box:before, .ui.checkbox label:before { - background: #304251; - border: 1px solid #304251; + +.ui.checkbox .box:before, .ui.checkbox label:before { + background: #304251; + border: 1px solid #304251; } - .ui.checkbox .box:active::before, .ui.checkbox label:active::before { - background: #304251; - border-color: rgba(34,36,38,.35); + +.ui.checkbox .box:active::before, .ui.checkbox label:active::before { + background: #304251; + border-color: rgba(34, 36, 38, .35); } - .ui.checkbox input:checked~.box:before, .ui.checkbox input:checked~label:before { - border-color: #304251; - background: #304251; + +.ui.checkbox input:checked ~ .box:before, .ui.checkbox input:checked ~ label:before { + border-color: #304251; + background: #304251; } - .ui.checkbox input:focus~.box:before, .ui.checkbox input:focus~label:before { - border-color: #304251; - background: #304251; + +.ui.checkbox input:focus ~ .box:before, .ui.checkbox input:focus ~ label:before { + border-color: #304251; + background: #304251; } - .ui.checkbox input:checked:focus~.box:before, .ui.checkbox input:checked:focus~label:before, .ui.checkbox input:not([type=radio]):indeterminate:focus~.box:before, .ui.checkbox input:not([type=radio]):indeterminate:focus~label:before { - border-color: #304251; - background: #304251; + +.ui.checkbox input:checked:focus ~ .box:before, .ui.checkbox input:checked:focus ~ label:before, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ .box:before, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ label:before { + border-color: #304251; + background: #304251; } - .ui.checkbox input:checked~.box:after, .ui.checkbox input:checked~label:after { - opacity: 1; - color: rgb(127, 152, 173); + +.ui.checkbox input:checked ~ .box:after, .ui.checkbox input:checked ~ label:after { + opacity: 1; + color: rgb(127, 152, 173); } - .ui.checkbox input:checked:focus~.box:after, .ui.checkbox input:checked:focus~label:after, .ui.checkbox input:not([type=radio]):indeterminate:focus~.box:after, .ui.checkbox input:not([type=radio]):indeterminate:focus~label:after { - color: rgb(127, 152, 173); + +.ui.checkbox input:checked:focus ~ .box:after, .ui.checkbox input:checked:focus ~ label:after, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ .box:after, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ label:after { + color: rgb(127, 152, 173); } - .ui.checkbox input:focus~.box:after, .ui.checkbox input:focus~label, .ui.checkbox input:focus~label:after { - color: #9a9a9a; + +.ui.checkbox input:focus ~ .box:after, .ui.checkbox input:focus ~ label, .ui.checkbox input:focus ~ label:after { + color: #9a9a9a; } - .ui.selection.dropdown:hover { - border-color: rgba(34,36,38,.35); - border: 1px solid #456580; + +.ui.selection.dropdown:hover { + border: 1px solid #456580; } - .ui.selection.dropdown .menu>.item { - border-top: 1px solid #313c47; + +.ui.selection.dropdown .menu > .item { + border-top: 1px solid #313c47; } - .ui.selection.visible.dropdown>.text:not(.default) { - color: #9e9e9e; + +.ui.selection.visible.dropdown > .text:not(.default) { + color: #9e9e9e; } - .ui.negative.message { - background-color: rgba(80, 23, 17, 0.6); - color: #f9cbcb; - box-shadow: 0 0 0 1px rgba(121, 71, 66, 0.5) inset, 0 0 0 0 transparent; + +.ui.negative.message { + background-color: rgba(80, 23, 17, 0.6); + color: #f9cbcb; + box-shadow: 0 0 0 1px rgba(121, 71, 66, 0.5) inset, 0 0 0 0 transparent; } - .hljs-tag, .hljs-name, .hljs-attribute { - color: #ef5e77; + +.hljs-tag, .hljs-name, .hljs-attribute { + color: #ef5e77; } - .user.profile .ui.card .extra.content ul li:not(:last-child) { - border-bottom: 1px solid #4c505c; + +.user.profile .ui.card .extra.content ul li:not(:last-child) { + border-bottom: 1px solid #4c505c; } - .ui.form textarea, .ui.form textarea:focus { - background: #404552; - border: 2px solid #353945; + +.ui.form textarea, .ui.form textarea:focus { + background: #404552; + border: 2px solid #353945; } - .hljs-number, .hljs-literal, .hljs-variable, .hljs-template-variable, .hljs-tag .hljs-attr { - color: #bd84bf; + +.hljs-number, .hljs-literal, .hljs-variable, .hljs-template-variable, .hljs-tag .hljs-attr { + color: #bd84bf; } - .hljs-string, .hljs-doctag { - color: #8ab398; + +.hljs-string, .hljs-doctag { + color: #8ab398; } - .ui.form .dropzone { - border: 2px dashed #4c505c; + +.ui.form .dropzone { + border: 2px dashed #4c505c; } - .ui.basic.red.button, .ui.basic.red.buttons .button { - box-shadow: 0 0 0 1px #a04141 inset!important; - color: #a04141!important; + +.ui.basic.red.button, .ui.basic.red.buttons .button { + box-shadow: 0 0 0 1px #a04141 inset !important; + color: #a04141 !important; } - .ui.list .list>.item .header, .ui.list>.item .header { - color: #dedede; + +.ui.list .list > .item .header, .ui.list > .item .header { + color: #dedede; } - .ui.list .list>.item .description, .ui.list>.item .description { - color: #9e9e9e; + +.ui.list .list > .item .description, .ui.list > .item .description { + color: #9e9e9e; } - .ui.user.list .item .description a { - color: #668cb1; + +.ui.user.list .item .description a { + color: #668cb1; } - .repository.file.list #file-content .code-view .lines-num { - background: #2e323e; + +.repository.file.list #file-content .code-view .lines-num { + background: #2e323e; } - .repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, .repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { - color: #7c9b5e; + +.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, .repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { + color: #7c9b5e; } - .ui.blue.button:focus, .ui.blue.buttons .button:focus { - background-color: #87ab63; + +.ui.blue.button:focus, .ui.blue.buttons .button:focus { + background-color: #87ab63; } - .ui.basic.blue.button:hover, .ui.basic.blue.buttons .button:hover { - box-shadow: 0 0 0 1px #87ab63 inset!important; - color: #87ab63!important; + +.ui.basic.blue.button:hover, .ui.basic.blue.buttons .button:hover { + box-shadow: 0 0 0 1px #87ab63 inset !important; + color: #87ab63 !important; } - .ui.basic.blue.button:focus, .ui.basic.blue.buttons .button:focus { - box-shadow: 0 0 0 1px #87ab63 inset!important; - color: #87ab63!important; + +.ui.basic.blue.button:focus, .ui.basic.blue.buttons .button:focus { + box-shadow: 0 0 0 1px #87ab63 inset !important; + color: #87ab63 !important; } - .repository.file.list #file-content .code-view .lines-num pre, .repository.file.list #file-content .code-view .lines-code pre, .repository.file.list #file-content .code-view .lines-num ol, .repository.file.list #file-content .code-view .lines-code ol, .repository.file.list #file-content .code-view .lines-num .hljs, .repository.file.list #file-content .code-view .lines-code .hljs { - background-color: #2a2e3a; + +.repository.file.list #file-content .code-view .lines-num pre, .repository.file.list #file-content .code-view .lines-code pre, .repository.file.list #file-content .code-view .lines-num ol, .repository.file.list #file-content .code-view .lines-code ol, .repository.file.list #file-content .code-view .lines-num .hljs, .repository.file.list #file-content .code-view .lines-code .hljs { + background-color: #2a2e3a; } - a.ui.label:hover, a.ui.labels .label:hover { - background-color: #505667; - color: rgb(219, 219, 219); + +a.ui.label:hover, a.ui.labels .label:hover { + background-color: #505667; + color: rgb(219, 219, 219); } - .repository .label.list .item { - border-bottom: 1px dashed #4c505c; + +.repository .label.list .item { + border-bottom: 1px dashed #4c505c; } - .repository.file.list #file-content .code-view .lines-num { - background: #2e323e; + +.repository.file.list #file-content .code-view .lines-num { + background: #2e323e; } - .repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, .repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { - color: #7c9b5e; + +.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, .repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { + color: #7c9b5e; } - .ui.basic.blue.button, .ui.basic.blue.buttons .button { - box-shadow: 0 0 0 1px #a27558 inset !important; - color: #a27558 !important; + +.ui.basic.blue.button, .ui.basic.blue.buttons .button { + box-shadow: 0 0 0 1px #a27558 inset !important; + color: #a27558 !important; } - .repository.file.list #file-content .code-view .lines-num pre, .repository.file.list #file-content .code-view .lines-code pre, .repository.file.list #file-content .code-view .lines-num ol, .repository.file.list #file-content .code-view .lines-code ol, .repository.file.list #file-content .code-view .lines-num .hljs, .repository.file.list #file-content .code-view .lines-code .hljs { - background-color: #2a2e3a; + +.repository.file.list #file-content .code-view .lines-num pre, .repository.file.list #file-content .code-view .lines-code pre, .repository.file.list #file-content .code-view .lines-num ol, .repository.file.list #file-content .code-view .lines-code ol, .repository.file.list #file-content .code-view .lines-num .hljs, .repository.file.list #file-content .code-view .lines-code .hljs { + background-color: #2a2e3a; } - a.ui.label:hover, a.ui.labels .label:hover { - background-color: #505667; - color: rgb(219, 219, 219); + +a.ui.label:hover, a.ui.labels .label:hover { + background-color: #505667; + color: rgb(219, 219, 219); } - .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4) { - background-color: #2a2e3a; + +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4) { + background-color: #2a2e3a; } - .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4), .repository .diff-file-box .code-diff-split tbody tr td.add-code { - background-color: #283e2d !important; - border-color: #314a37 !important; + +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4), .repository .diff-file-box .code-diff-split tbody tr td.add-code { + background-color: #283e2d !important; + border-color: #314a37 !important; } - .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr td.del-code { - background-color: #3c2626 !important; - border-color: #634343 !important; + +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr td.del-code { + background-color: #3c2626 !important; + border-color: #634343 !important; } - .ui.blue.button:focus, .ui.blue.buttons .button:focus { - background-color: #a27558; + +.ui.blue.button:focus, .ui.blue.buttons .button:focus { + background-color: #a27558; } - .ui.blue.button:active, .ui.blue.buttons .button:active { - background-color: #a27558; + +.ui.blue.button:active, .ui.blue.buttons .button:active { + background-color: #a27558; } - #git-graph-container li a { - color: #c79575; + +#git-graph-container li a { + color: #c79575; } - #git-graph-container li .author { - color: #c79575; + +#git-graph-container li .author { + color: #c79575; } - .ui.header .sub.header { - color: #9e9e9e; + +.ui.header .sub.header { + color: #9e9e9e; } - .ui.dividing.header { - border-bottom: 1px solid #4c505c; + +.ui.dividing.header { + border-bottom: 1px solid #4c505c; } - .ui.modal>.header { - background: #404552; - color: #dbdbdb; + +.ui.modal > .header { + background: #404552; + color: #dbdbdb; } - .ui.modal>.actions { - background: #404552; - border-top: 1px solid #404552; + +.ui.modal > .actions { + background: #404552; + border-top: 1px solid #404552; } - .ui.modal>.content { - background: #383c4a; + +.ui.modal > .content { + background: #383c4a; } - .ui.basic.blue.button, .ui.basic.blue.buttons .button { - box-shadow: 0 0 0 1px #87ab63 inset!important; - color: #87ab63!important; + +.ui.basic.blue.button, .ui.basic.blue.buttons .button { + box-shadow: 0 0 0 1px #87ab63 inset !important; + color: #87ab63 !important; } - .editor-toolbar { - background-color: #404552; - a { - color: #87ab63 !important; - } + +.editor-toolbar { + background-color: #404552; + + a { + color: #87ab63 !important; + } } - .CodeMirror { - color: #9daccc; - background-color: #2b2b2b; - border-top: none; + +.CodeMirror { + color: #9daccc; + background-color: #2b2b2b; + border-top: none; } - .CodeMirror-gutters{ - background-color: #2b2b2b; + +.CodeMirror-gutters { + background-color: #2b2b2b; } .repository .diff-detail-box { background-color: #383c4a; + .detail-files { background-color: inherit; } @@ -801,6 +1029,7 @@ background: none transparent; border: none; } + .footer .markdown-info { color: inherit; } @@ -814,9 +1043,11 @@ .author { color: #dbdbdb; } + .metadata { color: #808084; } + .text { color: #9e9e9e; } From 34d06f4c6b23dfc458d51e9e3827c9400a87e84d Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Mon, 13 May 2019 08:38:53 -0700 Subject: [PATCH 004/220] Handle CORS requests (#6289) --- custom/conf/app.ini.sample | 17 + .../doc/advanced/config-cheat-sheet.en-us.md | 10 + go.mod | 13 +- go.sum | 20 +- integrations/cors_test.go | 22 + modules/setting/cors.go | 41 + modules/setting/setting.go | 1 + routers/api/v1/api.go | 21 +- vendor/github.com/Unknwon/com/dir.go | 53 +- vendor/github.com/Unknwon/com/go.mod | 8 + vendor/github.com/Unknwon/com/go.sum | 8 + vendor/github.com/Unknwon/com/html.go | 2 +- vendor/github.com/Unknwon/com/http.go | 2 +- vendor/github.com/Unknwon/com/math.go | 4 +- vendor/github.com/Unknwon/com/regex.go | 6 +- vendor/github.com/Unknwon/com/slice.go | 2 +- vendor/github.com/go-macaron/cors/.gitignore | 12 + vendor/github.com/go-macaron/cors/LICENSE | 201 +++++ vendor/github.com/go-macaron/cors/README.md | 2 + vendor/github.com/go-macaron/cors/cors.go | 139 ++++ vendor/github.com/go-macaron/cors/go.mod | 11 + vendor/github.com/go-macaron/cors/go.sum | 19 + vendor/golang.org/x/crypto/acme/acme.go | 43 +- .../x/crypto/acme/autocert/autocert.go | 2 +- vendor/golang.org/x/crypto/acme/jws.go | 29 +- vendor/golang.org/x/crypto/blowfish/cipher.go | 8 + vendor/golang.org/x/crypto/cast5/cast5.go | 11 +- .../x/crypto/curve25519/curve25519.go | 2 +- .../x/crypto/curve25519/ladderstep_amd64.s | 90 +-- .../x/crypto/curve25519/mul_amd64.s | 10 +- .../x/crypto/curve25519/square_amd64.s | 10 +- .../x/crypto/internal/chacha20/asm_arm64.s | 308 +++++++ .../crypto/internal/chacha20/chacha_arm64.go | 31 + .../crypto/internal/chacha20/chacha_noasm.go | 2 +- .../crypto/internal/chacha20/chacha_s390x.go | 11 +- .../x/crypto/internal/chacha20/chacha_s390x.s | 23 - vendor/golang.org/x/crypto/md4/md4.go | 4 + vendor/golang.org/x/crypto/openpgp/keys.go | 143 ++-- .../x/crypto/openpgp/packet/packet.go | 12 +- .../x/crypto/openpgp/packet/private_key.go | 9 +- .../x/crypto/openpgp/packet/signature.go | 2 +- .../x/crypto/openpgp/packet/userattribute.go | 2 +- vendor/golang.org/x/crypto/openpgp/write.go | 2 + .../golang.org/x/crypto/poly1305/mac_noasm.go | 11 + .../golang.org/x/crypto/poly1305/poly1305.go | 80 +- .../golang.org/x/crypto/poly1305/sum_amd64.go | 60 +- .../golang.org/x/crypto/poly1305/sum_amd64.s | 61 +- .../poly1305/{sum_ref.go => sum_generic.go} | 121 ++- .../golang.org/x/crypto/poly1305/sum_noasm.go | 4 +- .../golang.org/x/crypto/poly1305/sum_s390x.go | 17 +- .../golang.org/x/crypto/poly1305/sum_s390x.s | 22 - .../x/crypto/poly1305/sum_vmsl_s390x.s | 22 - .../golang.org/x/crypto/ssh/agent/client.go | 120 ++- .../golang.org/x/crypto/ssh/agent/keyring.go | 28 +- .../golang.org/x/crypto/ssh/agent/server.go | 49 +- vendor/golang.org/x/crypto/ssh/certs.go | 16 +- vendor/golang.org/x/crypto/ssh/cipher.go | 24 +- vendor/golang.org/x/crypto/ssh/client.go | 2 +- vendor/golang.org/x/crypto/ssh/common.go | 20 +- vendor/golang.org/x/crypto/ssh/handshake.go | 5 +- vendor/golang.org/x/crypto/ssh/keys.go | 89 ++- .../x/crypto/ssh/knownhosts/knownhosts.go | 4 +- vendor/golang.org/x/crypto/ssh/messages.go | 26 + vendor/golang.org/x/crypto/ssh/server.go | 3 +- vendor/golang.org/x/crypto/ssh/transport.go | 12 +- vendor/golang.org/x/sys/cpu/byteorder.go | 30 + vendor/golang.org/x/sys/cpu/cpu.go | 126 +++ vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go | 30 + vendor/golang.org/x/sys/cpu/cpu_arm.go | 9 + vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 21 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 16 + vendor/golang.org/x/sys/cpu/cpu_gccgo.c | 43 + vendor/golang.org/x/sys/cpu/cpu_gccgo.go | 26 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 22 + vendor/golang.org/x/sys/cpu/cpu_linux.go | 59 ++ .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 67 ++ .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 33 + .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 161 ++++ vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 11 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 11 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 11 + vendor/golang.org/x/sys/cpu/cpu_s390x.s | 57 ++ vendor/golang.org/x/sys/cpu/cpu_wasm.go | 15 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 59 ++ vendor/golang.org/x/sys/cpu/cpu_x86.s | 27 + vendor/golang.org/x/sys/unix/mkall.sh | 4 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 2 + vendor/golang.org/x/sys/unix/mksyscall.go | 7 +- vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 4 +- vendor/golang.org/x/sys/unix/syscall_aix.go | 2 + .../golang.org/x/sys/unix/syscall_darwin.go | 17 + vendor/golang.org/x/sys/unix/syscall_linux.go | 40 + .../x/sys/unix/syscall_linux_arm.go | 6 + .../x/sys/unix/syscall_linux_arm64.go | 13 + .../x/sys/unix/syscall_linux_riscv64.go | 13 + .../golang.org/x/sys/unix/syscall_openbsd.go | 17 + vendor/golang.org/x/sys/unix/syscall_unix.go | 48 ++ vendor/golang.org/x/sys/unix/types_darwin.go | 6 + vendor/golang.org/x/sys/unix/types_openbsd.go | 6 + .../x/sys/unix/zerrors_linux_386.go | 57 +- .../x/sys/unix/zerrors_linux_amd64.go | 57 +- .../x/sys/unix/zerrors_linux_arm.go | 57 +- .../x/sys/unix/zerrors_linux_arm64.go | 57 +- .../x/sys/unix/zerrors_linux_mips.go | 57 +- .../x/sys/unix/zerrors_linux_mips64.go | 57 +- .../x/sys/unix/zerrors_linux_mips64le.go | 57 +- .../x/sys/unix/zerrors_linux_mipsle.go | 57 +- .../x/sys/unix/zerrors_linux_ppc64.go | 57 +- .../x/sys/unix/zerrors_linux_ppc64le.go | 57 +- .../x/sys/unix/zerrors_linux_riscv64.go | 57 +- .../x/sys/unix/zerrors_linux_s390x.go | 57 +- .../x/sys/unix/zerrors_linux_sparc64.go | 57 +- .../x/sys/unix/zsyscall_aix_ppc64.go | 8 + .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 10 + .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 9 + .../x/sys/unix/zsyscall_linux_386.go | 21 + .../x/sys/unix/zsyscall_linux_amd64.go | 21 + .../x/sys/unix/zsyscall_linux_arm.go | 31 + .../x/sys/unix/zsyscall_linux_arm64.go | 36 + .../x/sys/unix/zsyscall_linux_mips.go | 21 + .../x/sys/unix/zsyscall_linux_mips64.go | 21 + .../x/sys/unix/zsyscall_linux_mips64le.go | 21 + .../x/sys/unix/zsyscall_linux_mipsle.go | 21 + .../x/sys/unix/zsyscall_linux_ppc64.go | 21 + .../x/sys/unix/zsyscall_linux_ppc64le.go | 21 + .../x/sys/unix/zsyscall_linux_riscv64.go | 36 + .../x/sys/unix/zsyscall_linux_s390x.go | 21 + .../x/sys/unix/zsyscall_linux_sparc64.go | 21 + .../x/sys/unix/zsysnum_linux_arm64.go | 1 + .../x/sys/unix/zsysnum_linux_riscv64.go | 1 + .../x/sys/unix/zsysnum_linux_sparc64.go | 1 + .../x/sys/unix/ztypes_darwin_386.go | 10 + .../x/sys/unix/ztypes_darwin_amd64.go | 10 + .../x/sys/unix/ztypes_darwin_arm.go | 10 + .../x/sys/unix/ztypes_darwin_arm64.go | 10 + .../golang.org/x/sys/unix/ztypes_linux_386.go | 70 +- .../x/sys/unix/ztypes_linux_amd64.go | 70 +- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 70 +- .../x/sys/unix/ztypes_linux_arm64.go | 70 +- .../x/sys/unix/ztypes_linux_mips.go | 70 +- .../x/sys/unix/ztypes_linux_mips64.go | 70 +- .../x/sys/unix/ztypes_linux_mips64le.go | 70 +- .../x/sys/unix/ztypes_linux_mipsle.go | 70 +- .../x/sys/unix/ztypes_linux_ppc64.go | 70 +- .../x/sys/unix/ztypes_linux_ppc64le.go | 70 +- .../x/sys/unix/ztypes_linux_riscv64.go | 70 +- .../x/sys/unix/ztypes_linux_s390x.go | 70 +- .../x/sys/unix/ztypes_linux_sparc64.go | 70 +- .../x/sys/unix/ztypes_openbsd_386.go | 10 + .../x/sys/unix/ztypes_openbsd_amd64.go | 10 + .../x/sys/unix/ztypes_openbsd_arm.go | 10 + .../golang.org/x/sys/windows/dll_windows.go | 8 +- .../x/sys/windows/security_windows.go | 171 ++++ .../golang.org/x/sys/windows/svc/service.go | 36 +- vendor/golang.org/x/sys/windows/svc/sys_386.s | 3 +- .../golang.org/x/sys/windows/svc/sys_amd64.s | 2 + .../x/sys/windows/syscall_windows.go | 1 + .../golang.org/x/sys/windows/types_windows.go | 16 +- .../x/sys/windows/zsyscall_windows.go | 46 ++ vendor/gopkg.in/ini.v1/.travis.yml | 6 +- vendor/gopkg.in/ini.v1/Makefile | 2 +- vendor/gopkg.in/ini.v1/README.md | 741 +---------------- vendor/gopkg.in/ini.v1/README_ZH.md | 750 ------------------ vendor/gopkg.in/ini.v1/file.go | 66 +- vendor/gopkg.in/ini.v1/ini.go | 34 +- vendor/gopkg.in/ini.v1/key.go | 45 +- vendor/gopkg.in/ini.v1/parser.go | 155 +++- vendor/gopkg.in/ini.v1/section.go | 2 + vendor/gopkg.in/ini.v1/struct.go | 2 +- vendor/modules.txt | 11 +- 170 files changed, 5220 insertions(+), 2124 deletions(-) create mode 100644 integrations/cors_test.go create mode 100644 modules/setting/cors.go create mode 100644 vendor/github.com/Unknwon/com/go.mod create mode 100644 vendor/github.com/Unknwon/com/go.sum create mode 100644 vendor/github.com/go-macaron/cors/.gitignore create mode 100644 vendor/github.com/go-macaron/cors/LICENSE create mode 100644 vendor/github.com/go-macaron/cors/README.md create mode 100644 vendor/github.com/go-macaron/cors/cors.go create mode 100644 vendor/github.com/go-macaron/cors/go.mod create mode 100644 vendor/github.com/go-macaron/cors/go.sum create mode 100644 vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s create mode 100644 vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go create mode 100644 vendor/golang.org/x/crypto/poly1305/mac_noasm.go rename vendor/golang.org/x/crypto/poly1305/{sum_ref.go => sum_generic.go} (54%) create mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo.c create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.s delete mode 100644 vendor/gopkg.in/ini.v1/README_ZH.md diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 6f7844962b..599569464c 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -74,6 +74,23 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ; List of reasons why a Pull Request or Issue can be locked LOCK_REASONS=Too heated,Off-topic,Resolved,Spam +[cors] +; More information about CORS can be found here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers +; enable cors headers (disabled by default) +ENABLED=false +; scheme of allowed requests +SCHEME=http +; list of requesting domains that are allowed +ALLOW_DOMAIN=* +; allow subdomains of headers listed above to request +ALLOW_SUBDOMAIN=false +; list of methods allowed to request +METHODS=GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS +; max time to cache response +MAX_AGE=10m +; allow request with credentials +ALLOW_CREDENTIALS=false + [ui] ; Number of repositories that are displayed on one explore page EXPLORE_PAGING_NUM = 20 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 87a92eb60d..6b209b97bb 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -76,6 +76,16 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `LOCK_REASONS`: **Too heated,Off-topic,Resolved,Spam**: A list of reasons why a Pull Request or Issue can be locked +## CORS (`cors`) + +- `ENABLED`: **false**: enable cors headers (disabled by default) +- `SCHEME`: **http**: scheme of allowed requests +- `ALLOW_DOMAIN`: **\***: list of requesting domains that are allowed +- `ALLOW_SUBDOMAIN`: **false**: allow subdomains of headers listed above to request +- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request +- `MAX_AGE`: **10m**: max time to cache response +- `ALLOW_CREDENTIALS`: **false**: allow request with credentials + ## UI (`ui`) - `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page. diff --git a/go.mod b/go.mod index 45f62e676b..d02765fb10 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 github.com/RoaringBitmap/roaring v0.4.7 // indirect github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca - github.com/Unknwon/com v0.0.0-20170819223952-7677a1d7c113 + github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 // indirect @@ -48,6 +48,7 @@ require ( github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab + github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 @@ -113,17 +114,17 @@ require ( github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 go.etcd.io/bbolt v1.3.2 // indirect - golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 + golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 - golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 + golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e golang.org/x/text v0.3.0 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect gopkg.in/editorconfig/editorconfig-core-go.v1 v1.2.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - gopkg.in/ini.v1 v1.31.1 + gopkg.in/ini.v1 v1.42.0 gopkg.in/ldap.v3 v3.0.2 gopkg.in/macaron.v1 v1.3.2 gopkg.in/redis.v2 v2.3.2 // indirect @@ -135,6 +136,6 @@ require ( ) replace ( - github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 - github.com/go-sql-driver/mysql v1.4.0 => github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f + github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 + github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f ) diff --git a/go.sum b/go.sum index df3c606eb4..6b0a59d5b5 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/RoaringBitmap/roaring v0.4.7 h1:eGUudvFzvF7Kxh7JjYvXfI1f7l22/2duFby7r github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca h1:xU8R31tsvj6TesCBog973+UgI3TXjh/LqN5clki6hcc= github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca/go.mod h1:IRSre9/SEhVuy972TVuJLyaPTS73+8Owhe0Y0l9NXHc= -github.com/Unknwon/com v0.0.0-20170819223952-7677a1d7c113 h1:YwXm6KwmrA5R5yJRhcnpqRUHmBXSKciHuWtK9zP5qKQ= -github.com/Unknwon/com v0.0.0-20170819223952-7677a1d7c113/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no= +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 h1:Mp8GNJ/tdTZIEdLdZfykEJaL3mTyEYrSzYNcdoQKpJk= github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966/go.mod h1:SFtfq0zFPsENI7DpE87QM2hcYu5QQ0fRdCgP+P1Hrqo= github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 h1:SSvHGK7iMpeypcHjI8UzNMz7zW/K8/dcgqk/82lCYP0= @@ -105,6 +105,8 @@ github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5 github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok= github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI= github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA= +github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8= +github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E= github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo= github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372/go.mod h1:oZGMxI7MBnicI0jJqJvH4qQzyrWKhtiKxLSJKHC+ydc= github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f h1:wDKrZFc9pYJlqFOf7EzGbFMrSFFtyHt3plr2uTdo8Rg= @@ -148,6 +150,8 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= @@ -178,6 +182,7 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7cCpiRVEIr1B5ccDxRpbPsWT5JU3if2Di5nE4= @@ -281,6 +286,9 @@ github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7 github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys= github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= @@ -316,6 +324,8 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -332,6 +342,8 @@ golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -353,8 +365,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= -gopkg.in/ini.v1 v1.31.1 h1:8EY/6KDwKM9Qg4vu1+01ZpsxClC/XV71R+nZ/TL7D4M= -gopkg.in/ini.v1 v1.31.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= diff --git a/integrations/cors_test.go b/integrations/cors_test.go new file mode 100644 index 0000000000..02b6b9dbfc --- /dev/null +++ b/integrations/cors_test.go @@ -0,0 +1,22 @@ +// Copyright 2019 The Gitea 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 integrations + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCORSNotSet(t *testing.T) { + prepareTestEnv(t) + req := NewRequestf(t, "GET", "/api/v1/version") + session := loginUser(t, "user2") + resp := session.MakeRequest(t, req, http.StatusOK) + assert.Equal(t, resp.Code, http.StatusOK) + corsHeader := resp.Header().Get("Access-Control-Allow-Origin") + assert.Equal(t, corsHeader, "", "Access-Control-Allow-Origin: generated header should match") // header not set +} diff --git a/modules/setting/cors.go b/modules/setting/cors.go new file mode 100644 index 0000000000..c1c3bfb813 --- /dev/null +++ b/modules/setting/cors.go @@ -0,0 +1,41 @@ +// Copyright 2019 The Gitea 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 setting + +import ( + "time" + + "code.gitea.io/gitea/modules/log" + + "github.com/go-macaron/cors" +) + +var ( + // CORSConfig defines CORS settings + CORSConfig cors.Options + // EnableCORS defines whether CORS settings is enabled or not + EnableCORS bool +) + +func newCORSService() { + sec := Cfg.Section("cors") + // Check cors setting. + EnableCORS = sec.Key("ENABLED").MustBool(false) + + maxAge := sec.Key("MAX_AGE").MustDuration(10 * time.Minute) + + CORSConfig = cors.Options{ + Scheme: sec.Key("SCHEME").String(), + AllowDomain: sec.Key("ALLOW_DOMAIN").String(), + AllowSubdomain: sec.Key("ALLOW_SUBDOMAIN").MustBool(), + Methods: sec.Key("METHODS").Strings(","), + MaxAgeSeconds: int(maxAge.Seconds()), + AllowCredentials: sec.Key("ALLOW_CREDENTIALS").MustBool(), + } + + if EnableCORS { + log.Info("CORS Service Enabled") + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 687f01bc29..d7f361c01e 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1006,6 +1006,7 @@ func NewServices() { NewLogServices(false) newCacheService() newSessionService() + newCORSService() newMailService() newRegisterMailService() newNotifyMailService() diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index dfe705f7a8..ae64e887ca 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -74,7 +74,8 @@ import ( "code.gitea.io/gitea/routers/api/v1/user" "github.com/go-macaron/binding" - "gopkg.in/macaron.v1" + "github.com/go-macaron/cors" + macaron "gopkg.in/macaron.v1" ) func sudo() macaron.Handler { @@ -500,6 +501,12 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/swagger", misc.Swagger) //Render V1 by default } + var handlers []macaron.Handler + if setting.EnableCORS { + handlers = append(handlers, cors.CORS(setting.CORSConfig)) + } + handlers = append(handlers, securityHeaders(), context.APIContexter(), sudo()) + m.Group("/v1", func() { // Miscellaneous if setting.API.EnableSwagger { @@ -841,5 +848,15 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/topics", func() { m.Get("/search", repo.TopicSearch) }) - }, context.APIContexter(), sudo()) + }, handlers...) +} + +func securityHeaders() macaron.Handler { + return func(ctx *macaron.Context) { + ctx.Resp.Before(func(w macaron.ResponseWriter) { + // CORB: https://www.chromium.org/Home/chromium-security/corb-for-developers + // http://stackoverflow.com/a/3146618/244009 + w.Header().Set("x-content-type-options", "nosniff") + }) + } } diff --git a/vendor/github.com/Unknwon/com/dir.go b/vendor/github.com/Unknwon/com/dir.go index c126d79da8..c16e9de333 100644 --- a/vendor/github.com/Unknwon/com/dir.go +++ b/vendor/github.com/Unknwon/com/dir.go @@ -32,7 +32,7 @@ func IsDir(dir string) bool { return f.IsDir() } -func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, error) { +func statDir(dirPath, recPath string, includeDir, isDirOnly, followSymlinks bool) ([]string, error) { dir, err := os.Open(dirPath) if err != nil { return nil, err @@ -56,13 +56,29 @@ func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, err if includeDir { statList = append(statList, relPath+"/") } - s, err := statDir(curPath, relPath, includeDir, isDirOnly) + s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks) if err != nil { return nil, err } statList = append(statList, s...) } else if !isDirOnly { statList = append(statList, relPath) + } else if followSymlinks && fi.Mode()&os.ModeSymlink != 0 { + link, err := os.Readlink(curPath) + if err != nil { + return nil, err + } + + if IsDir(link) { + if includeDir { + statList = append(statList, relPath+"/") + } + s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks) + if err != nil { + return nil, err + } + statList = append(statList, s...) + } } } return statList, nil @@ -84,7 +100,26 @@ func StatDir(rootPath string, includeDir ...bool) ([]string, error) { if len(includeDir) >= 1 { isIncludeDir = includeDir[0] } - return statDir(rootPath, "", isIncludeDir, false) + return statDir(rootPath, "", isIncludeDir, false, false) +} + +// LstatDir gathers information of given directory by depth-first. +// It returns slice of file list, follows symbolic links and includes subdirectories if enabled; +// it returns error and nil slice when error occurs in underlying functions, +// or given path is not a directory or does not exist. +// +// Slice does not include given path itself. +// If subdirectories is enabled, they will have suffix '/'. +func LstatDir(rootPath string, includeDir ...bool) ([]string, error) { + if !IsDir(rootPath) { + return nil, errors.New("not a directory or does not exist: " + rootPath) + } + + isIncludeDir := false + if len(includeDir) >= 1 { + isIncludeDir = includeDir[0] + } + return statDir(rootPath, "", isIncludeDir, false, true) } // GetAllSubDirs returns all subdirectories of given root path. @@ -93,7 +128,17 @@ func GetAllSubDirs(rootPath string) ([]string, error) { if !IsDir(rootPath) { return nil, errors.New("not a directory or does not exist: " + rootPath) } - return statDir(rootPath, "", true, true) + return statDir(rootPath, "", true, true, false) +} + +// LgetAllSubDirs returns all subdirectories of given root path, including +// following symbolic links, if any. +// Slice does not include given path itself. +func LgetAllSubDirs(rootPath string) ([]string, error) { + if !IsDir(rootPath) { + return nil, errors.New("not a directory or does not exist: " + rootPath) + } + return statDir(rootPath, "", true, true, true) } // GetFileListBySuffix returns an ordered list of file paths. diff --git a/vendor/github.com/Unknwon/com/go.mod b/vendor/github.com/Unknwon/com/go.mod new file mode 100644 index 0000000000..0bb87b46af --- /dev/null +++ b/vendor/github.com/Unknwon/com/go.mod @@ -0,0 +1,8 @@ +module github.com/Unknwon/com + +require ( + github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect + github.com/jtolds/gls v4.2.1+incompatible // indirect + github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect + github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c +) diff --git a/vendor/github.com/Unknwon/com/go.sum b/vendor/github.com/Unknwon/com/go.sum new file mode 100644 index 0000000000..3fcc30358b --- /dev/null +++ b/vendor/github.com/Unknwon/com/go.sum @@ -0,0 +1,8 @@ +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= diff --git a/vendor/github.com/Unknwon/com/html.go b/vendor/github.com/Unknwon/com/html.go index 762d94b050..8a99df4e08 100644 --- a/vendor/github.com/Unknwon/com/html.go +++ b/vendor/github.com/Unknwon/com/html.go @@ -36,7 +36,7 @@ func HtmlEncode(str string) string { return html.EscapeString(str) } -// decode string to html chars +// HtmlDecode decodes string to html chars func HtmlDecode(str string) string { return html.UnescapeString(str) } diff --git a/vendor/github.com/Unknwon/com/http.go b/vendor/github.com/Unknwon/com/http.go index 3415059ae9..cf0820f378 100644 --- a/vendor/github.com/Unknwon/com/http.go +++ b/vendor/github.com/Unknwon/com/http.go @@ -177,7 +177,7 @@ func FetchFiles(client *http.Client, files []RawFile, header http.Header) error return nil } -// FetchFiles uses command `curl` to fetch files specified by the rawURL field in parallel. +// FetchFilesCurl uses command `curl` to fetch files specified by the rawURL field in parallel. func FetchFilesCurl(files []RawFile, curlOptions ...string) error { ch := make(chan error, len(files)) for i := range files { diff --git a/vendor/github.com/Unknwon/com/math.go b/vendor/github.com/Unknwon/com/math.go index 99c56b6594..62b77e87c8 100644 --- a/vendor/github.com/Unknwon/com/math.go +++ b/vendor/github.com/Unknwon/com/math.go @@ -14,12 +14,12 @@ package com -// PowInt is int type of math.Pow function. +// PowInt is int type of math.Pow function. func PowInt(x int, y int) int { if y <= 0 { return 1 } else { - if y % 2 == 0 { + if y%2 == 0 { sqrt := PowInt(x, y/2) return sqrt * sqrt } else { diff --git a/vendor/github.com/Unknwon/com/regex.go b/vendor/github.com/Unknwon/com/regex.go index 765bfc4311..14926474e0 100644 --- a/vendor/github.com/Unknwon/com/regex.go +++ b/vendor/github.com/Unknwon/com/regex.go @@ -37,19 +37,19 @@ func init() { regex_url = regexp.MustCompile(regex_url_pattern) } -// validate string is an email address, if not return false +// IsEmail validates string is an email address, if not return false // basically validation can match 99% cases func IsEmail(email string) bool { return regex_email.MatchString(email) } -// validate string is an email address, if not return false +// IsEmailRFC validates string is an email address, if not return false // this validation omits RFC 2822 func IsEmailRFC(email string) bool { return regex_strict_email.MatchString(email) } -// validate string is a url link, if not return false +// IsUrl validates string is a url link, if not return false // simple validation can match 99% cases func IsUrl(url string) bool { return regex_url.MatchString(url) diff --git a/vendor/github.com/Unknwon/com/slice.go b/vendor/github.com/Unknwon/com/slice.go index 27801a4d7d..c3c9ab2e72 100644 --- a/vendor/github.com/Unknwon/com/slice.go +++ b/vendor/github.com/Unknwon/com/slice.go @@ -44,7 +44,7 @@ func CompareSliceStr(s1, s2 []string) bool { return true } -// CompareSliceStr compares two 'string' type slices. +// CompareSliceStrU compares two 'string' type slices. // It returns true if elements are the same, and ignores the order. func CompareSliceStrU(s1, s2 []string) bool { if len(s1) != len(s2) { diff --git a/vendor/github.com/go-macaron/cors/.gitignore b/vendor/github.com/go-macaron/cors/.gitignore new file mode 100644 index 0000000000..f1c181ec9c --- /dev/null +++ b/vendor/github.com/go-macaron/cors/.gitignore @@ -0,0 +1,12 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/vendor/github.com/go-macaron/cors/LICENSE b/vendor/github.com/go-macaron/cors/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/go-macaron/cors/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/go-macaron/cors/README.md b/vendor/github.com/go-macaron/cors/README.md new file mode 100644 index 0000000000..be1cdca1a9 --- /dev/null +++ b/vendor/github.com/go-macaron/cors/README.md @@ -0,0 +1,2 @@ +# cors +Package cors is a middleware that handles CORS requests & headers for Macaron. diff --git a/vendor/github.com/go-macaron/cors/cors.go b/vendor/github.com/go-macaron/cors/cors.go new file mode 100644 index 0000000000..b0cec3ddd8 --- /dev/null +++ b/vendor/github.com/go-macaron/cors/cors.go @@ -0,0 +1,139 @@ +package cors + +import ( + "fmt" + "log" + "net/http" + "net/url" + "strconv" + "strings" + + macaron "gopkg.in/macaron.v1" +) + +const _VERSION = "0.1.0" + +func Version() string { + return _VERSION +} + +// Options represents a struct for specifying configuration options for the CORS middleware. +type Options struct { + Section string + Scheme string + AllowDomain string + AllowSubdomain bool + Methods []string + MaxAgeSeconds int + AllowCredentials bool +} + +func prepareOptions(options []Options) Options { + var opt Options + if len(options) > 0 { + opt = options[0] + } + + if len(opt.Section) == 0 { + opt.Section = "cors" + } + sec := macaron.Config().Section(opt.Section) + + if len(opt.Scheme) == 0 { + opt.Scheme = sec.Key("SCHEME").MustString("http") + } + if len(opt.AllowDomain) == 0 { + opt.AllowDomain = sec.Key("ALLOW_DOMAIN").MustString("*") + } + if !opt.AllowSubdomain { + opt.AllowSubdomain = sec.Key("ALLOW_SUBDOMAIN").MustBool(false) + } + if len(opt.Methods) == 0 { + opt.Methods = sec.Key("METHODS").Strings(",") + if len(opt.Methods) == 0 { + opt.Methods = []string{ + http.MethodGet, + http.MethodHead, + http.MethodPost, + http.MethodPut, + http.MethodPatch, + http.MethodDelete, + http.MethodOptions, + } + } + } + if opt.MaxAgeSeconds <= 0 { + // cache options response for 600 secs + // ref: https://stackoverflow.com/questions/54300997/is-it-possible-to-cache-http-options-response?noredirect=1#comment95790277_54300997 + // ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age + opt.MaxAgeSeconds = sec.Key("MAX_AGE_SECONDS").MustInt(600) + } + if !opt.AllowCredentials { + opt.AllowCredentials = sec.Key("ALLOW_CREDENTIALS").MustBool(true) + } + + return opt +} + +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin +// https://fetch.spec.whatwg.org/#cors-protocol-and-credentials +// For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource. +func CORS(options ...Options) macaron.Handler { + opt := prepareOptions(options) + return func(ctx *macaron.Context, log *log.Logger) { + reqOptions := ctx.Req.Method == http.MethodOptions + + headers := map[string]string{ + "access-control-allow-methods": strings.Join(opt.Methods, ","), + "access-control-allow-headers": ctx.Req.Header.Get("access-control-request-headers"), + "access-control-max-age": strconv.Itoa(opt.MaxAgeSeconds), + } + if opt.AllowDomain == "*" { + headers["access-control-allow-origin"] = "*" + } else if opt.AllowDomain != "" { + origin := ctx.Req.Header.Get("Origin") + if reqOptions && origin == "" { + respErrorf(ctx, log, http.StatusBadRequest, "missing origin header in CORS request") + return + } + + u, err := url.Parse(origin) + if err != nil { + respErrorf(ctx, log, http.StatusBadRequest, "Failed to parse CORS origin header. Reason: %v", err) + return + } + + ok := u.Hostname() == opt.AllowDomain || + (opt.AllowSubdomain && strings.HasSuffix(u.Hostname(), "."+opt.AllowDomain)) + if ok { + u.Scheme = opt.Scheme + headers["access-control-allow-origin"] = u.String() + headers["access-control-allow-credentials"] = strconv.FormatBool(opt.AllowCredentials) + headers["vary"] = "Origin" + } + if reqOptions && !ok { + respErrorf(ctx, log, http.StatusBadRequest, "CORS request from prohibited domain %v", origin) + return + } + } + ctx.Resp.Before(func(w macaron.ResponseWriter) { + for k, v := range headers { + w.Header().Set(k, v) + } + }) + if reqOptions { + ctx.Status(200) // return response + } + } +} + +func respErrorf(ctx *macaron.Context, log *log.Logger, statusCode int, format string, a ...interface{}) { + msg := fmt.Sprintf(format, a...) + log.Println(msg) + ctx.WriteHeader(statusCode) + _, err := ctx.Write([]byte(msg)) + if err != nil { + panic(err) + } + return +} diff --git a/vendor/github.com/go-macaron/cors/go.mod b/vendor/github.com/go-macaron/cors/go.mod new file mode 100644 index 0000000000..6e03401924 --- /dev/null +++ b/vendor/github.com/go-macaron/cors/go.mod @@ -0,0 +1,11 @@ +module github.com/go-macaron/cors + +go 1.12 + +require ( + github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 // indirect + github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect + golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 // indirect + gopkg.in/ini.v1 v1.42.0 // indirect + gopkg.in/macaron.v1 v1.3.2 +) diff --git a/vendor/github.com/go-macaron/cors/go.sum b/vendor/github.com/go-macaron/cors/go.sum new file mode 100644 index 0000000000..782d98c540 --- /dev/null +++ b/vendor/github.com/go-macaron/cors/go.sum @@ -0,0 +1,19 @@ +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= +gopkg.in/macaron.v1 v1.3.2/go.mod h1:PrsiawTWAGZs6wFbT5hlr7SQ2Ns9h7cUVtcUu4lQOVo= diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go index 7df6476412..00ee955503 100644 --- a/vendor/golang.org/x/crypto/acme/acme.go +++ b/vendor/golang.org/x/crypto/acme/acme.go @@ -77,6 +77,10 @@ const ( type Client struct { // Key is the account key used to register with a CA and sign requests. // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey. + // + // The following algorithms are supported: + // RS256, ES256, ES384 and ES512. + // See RFC7518 for more details about the algorithms. Key crypto.Signer // HTTPClient optionally specifies an HTTP client to use @@ -124,11 +128,7 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { return *c.dir, nil } - dirURL := c.DirectoryURL - if dirURL == "" { - dirURL = LetsEncryptURL - } - res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK)) + res, err := c.get(ctx, c.directoryURL(), wantStatus(http.StatusOK)) if err != nil { return Directory{}, err } @@ -161,6 +161,13 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { return *c.dir, nil } +func (c *Client) directoryURL() string { + if c.DirectoryURL != "" { + return c.DirectoryURL + } + return LetsEncryptURL +} + // CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format. // The exp argument indicates the desired certificate validity duration. CA may issue a certificate // with a different duration. @@ -319,6 +326,20 @@ func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { // a valid authorization (Authorization.Status is StatusValid). If so, the caller // need not fulfill any challenge and can proceed to requesting a certificate. func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { + return c.authorize(ctx, "dns", domain) +} + +// AuthorizeIP is the same as Authorize but requests IP address authorization. +// Clients which successfully obtain such authorization may request to issue +// a certificate for IP addresses. +// +// See the ACME spec extension for more details about IP address identifiers: +// https://tools.ietf.org/html/draft-ietf-acme-ip. +func (c *Client) AuthorizeIP(ctx context.Context, ipaddr string) (*Authorization, error) { + return c.authorize(ctx, "ip", ipaddr) +} + +func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization, error) { if _, err := c.Discover(ctx); err != nil { return nil, err } @@ -332,7 +353,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, Identifier authzID `json:"identifier"` }{ Resource: "new-authz", - Identifier: authzID{Type: "dns", Value: domain}, + Identifier: authzID{Type: typ, Value: val}, } res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) if err != nil { @@ -693,12 +714,18 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun } // popNonce returns a nonce value previously stored with c.addNonce -// or fetches a fresh one from the given URL. +// or fetches a fresh one from a URL by issuing a HEAD request. +// It first tries c.directoryURL() and then the provided url if the former fails. func (c *Client) popNonce(ctx context.Context, url string) (string, error) { c.noncesMu.Lock() defer c.noncesMu.Unlock() if len(c.nonces) == 0 { - return c.fetchNonce(ctx, url) + dirURL := c.directoryURL() + v, err := c.fetchNonce(ctx, dirURL) + if err != nil && url != dirURL { + v, err = c.fetchNonce(ctx, url) + } + return v, err } var nonce string for nonce = range c.nonces { diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go index 4c2fc07226..a50d9bfc95 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go @@ -69,7 +69,7 @@ func HostWhitelist(hosts ...string) HostPolicy { } return func(_ context.Context, host string) error { if !whitelist[host] { - return errors.New("acme/autocert: host not configured") + return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host) } return nil } diff --git a/vendor/golang.org/x/crypto/acme/jws.go b/vendor/golang.org/x/crypto/acme/jws.go index 6cbca25de9..1093b50390 100644 --- a/vendor/golang.org/x/crypto/acme/jws.go +++ b/vendor/golang.org/x/crypto/acme/jws.go @@ -25,7 +25,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byt if err != nil { return nil, err } - alg, sha := jwsHasher(key) + alg, sha := jwsHasher(key.Public()) if alg == "" || !sha.Available() { return nil, ErrUnsupportedKey } @@ -97,13 +97,16 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { } // jwsSign signs the digest using the given key. -// It returns ErrUnsupportedKey if the key type is unknown. -// The hash is used only for RSA keys. +// The hash is unused for ECDSA keys. +// +// Note: non-stdlib crypto.Signer implementations are expected to return +// the signature in the format as specified in RFC7518. +// See https://tools.ietf.org/html/rfc7518 for more details. func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { - switch key := key.(type) { - case *rsa.PrivateKey: - return key.Sign(rand.Reader, digest, hash) - case *ecdsa.PrivateKey: + if key, ok := key.(*ecdsa.PrivateKey); ok { + // The key.Sign method of ecdsa returns ASN1-encoded signature. + // So, we use the package Sign function instead + // to get R and S values directly and format the result accordingly. r, s, err := ecdsa.Sign(rand.Reader, key, digest) if err != nil { return nil, err @@ -118,18 +121,18 @@ func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) copy(sig[size*2-len(sb):], sb) return sig, nil } - return nil, ErrUnsupportedKey + return key.Sign(rand.Reader, digest, hash) } // jwsHasher indicates suitable JWS algorithm name and a hash function // to use for signing a digest with the provided key. // It returns ("", 0) if the key is not supported. -func jwsHasher(key crypto.Signer) (string, crypto.Hash) { - switch key := key.(type) { - case *rsa.PrivateKey: +func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) { + switch pub := pub.(type) { + case *rsa.PublicKey: return "RS256", crypto.SHA256 - case *ecdsa.PrivateKey: - switch key.Params().Name { + case *ecdsa.PublicKey: + switch pub.Params().Name { case "P-256": return "ES256", crypto.SHA256 case "P-384": diff --git a/vendor/golang.org/x/crypto/blowfish/cipher.go b/vendor/golang.org/x/crypto/blowfish/cipher.go index 2641dadd64..213bf204af 100644 --- a/vendor/golang.org/x/crypto/blowfish/cipher.go +++ b/vendor/golang.org/x/crypto/blowfish/cipher.go @@ -3,6 +3,14 @@ // license that can be found in the LICENSE file. // Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. +// +// Blowfish is a legacy cipher and its short block size makes it vulnerable to +// birthday bound attacks (see https://sweet32.info). It should only be used +// where compatibility with legacy systems, not security, is the goal. +// +// Deprecated: any new system should use AES (from crypto/aes, if necessary in +// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from +// golang.org/x/crypto/chacha20poly1305). package blowfish // import "golang.org/x/crypto/blowfish" // The code is a port of Bruce Schneier's C implementation. diff --git a/vendor/golang.org/x/crypto/cast5/cast5.go b/vendor/golang.org/x/crypto/cast5/cast5.go index 0b4af37bdc..ddcbeb6f2a 100644 --- a/vendor/golang.org/x/crypto/cast5/cast5.go +++ b/vendor/golang.org/x/crypto/cast5/cast5.go @@ -2,8 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common -// OpenPGP cipher. +// Package cast5 implements CAST5, as defined in RFC 2144. +// +// CAST5 is a legacy cipher and its short block size makes it vulnerable to +// birthday bound attacks (see https://sweet32.info). It should only be used +// where compatibility with legacy systems, not security, is the goal. +// +// Deprecated: any new system should use AES (from crypto/aes, if necessary in +// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from +// golang.org/x/crypto/chacha20poly1305). package cast5 // import "golang.org/x/crypto/cast5" import "errors" diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go index cb8fbc57b9..75f24babb6 100644 --- a/vendor/golang.org/x/crypto/curve25519/curve25519.go +++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go @@ -86,7 +86,7 @@ func feFromBytes(dst *fieldElement, src *[32]byte) { h6 := load3(src[20:]) << 7 h7 := load3(src[23:]) << 5 h8 := load3(src[26:]) << 4 - h9 := load3(src[29:]) << 2 + h9 := (load3(src[29:]) & 0x7fffff) << 2 var carry [10]int64 carry[9] = (h9 + 1<<24) >> 25 diff --git a/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s b/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s index 9e9040b250..e0ac30c70f 100644 --- a/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s +++ b/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s @@ -121,18 +121,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -236,18 +236,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -441,18 +441,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -591,18 +591,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -731,18 +731,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -846,18 +846,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -996,18 +996,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -1146,18 +1146,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX @@ -1332,18 +1332,18 @@ TEXT ·ladderstep(SB),0,$296-8 ADDQ AX,R12 ADCQ DX,R13 MOVQ $REDMASK51,DX - SHLQ $13,CX:SI + SHLQ $13,SI,CX ANDQ DX,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ DX,R8 ADDQ CX,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ DX,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ DX,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ DX,R14 ADDQ R13,R14 IMUL3Q $19,R15,CX diff --git a/vendor/golang.org/x/crypto/curve25519/mul_amd64.s b/vendor/golang.org/x/crypto/curve25519/mul_amd64.s index 5ce80a2e56..1f76d1a3f5 100644 --- a/vendor/golang.org/x/crypto/curve25519/mul_amd64.s +++ b/vendor/golang.org/x/crypto/curve25519/mul_amd64.s @@ -124,18 +124,18 @@ TEXT ·mul(SB),0,$16-24 ADDQ AX,R14 ADCQ DX,R15 MOVQ $REDMASK51,SI - SHLQ $13,R9:R8 + SHLQ $13,R8,R9 ANDQ SI,R8 - SHLQ $13,R11:R10 + SHLQ $13,R10,R11 ANDQ SI,R10 ADDQ R9,R10 - SHLQ $13,R13:R12 + SHLQ $13,R12,R13 ANDQ SI,R12 ADDQ R11,R12 - SHLQ $13,R15:R14 + SHLQ $13,R14,R15 ANDQ SI,R14 ADDQ R13,R14 - SHLQ $13,BP:BX + SHLQ $13,BX,BP ANDQ SI,BX ADDQ R15,BX IMUL3Q $19,BP,DX diff --git a/vendor/golang.org/x/crypto/curve25519/square_amd64.s b/vendor/golang.org/x/crypto/curve25519/square_amd64.s index 12f73734ff..07511a45af 100644 --- a/vendor/golang.org/x/crypto/curve25519/square_amd64.s +++ b/vendor/golang.org/x/crypto/curve25519/square_amd64.s @@ -87,18 +87,18 @@ TEXT ·square(SB),7,$0-16 ADDQ AX,R13 ADCQ DX,R14 MOVQ $REDMASK51,SI - SHLQ $13,R8:CX + SHLQ $13,CX,R8 ANDQ SI,CX - SHLQ $13,R10:R9 + SHLQ $13,R9,R10 ANDQ SI,R9 ADDQ R8,R9 - SHLQ $13,R12:R11 + SHLQ $13,R11,R12 ANDQ SI,R11 ADDQ R10,R11 - SHLQ $13,R14:R13 + SHLQ $13,R13,R14 ANDQ SI,R13 ADDQ R12,R13 - SHLQ $13,BX:R15 + SHLQ $13,R15,BX ANDQ SI,R15 ADDQ R14,R15 IMUL3Q $19,BX,DX diff --git a/vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s b/vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s new file mode 100644 index 0000000000..b3a16ef751 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s @@ -0,0 +1,308 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.11 +// +build !gccgo,!appengine + +#include "textflag.h" + +#define NUM_ROUNDS 10 + +// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) +TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 + MOVD dst+0(FP), R1 + MOVD src+24(FP), R2 + MOVD src_len+32(FP), R3 + MOVD key+48(FP), R4 + MOVD nonce+56(FP), R6 + MOVD counter+64(FP), R7 + + MOVD $·constants(SB), R10 + MOVD $·incRotMatrix(SB), R11 + + MOVW (R7), R20 + + AND $~255, R3, R13 + ADD R2, R13, R12 // R12 for block end + AND $255, R3, R13 +loop: + MOVD $NUM_ROUNDS, R21 + VLD1 (R11), [V30.S4, V31.S4] + + // load contants + // VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4] + WORD $0x4D60E940 + + // load keys + // VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4] + WORD $0x4DFFE884 + // VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4] + WORD $0x4DFFE888 + SUB $32, R4 + + // load counter + nonce + // VLD1R (R7), [V12.S4] + WORD $0x4D40C8EC + + // VLD3R (R6), [V13.S4, V14.S4, V15.S4] + WORD $0x4D40E8CD + + // update counter + VADD V30.S4, V12.S4, V12.S4 + +chacha: + // V0..V3 += V4..V7 + // V12..V15 <<<= ((V12..V15 XOR V0..V3), 16) + VADD V0.S4, V4.S4, V0.S4 + VADD V1.S4, V5.S4, V1.S4 + VADD V2.S4, V6.S4, V2.S4 + VADD V3.S4, V7.S4, V3.S4 + VEOR V12.B16, V0.B16, V12.B16 + VEOR V13.B16, V1.B16, V13.B16 + VEOR V14.B16, V2.B16, V14.B16 + VEOR V15.B16, V3.B16, V15.B16 + VREV32 V12.H8, V12.H8 + VREV32 V13.H8, V13.H8 + VREV32 V14.H8, V14.H8 + VREV32 V15.H8, V15.H8 + // V8..V11 += V12..V15 + // V4..V7 <<<= ((V4..V7 XOR V8..V11), 12) + VADD V8.S4, V12.S4, V8.S4 + VADD V9.S4, V13.S4, V9.S4 + VADD V10.S4, V14.S4, V10.S4 + VADD V11.S4, V15.S4, V11.S4 + VEOR V8.B16, V4.B16, V16.B16 + VEOR V9.B16, V5.B16, V17.B16 + VEOR V10.B16, V6.B16, V18.B16 + VEOR V11.B16, V7.B16, V19.B16 + VSHL $12, V16.S4, V4.S4 + VSHL $12, V17.S4, V5.S4 + VSHL $12, V18.S4, V6.S4 + VSHL $12, V19.S4, V7.S4 + VSRI $20, V16.S4, V4.S4 + VSRI $20, V17.S4, V5.S4 + VSRI $20, V18.S4, V6.S4 + VSRI $20, V19.S4, V7.S4 + + // V0..V3 += V4..V7 + // V12..V15 <<<= ((V12..V15 XOR V0..V3), 8) + VADD V0.S4, V4.S4, V0.S4 + VADD V1.S4, V5.S4, V1.S4 + VADD V2.S4, V6.S4, V2.S4 + VADD V3.S4, V7.S4, V3.S4 + VEOR V12.B16, V0.B16, V12.B16 + VEOR V13.B16, V1.B16, V13.B16 + VEOR V14.B16, V2.B16, V14.B16 + VEOR V15.B16, V3.B16, V15.B16 + VTBL V31.B16, [V12.B16], V12.B16 + VTBL V31.B16, [V13.B16], V13.B16 + VTBL V31.B16, [V14.B16], V14.B16 + VTBL V31.B16, [V15.B16], V15.B16 + + // V8..V11 += V12..V15 + // V4..V7 <<<= ((V4..V7 XOR V8..V11), 7) + VADD V12.S4, V8.S4, V8.S4 + VADD V13.S4, V9.S4, V9.S4 + VADD V14.S4, V10.S4, V10.S4 + VADD V15.S4, V11.S4, V11.S4 + VEOR V8.B16, V4.B16, V16.B16 + VEOR V9.B16, V5.B16, V17.B16 + VEOR V10.B16, V6.B16, V18.B16 + VEOR V11.B16, V7.B16, V19.B16 + VSHL $7, V16.S4, V4.S4 + VSHL $7, V17.S4, V5.S4 + VSHL $7, V18.S4, V6.S4 + VSHL $7, V19.S4, V7.S4 + VSRI $25, V16.S4, V4.S4 + VSRI $25, V17.S4, V5.S4 + VSRI $25, V18.S4, V6.S4 + VSRI $25, V19.S4, V7.S4 + + // V0..V3 += V5..V7, V4 + // V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16) + VADD V0.S4, V5.S4, V0.S4 + VADD V1.S4, V6.S4, V1.S4 + VADD V2.S4, V7.S4, V2.S4 + VADD V3.S4, V4.S4, V3.S4 + VEOR V15.B16, V0.B16, V15.B16 + VEOR V12.B16, V1.B16, V12.B16 + VEOR V13.B16, V2.B16, V13.B16 + VEOR V14.B16, V3.B16, V14.B16 + VREV32 V12.H8, V12.H8 + VREV32 V13.H8, V13.H8 + VREV32 V14.H8, V14.H8 + VREV32 V15.H8, V15.H8 + + // V10 += V15; V5 <<<= ((V10 XOR V5), 12) + // ... + VADD V15.S4, V10.S4, V10.S4 + VADD V12.S4, V11.S4, V11.S4 + VADD V13.S4, V8.S4, V8.S4 + VADD V14.S4, V9.S4, V9.S4 + VEOR V10.B16, V5.B16, V16.B16 + VEOR V11.B16, V6.B16, V17.B16 + VEOR V8.B16, V7.B16, V18.B16 + VEOR V9.B16, V4.B16, V19.B16 + VSHL $12, V16.S4, V5.S4 + VSHL $12, V17.S4, V6.S4 + VSHL $12, V18.S4, V7.S4 + VSHL $12, V19.S4, V4.S4 + VSRI $20, V16.S4, V5.S4 + VSRI $20, V17.S4, V6.S4 + VSRI $20, V18.S4, V7.S4 + VSRI $20, V19.S4, V4.S4 + + // V0 += V5; V15 <<<= ((V0 XOR V15), 8) + // ... + VADD V5.S4, V0.S4, V0.S4 + VADD V6.S4, V1.S4, V1.S4 + VADD V7.S4, V2.S4, V2.S4 + VADD V4.S4, V3.S4, V3.S4 + VEOR V0.B16, V15.B16, V15.B16 + VEOR V1.B16, V12.B16, V12.B16 + VEOR V2.B16, V13.B16, V13.B16 + VEOR V3.B16, V14.B16, V14.B16 + VTBL V31.B16, [V12.B16], V12.B16 + VTBL V31.B16, [V13.B16], V13.B16 + VTBL V31.B16, [V14.B16], V14.B16 + VTBL V31.B16, [V15.B16], V15.B16 + + // V10 += V15; V5 <<<= ((V10 XOR V5), 7) + // ... + VADD V15.S4, V10.S4, V10.S4 + VADD V12.S4, V11.S4, V11.S4 + VADD V13.S4, V8.S4, V8.S4 + VADD V14.S4, V9.S4, V9.S4 + VEOR V10.B16, V5.B16, V16.B16 + VEOR V11.B16, V6.B16, V17.B16 + VEOR V8.B16, V7.B16, V18.B16 + VEOR V9.B16, V4.B16, V19.B16 + VSHL $7, V16.S4, V5.S4 + VSHL $7, V17.S4, V6.S4 + VSHL $7, V18.S4, V7.S4 + VSHL $7, V19.S4, V4.S4 + VSRI $25, V16.S4, V5.S4 + VSRI $25, V17.S4, V6.S4 + VSRI $25, V18.S4, V7.S4 + VSRI $25, V19.S4, V4.S4 + + SUB $1, R21 + CBNZ R21, chacha + + // VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4] + WORD $0x4D60E950 + + // VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4] + WORD $0x4DFFE894 + VADD V30.S4, V12.S4, V12.S4 + VADD V16.S4, V0.S4, V0.S4 + VADD V17.S4, V1.S4, V1.S4 + VADD V18.S4, V2.S4, V2.S4 + VADD V19.S4, V3.S4, V3.S4 + // VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4] + WORD $0x4DFFE898 + // restore R4 + SUB $32, R4 + + // load counter + nonce + // VLD1R (R7), [V28.S4] + WORD $0x4D40C8FC + // VLD3R (R6), [V29.S4, V30.S4, V31.S4] + WORD $0x4D40E8DD + + VADD V20.S4, V4.S4, V4.S4 + VADD V21.S4, V5.S4, V5.S4 + VADD V22.S4, V6.S4, V6.S4 + VADD V23.S4, V7.S4, V7.S4 + VADD V24.S4, V8.S4, V8.S4 + VADD V25.S4, V9.S4, V9.S4 + VADD V26.S4, V10.S4, V10.S4 + VADD V27.S4, V11.S4, V11.S4 + VADD V28.S4, V12.S4, V12.S4 + VADD V29.S4, V13.S4, V13.S4 + VADD V30.S4, V14.S4, V14.S4 + VADD V31.S4, V15.S4, V15.S4 + + VZIP1 V1.S4, V0.S4, V16.S4 + VZIP2 V1.S4, V0.S4, V17.S4 + VZIP1 V3.S4, V2.S4, V18.S4 + VZIP2 V3.S4, V2.S4, V19.S4 + VZIP1 V5.S4, V4.S4, V20.S4 + VZIP2 V5.S4, V4.S4, V21.S4 + VZIP1 V7.S4, V6.S4, V22.S4 + VZIP2 V7.S4, V6.S4, V23.S4 + VZIP1 V9.S4, V8.S4, V24.S4 + VZIP2 V9.S4, V8.S4, V25.S4 + VZIP1 V11.S4, V10.S4, V26.S4 + VZIP2 V11.S4, V10.S4, V27.S4 + VZIP1 V13.S4, V12.S4, V28.S4 + VZIP2 V13.S4, V12.S4, V29.S4 + VZIP1 V15.S4, V14.S4, V30.S4 + VZIP2 V15.S4, V14.S4, V31.S4 + VZIP1 V18.D2, V16.D2, V0.D2 + VZIP2 V18.D2, V16.D2, V4.D2 + VZIP1 V19.D2, V17.D2, V8.D2 + VZIP2 V19.D2, V17.D2, V12.D2 + VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16] + + VZIP1 V22.D2, V20.D2, V1.D2 + VZIP2 V22.D2, V20.D2, V5.D2 + VZIP1 V23.D2, V21.D2, V9.D2 + VZIP2 V23.D2, V21.D2, V13.D2 + VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16] + VZIP1 V26.D2, V24.D2, V2.D2 + VZIP2 V26.D2, V24.D2, V6.D2 + VZIP1 V27.D2, V25.D2, V10.D2 + VZIP2 V27.D2, V25.D2, V14.D2 + VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16] + VZIP1 V30.D2, V28.D2, V3.D2 + VZIP2 V30.D2, V28.D2, V7.D2 + VZIP1 V31.D2, V29.D2, V11.D2 + VZIP2 V31.D2, V29.D2, V15.D2 + VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16] + VEOR V0.B16, V16.B16, V16.B16 + VEOR V1.B16, V17.B16, V17.B16 + VEOR V2.B16, V18.B16, V18.B16 + VEOR V3.B16, V19.B16, V19.B16 + VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1) + VEOR V4.B16, V20.B16, V20.B16 + VEOR V5.B16, V21.B16, V21.B16 + VEOR V6.B16, V22.B16, V22.B16 + VEOR V7.B16, V23.B16, V23.B16 + VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1) + VEOR V8.B16, V24.B16, V24.B16 + VEOR V9.B16, V25.B16, V25.B16 + VEOR V10.B16, V26.B16, V26.B16 + VEOR V11.B16, V27.B16, V27.B16 + VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1) + VEOR V12.B16, V28.B16, V28.B16 + VEOR V13.B16, V29.B16, V29.B16 + VEOR V14.B16, V30.B16, V30.B16 + VEOR V15.B16, V31.B16, V31.B16 + VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1) + + ADD $4, R20 + MOVW R20, (R7) // update counter + + CMP R2, R12 + BGT loop + + RET + + +DATA ·constants+0x00(SB)/4, $0x61707865 +DATA ·constants+0x04(SB)/4, $0x3320646e +DATA ·constants+0x08(SB)/4, $0x79622d32 +DATA ·constants+0x0c(SB)/4, $0x6b206574 +GLOBL ·constants(SB), NOPTR|RODATA, $32 + +DATA ·incRotMatrix+0x00(SB)/4, $0x00000000 +DATA ·incRotMatrix+0x04(SB)/4, $0x00000001 +DATA ·incRotMatrix+0x08(SB)/4, $0x00000002 +DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003 +DATA ·incRotMatrix+0x10(SB)/4, $0x02010003 +DATA ·incRotMatrix+0x14(SB)/4, $0x06050407 +DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B +DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F +GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32 diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go new file mode 100644 index 0000000000..ad74e23aef --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go @@ -0,0 +1,31 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.11 +// +build !gccgo + +package chacha20 + +const ( + haveAsm = true + bufSize = 256 +) + +//go:noescape +func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) + +func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { + + if len(src) >= bufSize { + xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) + } + + if len(src)%bufSize != 0 { + i := len(src) - len(src)%bufSize + c.buf = [bufSize]byte{} + copy(c.buf[:], src[i:]) + xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter) + c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize]) + } +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go index 91520d1de0..47eac0314c 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !s390x gccgo appengine +// +build !arm64,!s390x arm64,!go1.11 gccgo appengine package chacha20 diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go index 0c1c671c40..aad645b447 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go @@ -6,15 +6,14 @@ package chacha20 -var haveAsm = hasVectorFacility() +import ( + "golang.org/x/sys/cpu" +) + +var haveAsm = cpu.S390X.HasVX const bufSize = 256 -// hasVectorFacility reports whether the machine supports the vector -// facility (vx). -// Implementation in asm_s390x.s. -func hasVectorFacility() bool - // xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only // be called when the vector facility is available. // Implementation in asm_s390x.s. diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s index 98427c5e22..57df404465 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s @@ -258,26 +258,3 @@ tail: MOVD R8, R3 MOVD $0, R4 JMP continue - -// func hasVectorFacility() bool -TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 - MOVD $x-24(SP), R1 - XC $24, 0(R1), 0(R1) // clear the storage - MOVD $2, R0 // R0 is the number of double words stored -1 - WORD $0xB2B01000 // STFLE 0(R1) - XOR R0, R0 // reset the value of R0 - MOVBZ z-8(SP), R1 - AND $0x40, R1 - BEQ novector - -vectorinstalled: - // check if the vector instruction has been enabled - VLEIB $0, $0xF, V16 - VLGVB $0, V16, R1 - CMPBNE R1, $0xF, novector - MOVB $1, ret+0(FP) // have vx - RET - -novector: - MOVB $0, ret+0(FP) // no vx - RET diff --git a/vendor/golang.org/x/crypto/md4/md4.go b/vendor/golang.org/x/crypto/md4/md4.go index 6d9ba9e5f3..59d3480693 100644 --- a/vendor/golang.org/x/crypto/md4/md4.go +++ b/vendor/golang.org/x/crypto/md4/md4.go @@ -3,6 +3,10 @@ // license that can be found in the LICENSE file. // Package md4 implements the MD4 hash algorithm as defined in RFC 1320. +// +// Deprecated: MD4 is cryptographically broken and should should only be used +// where compatibility with legacy systems, not security, is the goal. Instead, +// use a secure hash like SHA-256 (from crypto/sha256). package md4 // import "golang.org/x/crypto/md4" import ( diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go index a79a8c13ae..3e2518600e 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ b/vendor/golang.org/x/crypto/openpgp/keys.go @@ -333,7 +333,6 @@ func ReadEntity(packets *packet.Reader) (*Entity, error) { return nil, errors.StructuralError("primary key cannot be used for signatures") } - var current *Identity var revocations []*packet.Signature EachPacket: for { @@ -346,36 +345,8 @@ EachPacket: switch pkt := p.(type) { case *packet.UserId: - // Make a new Identity object, that we might wind up throwing away. - // We'll only add it if we get a valid self-signature over this - // userID. - current = new(Identity) - current.Name = pkt.Id - current.UserId = pkt - - for { - p, err = packets.Next() - if err == io.EOF { - break EachPacket - } else if err != nil { - return nil, err - } - - sig, ok := p.(*packet.Signature) - if !ok { - packets.Unread(p) - continue EachPacket - } - - if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { - if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { - return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error()) - } - current.SelfSignature = sig - e.Identities[pkt.Id] = current - } else { - current.Signatures = append(current.Signatures, sig) - } + if err := addUserID(e, packets, pkt); err != nil { + return nil, err } case *packet.Signature: if pkt.SigType == packet.SigTypeKeyRevocation { @@ -384,11 +355,9 @@ EachPacket: // TODO: RFC4880 5.2.1 permits signatures // directly on keys (eg. to bind additional // revocation keys). - } else if current == nil { - return nil, errors.StructuralError("signature packet found before user id packet") - } else { - current.Signatures = append(current.Signatures, pkt) } + // Else, ignoring the signature as it does not follow anything + // we would know to attach it to. case *packet.PrivateKey: if pkt.IsSubkey == false { packets.Unread(p) @@ -429,33 +398,105 @@ EachPacket: return e, nil } +func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { + // Make a new Identity object, that we might wind up throwing away. + // We'll only add it if we get a valid self-signature over this + // userID. + identity := new(Identity) + identity.Name = pkt.Id + identity.UserId = pkt + + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return err + } + + sig, ok := p.(*packet.Signature) + if !ok { + packets.Unread(p) + break + } + + if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { + if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { + return errors.StructuralError("user ID self-signature invalid: " + err.Error()) + } + identity.SelfSignature = sig + e.Identities[pkt.Id] = identity + } else { + identity.Signatures = append(identity.Signatures, sig) + } + } + + return nil +} + func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { var subKey Subkey subKey.PublicKey = pub subKey.PrivateKey = priv - p, err := packets.Next() - if err == io.EOF { - return io.ErrUnexpectedEOF + + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return errors.StructuralError("subkey signature invalid: " + err.Error()) + } + + sig, ok := p.(*packet.Signature) + if !ok { + packets.Unread(p) + break + } + + if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation { + return errors.StructuralError("subkey signature with wrong type") + } + + if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil { + return errors.StructuralError("subkey signature invalid: " + err.Error()) + } + + switch sig.SigType { + case packet.SigTypeSubkeyRevocation: + subKey.Sig = sig + case packet.SigTypeSubkeyBinding: + + if shouldReplaceSubkeySig(subKey.Sig, sig) { + subKey.Sig = sig + } + } } - if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } - var ok bool - subKey.Sig, ok = p.(*packet.Signature) - if !ok { + + if subKey.Sig == nil { return errors.StructuralError("subkey packet not followed by signature") } - if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation { - return errors.StructuralError("subkey signature with wrong type") - } - err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig) - if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } + e.Subkeys = append(e.Subkeys, subKey) + return nil } +func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { + if potentialNewSig == nil { + return false + } + + if existingSig == nil { + return true + } + + if existingSig.SigType == packet.SigTypeSubkeyRevocation { + return false // never override a revocation signature + } + + return potentialNewSig.CreationTime.After(existingSig.CreationTime) +} + const defaultRSAKeyBits = 2048 // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go index 625bb5ac80..5af64c5421 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go @@ -404,14 +404,16 @@ const ( type PublicKeyAlgorithm uint8 const ( - PubKeyAlgoRSA PublicKeyAlgorithm = 1 - PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 - PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 - PubKeyAlgoElGamal PublicKeyAlgorithm = 16 - PubKeyAlgoDSA PublicKeyAlgorithm = 17 + PubKeyAlgoRSA PublicKeyAlgorithm = 1 + PubKeyAlgoElGamal PublicKeyAlgorithm = 16 + PubKeyAlgoDSA PublicKeyAlgorithm = 17 // RFC 6637, Section 5. PubKeyAlgoECDH PublicKeyAlgorithm = 18 PubKeyAlgoECDSA PublicKeyAlgorithm = 19 + + // Deprecated in RFC 4880, Section 13.5. Use key flags instead. + PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 + PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 ) // CanEncrypt returns true if it's possible to encrypt a message to a public diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go index 34734cc63d..bd31cceac6 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go @@ -64,14 +64,19 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK return pk } -// NewSignerPrivateKey creates a sign-only PrivateKey from a crypto.Signer that +// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that // implements RSA or ECDSA. func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { pk := new(PrivateKey) + // In general, the public Keys should be used as pointers. We still + // type-switch on the values, for backwards-compatibility. switch pubkey := signer.Public().(type) { + case *rsa.PublicKey: + pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) case rsa.PublicKey: pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) - pk.PubKeyAlgo = PubKeyAlgoRSASignOnly + case *ecdsa.PublicKey: + pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) case ecdsa.PublicKey: pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) default: diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go index 6ce0cbedbe..b2a24a5323 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/signature.go @@ -542,7 +542,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e r, s, err = ecdsa.Sign(config.Random(), pk, digest) } else { var b []byte - b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, nil) + b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) if err == nil { r, s, err = unwrapECDSASig(b) } diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go index 96a2b382a1..d19ffbc786 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go @@ -80,7 +80,7 @@ func (uat *UserAttribute) Serialize(w io.Writer) (err error) { // ImageData returns zero or more byte slices, each containing // JPEG File Interchange Format (JFIF), for each photo in the -// the user attribute packet. +// user attribute packet. func (uat *UserAttribute) ImageData() (imageData [][]byte) { for _, sp := range uat.Contents { if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { diff --git a/vendor/golang.org/x/crypto/openpgp/write.go b/vendor/golang.org/x/crypto/openpgp/write.go index d6dede74e9..4ee71784eb 100644 --- a/vendor/golang.org/x/crypto/openpgp/write.go +++ b/vendor/golang.org/x/crypto/openpgp/write.go @@ -271,6 +271,7 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint // These are the possible hash functions that we'll use for the signature. candidateHashes := []uint8{ hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA384), hashToHashId(crypto.SHA512), hashToHashId(crypto.SHA1), hashToHashId(crypto.RIPEMD160), @@ -349,6 +350,7 @@ func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Con // These are the possible hash functions that we'll use for the signature. candidateHashes := []uint8{ hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA384), hashToHashId(crypto.SHA512), hashToHashId(crypto.SHA1), hashToHashId(crypto.RIPEMD160), diff --git a/vendor/golang.org/x/crypto/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/poly1305/mac_noasm.go new file mode 100644 index 0000000000..8387d29998 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/mac_noasm.go @@ -0,0 +1,11 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !amd64 gccgo appengine + +package poly1305 + +type mac struct{ macGeneric } + +func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} } diff --git a/vendor/golang.org/x/crypto/poly1305/poly1305.go b/vendor/golang.org/x/crypto/poly1305/poly1305.go index f562fa5712..d076a56235 100644 --- a/vendor/golang.org/x/crypto/poly1305/poly1305.go +++ b/vendor/golang.org/x/crypto/poly1305/poly1305.go @@ -2,21 +2,19 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -/* -Package poly1305 implements Poly1305 one-time message authentication code as -specified in https://cr.yp.to/mac/poly1305-20050329.pdf. - -Poly1305 is a fast, one-time authentication function. It is infeasible for an -attacker to generate an authenticator for a message without the key. However, a -key must only be used for a single message. Authenticating two different -messages with the same key allows an attacker to forge authenticators for other -messages with the same key. - -Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was -used with a fixed key in order to generate one-time keys from an nonce. -However, in this package AES isn't used and the one-time key is specified -directly. -*/ +// Package poly1305 implements Poly1305 one-time message authentication code as +// specified in https://cr.yp.to/mac/poly1305-20050329.pdf. +// +// Poly1305 is a fast, one-time authentication function. It is infeasible for an +// attacker to generate an authenticator for a message without the key. However, a +// key must only be used for a single message. Authenticating two different +// messages with the same key allows an attacker to forge authenticators for other +// messages with the same key. +// +// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was +// used with a fixed key in order to generate one-time keys from an nonce. +// However, in this package AES isn't used and the one-time key is specified +// directly. package poly1305 // import "golang.org/x/crypto/poly1305" import "crypto/subtle" @@ -31,3 +29,55 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { Sum(&tmp, m, key) return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 } + +// New returns a new MAC computing an authentication +// tag of all data written to it with the given key. +// This allows writing the message progressively instead +// of passing it as a single slice. Common users should use +// the Sum function instead. +// +// The key must be unique for each message, as authenticating +// two different messages with the same key allows an attacker +// to forge messages at will. +func New(key *[32]byte) *MAC { + return &MAC{ + mac: newMAC(key), + finalized: false, + } +} + +// MAC is an io.Writer computing an authentication tag +// of the data written to it. +// +// MAC cannot be used like common hash.Hash implementations, +// because using a poly1305 key twice breaks its security. +// Therefore writing data to a running MAC after calling +// Sum causes it to panic. +type MAC struct { + mac // platform-dependent implementation + + finalized bool +} + +// Size returns the number of bytes Sum will return. +func (h *MAC) Size() int { return TagSize } + +// Write adds more data to the running message authentication code. +// It never returns an error. +// +// It must not be called after the first call of Sum. +func (h *MAC) Write(p []byte) (n int, err error) { + if h.finalized { + panic("poly1305: write to MAC after Sum") + } + return h.mac.Write(p) +} + +// Sum computes the authenticator of all data written to the +// message authentication code. +func (h *MAC) Sum(b []byte) []byte { + var mac [TagSize]byte + h.mac.Sum(&mac) + h.finalized = true + return append(b, mac[:]...) +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_amd64.go b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go index 4dd72fe799..2dbf42aa53 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_amd64.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go @@ -6,17 +6,63 @@ package poly1305 -// This function is implemented in sum_amd64.s //go:noescape -func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte) +func initialize(state *[7]uint64, key *[32]byte) + +//go:noescape +func update(state *[7]uint64, msg []byte) + +//go:noescape +func finalize(tag *[TagSize]byte, state *[7]uint64) // Sum generates an authenticator for m using a one-time key and puts the // 16-byte result into out. Authenticating two different messages with the same // key allows an attacker to forge messages at will. func Sum(out *[16]byte, m []byte, key *[32]byte) { - var mPtr *byte - if len(m) > 0 { - mPtr = &m[0] - } - poly1305(out, mPtr, uint64(len(m)), key) + h := newMAC(key) + h.Write(m) + h.Sum(out) +} + +func newMAC(key *[32]byte) (h mac) { + initialize(&h.state, key) + return +} + +type mac struct { + state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 } + + buffer [TagSize]byte + offset int +} + +func (h *mac) Write(p []byte) (n int, err error) { + n = len(p) + if h.offset > 0 { + remaining := TagSize - h.offset + if n < remaining { + h.offset += copy(h.buffer[h.offset:], p) + return n, nil + } + copy(h.buffer[h.offset:], p[:remaining]) + p = p[remaining:] + h.offset = 0 + update(&h.state, h.buffer[:]) + } + if nn := len(p) - (len(p) % TagSize); nn > 0 { + update(&h.state, p[:nn]) + p = p[nn:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return n, nil +} + +func (h *mac) Sum(out *[16]byte) { + state := h.state + if h.offset > 0 { + update(&state, h.buffer[:h.offset]) + } + finalize(out, &state) } diff --git a/vendor/golang.org/x/crypto/poly1305/sum_amd64.s b/vendor/golang.org/x/crypto/poly1305/sum_amd64.s index 2edae63828..7d600f13cc 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_amd64.s +++ b/vendor/golang.org/x/crypto/poly1305/sum_amd64.s @@ -58,20 +58,17 @@ DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC GLOBL ·poly1305Mask<>(SB), RODATA, $16 -// func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key) -TEXT ·poly1305(SB), $0-32 - MOVQ out+0(FP), DI - MOVQ m+8(FP), SI - MOVQ mlen+16(FP), R15 - MOVQ key+24(FP), AX +// func update(state *[7]uint64, msg []byte) +TEXT ·update(SB), $0-32 + MOVQ state+0(FP), DI + MOVQ msg_base+8(FP), SI + MOVQ msg_len+16(FP), R15 - MOVQ 0(AX), R11 - MOVQ 8(AX), R12 - ANDQ ·poly1305Mask<>(SB), R11 // r0 - ANDQ ·poly1305Mask<>+8(SB), R12 // r1 - XORQ R8, R8 // h0 - XORQ R9, R9 // h1 - XORQ R10, R10 // h2 + MOVQ 0(DI), R8 // h0 + MOVQ 8(DI), R9 // h1 + MOVQ 16(DI), R10 // h2 + MOVQ 24(DI), R11 // r0 + MOVQ 32(DI), R12 // r1 CMPQ R15, $16 JB bytes_between_0_and_15 @@ -109,16 +106,42 @@ flush_buffer: JMP multiply done: - MOVQ R8, AX - MOVQ R9, BX + MOVQ R8, 0(DI) + MOVQ R9, 8(DI) + MOVQ R10, 16(DI) + RET + +// func initialize(state *[7]uint64, key *[32]byte) +TEXT ·initialize(SB), $0-16 + MOVQ state+0(FP), DI + MOVQ key+8(FP), SI + + // state[0...7] is initialized with zero + MOVOU 0(SI), X0 + MOVOU 16(SI), X1 + MOVOU ·poly1305Mask<>(SB), X2 + PAND X2, X0 + MOVOU X0, 24(DI) + MOVOU X1, 40(DI) + RET + +// func finalize(tag *[TagSize]byte, state *[7]uint64) +TEXT ·finalize(SB), $0-16 + MOVQ tag+0(FP), DI + MOVQ state+8(FP), SI + + MOVQ 0(SI), AX + MOVQ 8(SI), BX + MOVQ 16(SI), CX + MOVQ AX, R8 + MOVQ BX, R9 SUBQ $0xFFFFFFFFFFFFFFFB, AX SBBQ $0xFFFFFFFFFFFFFFFF, BX - SBBQ $3, R10 + SBBQ $3, CX CMOVQCS R8, AX CMOVQCS R9, BX - MOVQ key+24(FP), R8 - ADDQ 16(R8), AX - ADCQ 24(R8), BX + ADDQ 40(SI), AX + ADCQ 48(SI), BX MOVQ AX, 0(DI) MOVQ BX, 8(DI) diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ref.go b/vendor/golang.org/x/crypto/poly1305/sum_generic.go similarity index 54% rename from vendor/golang.org/x/crypto/poly1305/sum_ref.go rename to vendor/golang.org/x/crypto/poly1305/sum_generic.go index c4d59bd098..bab76ef0d8 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_ref.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_generic.go @@ -1,4 +1,4 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -6,21 +6,79 @@ package poly1305 import "encoding/binary" +const ( + msgBlock = uint32(1 << 24) + finalBlock = uint32(0) +) + // sumGeneric generates an authenticator for msg using a one-time key and // puts the 16-byte result into out. This is the generic implementation of // Sum and should be called if no assembly implementation is available. func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { - var ( - h0, h1, h2, h3, h4 uint32 // the hash accumulators - r0, r1, r2, r3, r4 uint64 // the r part of the key - ) + h := newMACGeneric(key) + h.Write(msg) + h.Sum(out) +} - r0 = uint64(binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff) - r1 = uint64((binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03) - r2 = uint64((binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff) - r3 = uint64((binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff) - r4 = uint64((binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff) +func newMACGeneric(key *[32]byte) (h macGeneric) { + h.r[0] = binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff + h.r[1] = (binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03 + h.r[2] = (binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff + h.r[3] = (binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff + h.r[4] = (binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff + h.s[0] = binary.LittleEndian.Uint32(key[16:]) + h.s[1] = binary.LittleEndian.Uint32(key[20:]) + h.s[2] = binary.LittleEndian.Uint32(key[24:]) + h.s[3] = binary.LittleEndian.Uint32(key[28:]) + return +} + +type macGeneric struct { + h, r [5]uint32 + s [4]uint32 + + buffer [TagSize]byte + offset int +} + +func (h *macGeneric) Write(p []byte) (n int, err error) { + n = len(p) + if h.offset > 0 { + remaining := TagSize - h.offset + if n < remaining { + h.offset += copy(h.buffer[h.offset:], p) + return n, nil + } + copy(h.buffer[h.offset:], p[:remaining]) + p = p[remaining:] + h.offset = 0 + updateGeneric(h.buffer[:], msgBlock, &(h.h), &(h.r)) + } + if nn := len(p) - (len(p) % TagSize); nn > 0 { + updateGeneric(p, msgBlock, &(h.h), &(h.r)) + p = p[nn:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return n, nil +} + +func (h *macGeneric) Sum(out *[16]byte) { + H, R := h.h, h.r + if h.offset > 0 { + var buffer [TagSize]byte + copy(buffer[:], h.buffer[:h.offset]) + buffer[h.offset] = 1 // invariant: h.offset < TagSize + updateGeneric(buffer[:], finalBlock, &H, &R) + } + finalizeGeneric(out, &H, &(h.s)) +} + +func updateGeneric(msg []byte, flag uint32, h, r *[5]uint32) { + h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4] + r0, r1, r2, r3, r4 := uint64(r[0]), uint64(r[1]), uint64(r[2]), uint64(r[3]), uint64(r[4]) R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5 for len(msg) >= TagSize { @@ -29,7 +87,7 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff - h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | (1 << 24) + h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | flag // h *= r d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) @@ -52,36 +110,11 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { msg = msg[TagSize:] } - if len(msg) > 0 { - var block [TagSize]byte - off := copy(block[:], msg) - block[off] = 0x01 + h[0], h[1], h[2], h[3], h[4] = h0, h1, h2, h3, h4 +} - // h += msg - h0 += binary.LittleEndian.Uint32(block[0:]) & 0x3ffffff - h1 += (binary.LittleEndian.Uint32(block[3:]) >> 2) & 0x3ffffff - h2 += (binary.LittleEndian.Uint32(block[6:]) >> 4) & 0x3ffffff - h3 += (binary.LittleEndian.Uint32(block[9:]) >> 6) & 0x3ffffff - h4 += (binary.LittleEndian.Uint32(block[12:]) >> 8) - - // h *= r - d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) - d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2) - d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3) - d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4) - d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0) - - // h %= p - h0 = uint32(d0) & 0x3ffffff - h1 = uint32(d1) & 0x3ffffff - h2 = uint32(d2) & 0x3ffffff - h3 = uint32(d3) & 0x3ffffff - h4 = uint32(d4) & 0x3ffffff - - h0 += uint32(d4>>26) * 5 - h1 += h0 >> 26 - h0 = h0 & 0x3ffffff - } +func finalizeGeneric(out *[TagSize]byte, h *[5]uint32, s *[4]uint32) { + h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4] // h %= p reduction h2 += h1 >> 26 @@ -123,13 +156,13 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { // s: the s part of the key // tag = (h + s) % (2^128) - t := uint64(h0) + uint64(binary.LittleEndian.Uint32(key[16:])) + t := uint64(h0) + uint64(s[0]) h0 = uint32(t) - t = uint64(h1) + uint64(binary.LittleEndian.Uint32(key[20:])) + (t >> 32) + t = uint64(h1) + uint64(s[1]) + (t >> 32) h1 = uint32(t) - t = uint64(h2) + uint64(binary.LittleEndian.Uint32(key[24:])) + (t >> 32) + t = uint64(h2) + uint64(s[2]) + (t >> 32) h2 = uint32(t) - t = uint64(h3) + uint64(binary.LittleEndian.Uint32(key[28:])) + (t >> 32) + t = uint64(h3) + uint64(s[3]) + (t >> 32) h3 = uint32(t) binary.LittleEndian.PutUint32(out[0:], h0) diff --git a/vendor/golang.org/x/crypto/poly1305/sum_noasm.go b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go index 751eec5274..fcdef46ab6 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_noasm.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go @@ -10,5 +10,7 @@ package poly1305 // 16-byte result into out. Authenticating two different messages with the same // key allows an attacker to forge messages at will. func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { - sumGeneric(out, msg, key) + h := newMAC(key) + h.Write(msg) + h.Sum(out) } diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go index 7a266cece4..ec99e07e9f 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_s390x.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go @@ -6,16 +6,9 @@ package poly1305 -// hasVectorFacility reports whether the machine supports -// the vector facility (vx). -func hasVectorFacility() bool - -// hasVMSLFacility reports whether the machine supports -// Vector Multiply Sum Logical (VMSL). -func hasVMSLFacility() bool - -var hasVX = hasVectorFacility() -var hasVMSL = hasVMSLFacility() +import ( + "golang.org/x/sys/cpu" +) // poly1305vx is an assembly implementation of Poly1305 that uses vector // instructions. It must only be called if the vector facility (vx) is @@ -33,12 +26,12 @@ func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte) // 16-byte result into out. Authenticating two different messages with the same // key allows an attacker to forge messages at will. func Sum(out *[16]byte, m []byte, key *[32]byte) { - if hasVX { + if cpu.S390X.HasVX { var mPtr *byte if len(m) > 0 { mPtr = &m[0] } - if hasVMSL && len(m) > 256 { + if cpu.S390X.HasVXE && len(m) > 256 { poly1305vmsl(out, mPtr, uint64(len(m)), key) } else { poly1305vx(out, mPtr, uint64(len(m)), key) diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s index 356c07a6c2..ca5a309d86 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_s390x.s +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s @@ -376,25 +376,3 @@ b1: MOVD $0, R3 BR multiply - -TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 - MOVD $x-24(SP), R1 - XC $24, 0(R1), 0(R1) // clear the storage - MOVD $2, R0 // R0 is the number of double words stored -1 - WORD $0xB2B01000 // STFLE 0(R1) - XOR R0, R0 // reset the value of R0 - MOVBZ z-8(SP), R1 - AND $0x40, R1 - BEQ novector - -vectorinstalled: - // check if the vector instruction has been enabled - VLEIB $0, $0xF, V16 - VLGVB $0, V16, R1 - CMPBNE R1, $0xF, novector - MOVB $1, ret+0(FP) // have vx - RET - -novector: - MOVB $0, ret+0(FP) // no vx - RET diff --git a/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s index e548020b14..e60bbc1d7f 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s +++ b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s @@ -907,25 +907,3 @@ square: MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) BR next - -TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1 - MOVD $x-24(SP), R1 - XC $24, 0(R1), 0(R1) // clear the storage - MOVD $2, R0 // R0 is the number of double words stored -1 - WORD $0xB2B01000 // STFLE 0(R1) - XOR R0, R0 // reset the value of R0 - MOVBZ z-8(SP), R1 - AND $0x01, R1 - BEQ novmsl - -vectorinstalled: - // check if the vector instruction has been enabled - VLEIB $0, $0xF, V16 - VLGVB $0, V16, R1 - CMPBNE R1, $0xF, novmsl - MOVB $1, ret+0(FP) // have vx - RET - -novmsl: - MOVB $0, ret+0(FP) // no vx - RET diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go index b1808dd267..51f740500e 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client.go @@ -25,10 +25,22 @@ import ( "math/big" "sync" + "crypto" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ssh" ) +// SignatureFlags represent additional flags that can be passed to the signature +// requests an defined in [PROTOCOL.agent] section 4.5.1. +type SignatureFlags uint32 + +// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. +const ( + SignatureFlagReserved SignatureFlags = 1 << iota + SignatureFlagRsaSha256 + SignatureFlagRsaSha512 +) + // Agent represents the capabilities of an ssh-agent. type Agent interface { // List returns the identities known to the agent. @@ -57,6 +69,26 @@ type Agent interface { Signers() ([]ssh.Signer, error) } +type ExtendedAgent interface { + Agent + + // SignWithFlags signs like Sign, but allows for additional flags to be sent/received + SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) + + // Extension processes a custom extension request. Standard-compliant agents are not + // required to support any extensions, but this method allows agents to implement + // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. + // If agent extensions are unsupported entirely this method MUST return an + // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in + // the request is unsupported by the agent then ErrExtensionUnsupported MUST be + // returned. + // + // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents + // of the response are unspecified (including the type of the message), the complete + // response will be returned as a []byte slice, including the "type" byte of the message. + Extension(extensionType string, contents []byte) ([]byte, error) +} + // ConstraintExtension describes an optional constraint defined by users. type ConstraintExtension struct { // ExtensionName consist of a UTF-8 string suffixed by the @@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct { Rest []byte `ssh:"rest"` } +// See [PROTOCOL.agent], section 4.7 +const agentExtension = 27 +const agentExtensionFailure = 28 + +// ErrExtensionUnsupported indicates that an extension defined in +// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this +// error indicates that the agent returned a standard SSH_AGENT_FAILURE message +// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol +// specification (and therefore this error) does not distinguish between a +// specific extension being unsupported and extensions being unsupported entirely. +var ErrExtensionUnsupported = errors.New("agent: extension unsupported") + +type extensionAgentMsg struct { + ExtensionType string `sshtype:"27"` + Contents []byte +} + // Key represents a protocol 2 public key as defined in // [PROTOCOL.agent], section 2.5.2. type Key struct { @@ -260,7 +309,7 @@ type client struct { // NewClient returns an Agent that talks to an ssh-agent process over // the given connection. -func NewClient(rw io.ReadWriter) Agent { +func NewClient(rw io.ReadWriter) ExtendedAgent { return &client{conn: rw} } @@ -268,6 +317,21 @@ func NewClient(rw io.ReadWriter) Agent { // unmarshaled into reply and replyType is set to the first byte of // the reply, which contains the type of the message. func (c *client) call(req []byte) (reply interface{}, err error) { + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + reply, err = unmarshal(buf) + if err != nil { + return nil, clientErr(err) + } + return reply, nil +} + +// callRaw sends an RPC to the agent. On success, the raw +// bytes of the response are returned; no unmarshalling is +// performed on the response. +func (c *client) callRaw(req []byte) (reply []byte, err error) { c.mu.Lock() defer c.mu.Unlock() @@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) { } respSize := binary.BigEndian.Uint32(respSizeBuf[:]) if respSize > maxAgentResponseBytes { - return nil, clientErr(err) + return nil, clientErr(errors.New("response too large")) } buf := make([]byte, respSize) if _, err = io.ReadFull(c.conn, buf); err != nil { return nil, clientErr(err) } - reply, err = unmarshal(buf) - if err != nil { - return nil, clientErr(err) - } - return reply, err + return buf, nil } func (c *client) simpleCall(req []byte) error { @@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) { // Sign has the agent sign the data using a protocol 2 key as defined // in [PROTOCOL.agent] section 2.6.2. func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return c.SignWithFlags(key, data, 0) +} + +func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { req := ssh.Marshal(signRequestAgentMsg{ KeyBlob: key.Marshal(), Data: data, + Flags: uint32(flags), }) msg, err := c.call(req) @@ -681,3 +746,44 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, // The agent has its own entropy source, so the rand argument is ignored. return s.agent.Sign(s.pub, data) } + +func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) { + var flags SignatureFlags + if opts != nil { + switch opts.HashFunc() { + case crypto.SHA256: + flags = SignatureFlagRsaSha256 + case crypto.SHA512: + flags = SignatureFlagRsaSha512 + } + } + return s.agent.SignWithFlags(s.pub, data, flags) +} + +// Calls an extension method. It is up to the agent implementation as to whether or not +// any particular extension is supported and may always return an error. Because the +// type of the response is up to the implementation, this returns the bytes of the +// response and does not attempt any type of unmarshalling. +func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { + req := ssh.Marshal(extensionAgentMsg{ + ExtensionType: extensionType, + Contents: contents, + }) + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + if len(buf) == 0 { + return nil, errors.New("agent: failure; empty response") + } + // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message + // represents an agent that does not support the extension + if buf[0] == agentFailure { + return nil, ErrExtensionUnsupported + } + if buf[0] == agentExtensionFailure { + return nil, errors.New("agent: generic extension failure") + } + + return buf, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go index 1a5163270c..c9d9794307 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/keyring.go +++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go @@ -182,6 +182,10 @@ func (r *keyring) Add(key AddedKey) error { // Sign returns a signature for the data. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return r.SignWithFlags(key, data, 0) +} + +func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { r.mu.Lock() defer r.mu.Unlock() if r.locked { @@ -192,7 +196,24 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { wanted := key.Marshal() for _, k := range r.keys { if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { - return k.signer.Sign(rand.Reader, data) + if flags == 0 { + return k.signer.Sign(rand.Reader, data) + } else { + if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { + return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) + } else { + var algorithm string + switch flags { + case SignatureFlagRsaSha256: + algorithm = ssh.SigAlgoRSASHA2256 + case SignatureFlagRsaSha512: + algorithm = ssh.SigAlgoRSASHA2512 + default: + return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) + } + return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) + } + } } } return nil, errors.New("not found") @@ -213,3 +234,8 @@ func (r *keyring) Signers() ([]ssh.Signer, error) { } return s, nil } + +// The keyring does not support any extensions +func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { + return nil, ErrExtensionUnsupported +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go index 2e4692cbd5..6e7a1e02f2 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/server.go +++ b/vendor/golang.org/x/crypto/ssh/agent/server.go @@ -128,7 +128,14 @@ func (s *server) processRequest(data []byte) (interface{}, error) { Blob: req.KeyBlob, } - sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. + var sig *ssh.Signature + var err error + if extendedAgent, ok := s.agent.(ExtendedAgent); ok { + sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) + } else { + sig, err = s.agent.Sign(k, req.Data) + } + if err != nil { return nil, err } @@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) { case agentAddIDConstrained, agentAddIdentity: return nil, s.insertIdentity(data) + + case agentExtension: + // Return a stub object where the whole contents of the response gets marshaled. + var responseStub struct { + Rest []byte `ssh:"rest"` + } + + if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { + // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 + // requires that we return a standard SSH_AGENT_FAILURE message. + responseStub.Rest = []byte{agentFailure} + } else { + var req extensionAgentMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) + if err != nil { + // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE + // message as required by [PROTOCOL.agent] section 4.7. + if err == ErrExtensionUnsupported { + responseStub.Rest = []byte{agentFailure} + } else { + // As the result of any other error processing an extension request, + // [PROTOCOL.agent] section 4.7 requires that we return a + // SSH_AGENT_EXTENSION_FAILURE code. + responseStub.Rest = []byte{agentExtensionFailure} + } + } else { + if len(res) == 0 { + return nil, nil + } + responseStub.Rest = res + } + } + + return responseStub, nil } return nil, fmt.Errorf("unknown opcode %d", data[0]) @@ -497,6 +541,9 @@ func ServeAgent(agent Agent, c io.ReadWriter) error { return err } l := binary.BigEndian.Uint32(length[:]) + if l == 0 { + return fmt.Errorf("agent: request size is 0") + } if l > maxAgentResponseBytes { // We also cap requests. return fmt.Errorf("agent: request too large: %d", l) diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go index 42106f3f2c..00ed9923e7 100644 --- a/vendor/golang.org/x/crypto/ssh/certs.go +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -222,6 +222,11 @@ type openSSHCertSigner struct { signer Signer } +type algorithmOpenSSHCertSigner struct { + *openSSHCertSigner + algorithmSigner AlgorithmSigner +} + // NewCertSigner returns a Signer that signs with the given Certificate, whose // private key is held by signer. It returns an error if the public key in cert // doesn't match the key used by signer. @@ -230,7 +235,12 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { return nil, errors.New("ssh: signer and cert have different public key") } - return &openSSHCertSigner{cert, signer}, nil + if algorithmSigner, ok := signer.(AlgorithmSigner); ok { + return &algorithmOpenSSHCertSigner{ + &openSSHCertSigner{cert, signer}, algorithmSigner}, nil + } else { + return &openSSHCertSigner{cert, signer}, nil + } } func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { @@ -241,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey { return s.pub } +func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) +} + const sourceAddressCriticalOption = "source-address" // CertChecker does the work of verifying a certificate. Its methods diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go index 67b0126105..a65a923be3 100644 --- a/vendor/golang.org/x/crypto/ssh/cipher.go +++ b/vendor/golang.org/x/crypto/ssh/cipher.go @@ -149,8 +149,8 @@ type streamPacketCipher struct { macResult []byte } -// readPacket reads and decrypt a single packet from the reader argument. -func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { +// readCipherPacket reads and decrypt a single packet from the reader argument. +func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { if _, err := io.ReadFull(r, s.prefix[:]); err != nil { return nil, err } @@ -221,8 +221,8 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err return s.packetData[:length-paddingLength-1], nil } -// writePacket encrypts and sends a packet of data to the writer argument -func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { +// writeCipherPacket encrypts and sends a packet of data to the writer argument +func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { if len(packet) > maxPacket { return errors.New("ssh: packet too large") } @@ -327,7 +327,7 @@ func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) const gcmTagSize = 16 -func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { +func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { // Pad out to multiple of 16 bytes. This is different from the // stream cipher because that encrypts the length too. padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) @@ -370,7 +370,7 @@ func (c *gcmCipher) incIV() { } } -func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { +func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { if _, err := io.ReadFull(r, c.prefix[:]); err != nil { return nil, err } @@ -486,8 +486,8 @@ type cbcError string func (e cbcError) Error() string { return string(e) } -func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { - p, err := c.readPacketLeaky(seqNum, r) +func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { + p, err := c.readCipherPacketLeaky(seqNum, r) if err != nil { if _, ok := err.(cbcError); ok { // Verification error: read a fixed amount of @@ -500,7 +500,7 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { return p, err } -func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { +func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { blockSize := c.decrypter.BlockSize() // Read the header, which will include some of the subsequent data in the @@ -576,7 +576,7 @@ func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) return c.packetData[prefixLen:paddingStart], nil } -func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { +func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) // Length of encrypted portion of the packet (header, payload, padding). @@ -665,7 +665,7 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA return c, nil } -func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { +func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} s := chacha20.New(c.contentKey, nonce) var polyKey [32]byte @@ -723,7 +723,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, return plain, nil } -func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { +func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} s := chacha20.New(c.contentKey, nonce) var polyKey [32]byte diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go index ae6ca775ee..7b00bff1ca 100644 --- a/vendor/golang.org/x/crypto/ssh/client.go +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -185,7 +185,7 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) { // keys. A HostKeyCallback must return nil if the host key is OK, or // an error to reject it. It receives the hostname as passed to Dial // or NewClientConn. The remote address is the RemoteAddr of the -// net.Conn underlying the the SSH connection. +// net.Conn underlying the SSH connection. type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error // BannerCallback is the function type used for treat the banner sent by diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go index 04f3620b3d..d97415d2d3 100644 --- a/vendor/golang.org/x/crypto/ssh/common.go +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -109,6 +109,7 @@ func findCommon(what string, client []string, server []string) (common string, e return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) } +// directionAlgorithms records algorithm choices in one direction (either read or write) type directionAlgorithms struct { Cipher string MAC string @@ -137,7 +138,7 @@ type algorithms struct { r directionAlgorithms } -func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { +func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { result := &algorithms{} result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) @@ -150,32 +151,37 @@ func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor return } - result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) + stoc, ctos := &result.w, &result.r + if isClient { + ctos, stoc = stoc, ctos + } + + ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) if err != nil { return } - result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) + stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) if err != nil { return } - result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) + ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) if err != nil { return } - result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) + stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) if err != nil { return } - result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) + ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) if err != nil { return } - result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) + stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) if err != nil { return } diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go index 4f7912ecd6..2b10b05a49 100644 --- a/vendor/golang.org/x/crypto/ssh/handshake.go +++ b/vendor/golang.org/x/crypto/ssh/handshake.go @@ -543,7 +543,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { clientInit := otherInit serverInit := t.sentInitMsg - if len(t.hostKeys) == 0 { + isClient := len(t.hostKeys) == 0 + if isClient { clientInit, serverInit = serverInit, clientInit magics.clientKexInit = t.sentInitPacket @@ -551,7 +552,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { } var err error - t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) + t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit) if err != nil { return err } diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go index 2261dc386c..969804794f 100644 --- a/vendor/golang.org/x/crypto/ssh/keys.go +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -38,6 +38,16 @@ const ( KeyAlgoED25519 = "ssh-ed25519" ) +// These constants represent non-default signature algorithms that are supported +// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See +// [PROTOCOL.agent] section 4.5.1 and +// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10 +const ( + SigAlgoRSA = "ssh-rsa" + SigAlgoRSASHA2256 = "rsa-sha2-256" + SigAlgoRSASHA2512 = "rsa-sha2-512" +) + // parsePubKey parses a public key of the given algorithm. // Use ParsePublicKey for keys with prepended algorithm. func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { @@ -301,6 +311,19 @@ type Signer interface { Sign(rand io.Reader, data []byte) (*Signature, error) } +// A AlgorithmSigner is a Signer that also supports specifying a specific +// algorithm to use for signing. +type AlgorithmSigner interface { + Signer + + // SignWithAlgorithm is like Signer.Sign, but allows specification of a + // non-default signing algorithm. See the SigAlgo* constants in this + // package for signature algorithms supported by this package. Callers may + // pass an empty string for the algorithm in which case the AlgorithmSigner + // will use its default algorithm. + SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) +} + type rsaPublicKey rsa.PublicKey func (r *rsaPublicKey) Type() string { @@ -349,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte { } func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != r.Type() { + var hash crypto.Hash + switch sig.Format { + case SigAlgoRSA: + hash = crypto.SHA1 + case SigAlgoRSASHA2256: + hash = crypto.SHA256 + case SigAlgoRSASHA2512: + hash = crypto.SHA512 + default: return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) } - h := crypto.SHA1.New() + h := hash.New() h.Write(data) digest := h.Sum(nil) - return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) + return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) } func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { @@ -459,6 +490,14 @@ func (k *dsaPrivateKey) PublicKey() PublicKey { } func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { + return k.SignWithAlgorithm(rand, data, "") +} + +func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + if algorithm != "" && algorithm != k.PublicKey().Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + h := crypto.SHA1.New() h.Write(data) digest := h.Sum(nil) @@ -691,16 +730,42 @@ func (s *wrappedSigner) PublicKey() PublicKey { } func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + return s.SignWithAlgorithm(rand, data, "") +} + +func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { var hashFunc crypto.Hash - switch key := s.pubKey.(type) { - case *rsaPublicKey, *dsaPublicKey: - hashFunc = crypto.SHA1 - case *ecdsaPublicKey: - hashFunc = ecHash(key.Curve) - case ed25519PublicKey: - default: - return nil, fmt.Errorf("ssh: unsupported key type %T", key) + if _, ok := s.pubKey.(*rsaPublicKey); ok { + // RSA keys support a few hash functions determined by the requested signature algorithm + switch algorithm { + case "", SigAlgoRSA: + algorithm = SigAlgoRSA + hashFunc = crypto.SHA1 + case SigAlgoRSASHA2256: + hashFunc = crypto.SHA256 + case SigAlgoRSASHA2512: + hashFunc = crypto.SHA512 + default: + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + } else { + // The only supported algorithm for all other key types is the same as the type of the key + if algorithm == "" { + algorithm = s.pubKey.Type() + } else if algorithm != s.pubKey.Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + + switch key := s.pubKey.(type) { + case *dsaPublicKey: + hashFunc = crypto.SHA1 + case *ecdsaPublicKey: + hashFunc = ecHash(key.Curve) + case ed25519PublicKey: + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } } var digest []byte @@ -745,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { } return &Signature{ - Format: s.pubKey.Type(), + Format: algorithm, Blob: signature, }, nil } diff --git a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go index bc3db737e5..260cfe58c6 100644 --- a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go +++ b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go @@ -350,8 +350,8 @@ func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.Public return db.checkAddr(hostToCheck, remoteKey) } -// checkAddrs checks if we can find the given public key for any of -// the given addresses. If we only find an entry for the IP address, +// checkAddr checks if we can find the given public key for the +// given address. If we only find an entry for the IP address, // or only the hostname, then this still succeeds. func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { // TODO(hanwen): are these the right semantics? What if there diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go index 08d2811730..5ec42afa3b 100644 --- a/vendor/golang.org/x/crypto/ssh/messages.go +++ b/vendor/golang.org/x/crypto/ssh/messages.go @@ -764,3 +764,29 @@ func decode(packet []byte) (interface{}, error) { } return msg, nil } + +var packetTypeNames = map[byte]string{ + msgDisconnect: "disconnectMsg", + msgServiceRequest: "serviceRequestMsg", + msgServiceAccept: "serviceAcceptMsg", + msgKexInit: "kexInitMsg", + msgKexDHInit: "kexDHInitMsg", + msgKexDHReply: "kexDHReplyMsg", + msgUserAuthRequest: "userAuthRequestMsg", + msgUserAuthSuccess: "userAuthSuccessMsg", + msgUserAuthFailure: "userAuthFailureMsg", + msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg", + msgGlobalRequest: "globalRequestMsg", + msgRequestSuccess: "globalRequestSuccessMsg", + msgRequestFailure: "globalRequestFailureMsg", + msgChannelOpen: "channelOpenMsg", + msgChannelData: "channelDataMsg", + msgChannelOpenConfirm: "channelOpenConfirmMsg", + msgChannelOpenFailure: "channelOpenFailureMsg", + msgChannelWindowAdjust: "windowAdjustMsg", + msgChannelEOF: "channelEOFMsg", + msgChannelClose: "channelCloseMsg", + msgChannelRequest: "channelRequestMsg", + msgChannelSuccess: "channelRequestSuccessMsg", + msgChannelFailure: "channelRequestFailureMsg", +} diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index d0f4825319..e86e89661a 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -404,7 +404,7 @@ userAuthLoop: perms, authErr = config.PasswordCallback(s, password) case "keyboard-interactive": if config.KeyboardInteractiveCallback == nil { - authErr = errors.New("ssh: keyboard-interactive auth not configubred") + authErr = errors.New("ssh: keyboard-interactive auth not configured") break } @@ -484,6 +484,7 @@ userAuthLoop: // sig.Format. This is usually the same, but // for certs, the names differ. if !isAcceptableAlgo(sig.Format) { + authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) break } signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go index f6fae1db46..49ddc2e7de 100644 --- a/vendor/golang.org/x/crypto/ssh/transport.go +++ b/vendor/golang.org/x/crypto/ssh/transport.go @@ -53,14 +53,14 @@ type transport struct { // packetCipher represents a combination of SSH encryption/MAC // protocol. A single instance should be used for one direction only. type packetCipher interface { - // writePacket encrypts the packet and writes it to w. The + // writeCipherPacket encrypts the packet and writes it to w. The // contents of the packet are generally scrambled. - writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error + writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error - // readPacket reads and decrypts a packet of data. The + // readCipherPacket reads and decrypts a packet of data. The // returned packet may be overwritten by future calls of // readPacket. - readPacket(seqnum uint32, r io.Reader) ([]byte, error) + readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error) } // connectionState represents one side (read or write) of the @@ -127,7 +127,7 @@ func (t *transport) readPacket() (p []byte, err error) { } func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { - packet, err := s.packetCipher.readPacket(s.seqNum, r) + packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) s.seqNum++ if err == nil && len(packet) == 0 { err = errors.New("ssh: zero length packet") @@ -175,7 +175,7 @@ func (t *transport) writePacket(packet []byte) error { func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { changeKeys := len(packet) > 0 && packet[0] == msgNewKeys - err := s.packetCipher.writePacket(s.seqNum, w, rand, packet) + err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) if err != nil { return err } diff --git a/vendor/golang.org/x/sys/cpu/byteorder.go b/vendor/golang.org/x/sys/cpu/byteorder.go new file mode 100644 index 0000000000..da6b9e4363 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/byteorder.go @@ -0,0 +1,30 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "encoding/binary" + "runtime" +) + +// hostByteOrder returns binary.LittleEndian on little-endian machines and +// binary.BigEndian on big-endian machines. +func hostByteOrder() binary.ByteOrder { + switch runtime.GOARCH { + case "386", "amd64", "amd64p32", + "arm", "arm64", + "mipsle", "mips64le", "mips64p32le", + "ppc64le", + "riscv", "riscv64": + return binary.LittleEndian + case "armbe", "arm64be", + "mips", "mips64", "mips64p32", + "ppc", "ppc64", + "s390", "s390x", + "sparc", "sparc64": + return binary.BigEndian + } + panic("unknown architecture") +} diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 0000000000..679e78c2ce --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,126 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cpu implements processor feature detection for +// various CPU architectures. +package cpu + +// Initialized reports whether the CPU features were initialized. +// +// For some GOOS/GOARCH combinations initialization of the CPU features depends +// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm +// Initialized will report false if reading the file fails. +var Initialized bool + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasRDRAND bool // RDRAND instruction (on-chip random number generator) + HasRDSEED bool // RDSEED instruction (on-chip random number generator) + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + _ CacheLinePad +} + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + _ CacheLinePad +} + +// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. +// If the current platform is not ppc64/ppc64le then all feature flags are false. +// +// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (DARN, SCV), so there are feature bits for +// those as well. The minimum processor requirement is POWER8 (ISA 2.07). +// The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9) + _ CacheLinePad +} + +// S390X contains the supported CPU features of the current IBM Z +// (s390x) platform. If the current platform is not IBM Z then all +// feature flags are false. +// +// S390X is padded to avoid false sharing. Further HasVX is only set +// if the OS supports vector registers in addition to the STFLE +// feature bit being set. +var S390X struct { + _ CacheLinePad + HasZARCH bool // z/Architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended + HasLDISP bool // long (20-bit) displacements + HasEIMM bool // 32-bit immediates + HasDFP bool // decimal floating point + HasETF3EH bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions + HasVX bool // vector facility + HasVXE bool // vector-enhancements facility 1 + _ CacheLinePad +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go b/vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go new file mode 100644 index 0000000000..d8c26a048d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go @@ -0,0 +1,30 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix,ppc64 + +package cpu + +import "golang.org/x/sys/unix" + +const cacheLineSize = 128 + +const ( + // getsystemcfg constants + _SC_IMPL = 2 + _IMPL_POWER8 = 0x10000 + _IMPL_POWER9 = 0x20000 +) + +func init() { + impl := unix.Getsystemcfg(_SC_IMPL) + if impl&_IMPL_POWER8 != 0 { + PPC64.IsPOWER8 = true + } + if impl&_IMPL_POWER9 != 0 { + PPC64.IsPOWER9 = true + } + + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 0000000000..7f2348b7d4 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,9 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go new file mode 100644 index 0000000000..568bcd031a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go @@ -0,0 +1,21 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !gccgo + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return true } + +// The following feature detection functions are defined in cpu_s390x.s. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList +func kmQuery() queryResult +func kmcQuery() queryResult +func kmctrQuery() queryResult +func kmaQuery() queryResult +func kimdQuery() queryResult +func klmdQuery() queryResult diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go new file mode 100644 index 0000000000..f7cb46971c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 +// +build !gccgo + +package cpu + +// cpuid is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) + +// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo.c b/vendor/golang.org/x/sys/cpu/cpu_gccgo.c new file mode 100644 index 0000000000..e363c7d131 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo.c @@ -0,0 +1,43 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 +// +build gccgo + +#include +#include + +// Need to wrap __get_cpuid_count because it's declared as static. +int +gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); +} + +// xgetbv reads the contents of an XCR (Extended Control Register) +// specified in the ECX register into registers EDX:EAX. +// Currently, the only supported value for XCR is 0. +// +// TODO: Replace with a better alternative: +// +// #include +// +// #pragma GCC target("xsave") +// +// void gccgoXgetbv(uint32_t *eax, uint32_t *edx) { +// unsigned long long x = _xgetbv(0); +// *eax = x & 0xffffffff; +// *edx = (x >> 32) & 0xffffffff; +// } +// +// Note that _xgetbv is defined starting with GCC 8. +void +gccgoXgetbv(uint32_t *eax, uint32_t *edx) +{ + __asm(" xorl %%ecx, %%ecx\n" + " xgetbv" + : "=a"(*eax), "=d"(*edx)); +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo.go new file mode 100644 index 0000000000..ba49b91bd3 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo.go @@ -0,0 +1,26 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 +// +build gccgo + +package cpu + +//extern gccgoGetCpuidCount +func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) + +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { + var a, b, c, d uint32 + gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) + return a, b, c, d +} + +//extern gccgoXgetbv +func gccgoXgetbv(eax, edx *uint32) + +func xgetbv() (eax, edx uint32) { + var a, d uint32 + gccgoXgetbv(&a, &d) + return a, d +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go new file mode 100644 index 0000000000..aa986f7782 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go @@ -0,0 +1,22 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build gccgo + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return false } + +// TODO(mundaym): the following feature detection functions are currently +// stubs. See https://golang.org/cl/162887 for how to fix this. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList { panic("not implemented for gccgo") } +func kmQuery() queryResult { panic("not implemented for gccgo") } +func kmcQuery() queryResult { panic("not implemented for gccgo") } +func kmctrQuery() queryResult { panic("not implemented for gccgo") } +func kmaQuery() queryResult { panic("not implemented for gccgo") } +func kimdQuery() queryResult { panic("not implemented for gccgo") } +func klmdQuery() queryResult { panic("not implemented for gccgo") } diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux.go b/vendor/golang.org/x/sys/cpu/cpu_linux.go new file mode 100644 index 0000000000..76b5f507fa --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux.go @@ -0,0 +1,59 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build !amd64,!amd64p32,!386 + +package cpu + +import ( + "io/ioutil" +) + +const ( + _AT_HWCAP = 16 + _AT_HWCAP2 = 26 + + procAuxv = "/proc/self/auxv" + + uintSize = int(32 << (^uint(0) >> 63)) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var hwCap uint +var hwCap2 uint + +func init() { + buf, err := ioutil.ReadFile(procAuxv) + if err != nil { + // e.g. on android /proc/self/auxv is not accessible, so silently + // ignore the error and leave Initialized = false + return + } + + bo := hostByteOrder() + for len(buf) >= 2*(uintSize/8) { + var tag, val uint + switch uintSize { + case 32: + tag = uint(bo.Uint32(buf[0:])) + val = uint(bo.Uint32(buf[4:])) + buf = buf[8:] + case 64: + tag = uint(bo.Uint64(buf[0:])) + val = uint(bo.Uint64(buf[8:])) + buf = buf[16:] + } + switch tag { + case _AT_HWCAP: + hwCap = val + case _AT_HWCAP2: + hwCap2 = val + } + } + doinit() + + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go new file mode 100644 index 0000000000..fa7fb1bd7b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -0,0 +1,67 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 64 + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + hwcap_FP = 1 << 0 + hwcap_ASIMD = 1 << 1 + hwcap_EVTSTRM = 1 << 2 + hwcap_AES = 1 << 3 + hwcap_PMULL = 1 << 4 + hwcap_SHA1 = 1 << 5 + hwcap_SHA2 = 1 << 6 + hwcap_CRC32 = 1 << 7 + hwcap_ATOMICS = 1 << 8 + hwcap_FPHP = 1 << 9 + hwcap_ASIMDHP = 1 << 10 + hwcap_CPUID = 1 << 11 + hwcap_ASIMDRDM = 1 << 12 + hwcap_JSCVT = 1 << 13 + hwcap_FCMA = 1 << 14 + hwcap_LRCPC = 1 << 15 + hwcap_DCPOP = 1 << 16 + hwcap_SHA3 = 1 << 17 + hwcap_SM3 = 1 << 18 + hwcap_SM4 = 1 << 19 + hwcap_ASIMDDP = 1 << 20 + hwcap_SHA512 = 1 << 21 + hwcap_SVE = 1 << 22 + hwcap_ASIMDFHM = 1 << 23 +) + +func doinit() { + // HWCAP feature bits + ARM64.HasFP = isSet(hwCap, hwcap_FP) + ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD) + ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM64.HasAES = isSet(hwCap, hwcap_AES) + ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL) + ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1) + ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2) + ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32) + ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS) + ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP) + ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP) + ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID) + ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM) + ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT) + ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA) + ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC) + ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP) + ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3) + ARM64.HasSM3 = isSet(hwCap, hwcap_SM3) + ARM64.HasSM4 = isSet(hwCap, hwcap_SM4) + ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP) + ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) + ARM64.HasSVE = isSet(hwCap, hwcap_SVE) + ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go new file mode 100644 index 0000000000..6c8d975d40 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go @@ -0,0 +1,33 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build ppc64 ppc64le + +package cpu + +const cacheLineSize = 128 + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func doinit() { + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go new file mode 100644 index 0000000000..d579eaef40 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go @@ -0,0 +1,161 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 256 + +const ( + // bit mask values from /usr/include/bits/hwcap.h + hwcap_ZARCH = 2 + hwcap_STFLE = 4 + hwcap_MSA = 8 + hwcap_LDISP = 16 + hwcap_EIMM = 32 + hwcap_DFP = 64 + hwcap_ETF3EH = 256 + hwcap_VX = 2048 + hwcap_VXE = 8192 +) + +// bitIsSet reports whether the bit at index is set. The bit index +// is in big endian order, so bit index 0 is the leftmost bit. +func bitIsSet(bits []uint64, index uint) bool { + return bits[index/64]&((1<<63)>>(index%64)) != 0 +} + +// function is the code for the named cryptographic function. +type function uint8 + +const ( + // KM{,A,C,CTR} function codes + aes128 function = 18 // AES-128 + aes192 function = 19 // AES-192 + aes256 function = 20 // AES-256 + + // K{I,L}MD function codes + sha1 function = 1 // SHA-1 + sha256 function = 2 // SHA-256 + sha512 function = 3 // SHA-512 + sha3_224 function = 32 // SHA3-224 + sha3_256 function = 33 // SHA3-256 + sha3_384 function = 34 // SHA3-384 + sha3_512 function = 35 // SHA3-512 + shake128 function = 36 // SHAKE-128 + shake256 function = 37 // SHAKE-256 + + // KLMD function codes + ghash function = 65 // GHASH +) + +// queryResult contains the result of a Query function +// call. Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type queryResult struct { + bits [2]uint64 +} + +// Has reports whether the given functions are present. +func (q *queryResult) Has(fns ...function) bool { + if len(fns) == 0 { + panic("no function codes provided") + } + for _, f := range fns { + if !bitIsSet(q.bits[:], uint(f)) { + return false + } + } + return true +} + +// facility is a bit index for the named facility. +type facility uint8 + +const ( + // cryptography facilities + msa4 facility = 77 // message-security-assist extension 4 + msa8 facility = 146 // message-security-assist extension 8 +) + +// facilityList contains the result of an STFLE call. +// Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type facilityList struct { + bits [4]uint64 +} + +// Has reports whether the given facilities are present. +func (s *facilityList) Has(fs ...facility) bool { + if len(fs) == 0 { + panic("no facility bits provided") + } + for _, f := range fs { + if !bitIsSet(s.bits[:], uint(f)) { + return false + } + } + return true +} + +func doinit() { + // test HWCAP bit vector + has := func(featureMask uint) bool { + return hwCap&featureMask == featureMask + } + + // mandatory + S390X.HasZARCH = has(hwcap_ZARCH) + + // optional + S390X.HasSTFLE = has(hwcap_STFLE) + S390X.HasLDISP = has(hwcap_LDISP) + S390X.HasEIMM = has(hwcap_EIMM) + S390X.HasETF3EH = has(hwcap_ETF3EH) + S390X.HasDFP = has(hwcap_DFP) + S390X.HasMSA = has(hwcap_MSA) + S390X.HasVX = has(hwcap_VX) + if S390X.HasVX { + S390X.HasVXE = has(hwcap_VXE) + } + + // We need implementations of stfle, km and so on + // to detect cryptographic features. + if !haveAsmFunctions() { + return + } + + // optional cryptographic functions + if S390X.HasMSA { + aes := []function{aes128, aes192, aes256} + + // cipher message + km, kmc := kmQuery(), kmcQuery() + S390X.HasAES = km.Has(aes...) + S390X.HasAESCBC = kmc.Has(aes...) + if S390X.HasSTFLE { + facilities := stfle() + if facilities.Has(msa4) { + kmctr := kmctrQuery() + S390X.HasAESCTR = kmctr.Has(aes...) + } + if facilities.Has(msa8) { + kma := kmaQuery() + S390X.HasAESGCM = kma.Has(aes...) + } + } + + // compute message digest + kimd := kimdQuery() // intermediate (no padding) + klmd := klmdQuery() // last (padding) + S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) + S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) + S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) + S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist + sha3 := []function{ + sha3_224, sha3_256, sha3_384, sha3_512, + shake128, shake256, + } + S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 0000000000..f55e0c82c7 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,11 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build mips64 mips64le + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 0000000000..cda87b1a1b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,11 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build mips mipsle + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go new file mode 100644 index 0000000000..dd1e76dc92 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !linux,arm64 + +package cpu + +const cacheLineSize = 64 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/vendor/golang.org/x/sys/cpu/cpu_s390x.s new file mode 100644 index 0000000000..e5037d92e0 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.s @@ -0,0 +1,57 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !gccgo + +#include "textflag.h" + +// func stfle() facilityList +TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 + MOVD $ret+0(FP), R1 + MOVD $3, R0 // last doubleword index to store + XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) + WORD $0xb2b01000 // store facility list extended (STFLE) + RET + +// func kmQuery() queryResult +TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KM-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92E0024 // cipher message (KM) + RET + +// func kmcQuery() queryResult +TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMC-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92F0024 // cipher message with chaining (KMC) + RET + +// func kmctrQuery() queryResult +TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMCTR-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92D4024 // cipher message with counter (KMCTR) + RET + +// func kmaQuery() queryResult +TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMA-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xb9296024 // cipher message with authentication (KMA) + RET + +// func kimdQuery() queryResult +TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KIMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93E0024 // compute intermediate message digest (KIMD) + RET + +// func klmdQuery() queryResult +TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KLMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93F0024 // compute last message digest (KLMD) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_wasm.go b/vendor/golang.org/x/sys/cpu/cpu_wasm.go new file mode 100644 index 0000000000..bd9bbda0c0 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_wasm.go @@ -0,0 +1,15 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build wasm + +package cpu + +// We're compiling the cpu package for an unknown (software-abstracted) CPU. +// Make CacheLinePad an empty struct and hope that the usual struct alignment +// rules are good enough. + +const cacheLineSize = 0 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go new file mode 100644 index 0000000000..d70d317f5a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -0,0 +1,59 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 + +package cpu + +const cacheLineSize = 64 + +func init() { + Initialized = true + + maxID, _, _, _ := cpuid(0, 0) + + if maxID < 1 { + return + } + + _, _, ecx1, edx1 := cpuid(1, 0) + X86.HasSSE2 = isSet(26, edx1) + + X86.HasSSE3 = isSet(0, ecx1) + X86.HasPCLMULQDQ = isSet(1, ecx1) + X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) + X86.HasSSE41 = isSet(19, ecx1) + X86.HasSSE42 = isSet(20, ecx1) + X86.HasPOPCNT = isSet(23, ecx1) + X86.HasAES = isSet(25, ecx1) + X86.HasOSXSAVE = isSet(27, ecx1) + X86.HasRDRAND = isSet(30, ecx1) + + osSupportsAVX := false + // For XGETBV, OSXSAVE bit is required and sufficient. + if X86.HasOSXSAVE { + eax, _ := xgetbv() + // Check if XMM and YMM registers have OS support. + osSupportsAVX = isSet(1, eax) && isSet(2, eax) + } + + X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + + if maxID < 7 { + return + } + + _, ebx7, _, _ := cpuid(7, 0) + X86.HasBMI1 = isSet(3, ebx7) + X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX + X86.HasBMI2 = isSet(8, ebx7) + X86.HasERMS = isSet(9, ebx7) + X86.HasRDSEED = isSet(18, ebx7) + X86.HasADX = isSet(19, ebx7) +} + +func isSet(bitpos uint, value uint32) bool { + return value&(1<$zsysctl"; fi if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi - if [ -n "$mktypes" ]; then - echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; + if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi - fi ) | $run diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 6a23484e5b..cfb61ba049 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -192,6 +192,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -501,6 +502,7 @@ ccflags="$@" $2 !~ "WMESGLEN" && $2 ~ /^W[A-Z0-9]+$/ || $2 ~/^PPPIOC/ || + $2 ~ /^FAN_|FANOTIFY_/ || $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} $2 ~ /^__WCOREFLAG$/ {next} $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} diff --git a/vendor/golang.org/x/sys/unix/mksyscall.go b/vendor/golang.org/x/sys/unix/mksyscall.go index e06e4253ea..e4af9424e9 100644 --- a/vendor/golang.org/x/sys/unix/mksyscall.go +++ b/vendor/golang.org/x/sys/unix/mksyscall.go @@ -153,6 +153,11 @@ func main() { } funct, inps, outps, sysname := f[2], f[3], f[4], f[5] + // ClockGettime doesn't have a syscall number on Darwin, only generate libc wrappers. + if goos == "darwin" && !libc && funct == "ClockGettime" { + continue + } + // Split argument lists on comma. in := parseParamList(inps) out := parseParamList(outps) @@ -228,7 +233,7 @@ func main() { } else { args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) } - } else if p.Type == "int64" && endianness != "" { + } else if (p.Type == "int64" || p.Type == "uint64") && endianness != "" { if len(args)%2 == 1 && *arm { // arm abi specifies 64-bit argument uses // (even, odd) pair diff --git a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go index 5f9ae233a7..26e8b36cfc 100644 --- a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go +++ b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go @@ -25,8 +25,8 @@ func cmsgAlignOf(salen int) int { if SizeofPtr == 8 { salign = 4 } - case "openbsd": - // OpenBSD armv7 requires 64-bit alignment. + case "netbsd", "openbsd": + // NetBSD and OpenBSD armv7 require 64-bit alignment. if runtime.GOARCH == "arm" { salign = 8 } diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go index a76826f443..fd83d87509 100644 --- a/vendor/golang.org/x/sys/unix/syscall_aix.go +++ b/vendor/golang.org/x/sys/unix/syscall_aix.go @@ -545,3 +545,5 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { //sys gettimeofday(tv *Timeval, tzp *Timezone) (err error) //sysnb Time(t *Time_t) (tt Time_t, err error) //sys Utime(path string, buf *Utimbuf) (err error) + +//sys Getsystemcfg(label int) (n uint64) diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index a2e3688822..2120091892 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -144,6 +144,23 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) ( //sys getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) +func SysctlClockinfo(name string) (*Clockinfo, error) { + mib, err := sysctlmib(name) + if err != nil { + return nil, err + } + + n := uintptr(SizeofClockinfo) + var ci Clockinfo + if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil { + return nil, err + } + if n != SizeofClockinfo { + return nil, EIO + } + return &ci, nil +} + //sysnb pipe() (r int, w int, err error) func Pipe(p []int) (err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 4bb86aa0fe..7e429ab2f9 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -39,6 +39,20 @@ func Creat(path string, mode uint32) (fd int, err error) { return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) } +//sys FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) +//sys fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) + +func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) (err error) { + if pathname == "" { + return fanotifyMark(fd, flags, mask, dirFd, nil) + } + p, err := BytePtrFromString(pathname) + if err != nil { + return err + } + return fanotifyMark(fd, flags, mask, dirFd, p) +} + //sys fchmodat(dirfd int, path string, mode uint32) (err error) func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -990,10 +1004,28 @@ func GetsockoptString(fd, level, opt int) (string, error) { return string(buf[:vallen-1]), nil } +func GetsockoptTpacketStats(fd, level, opt int) (*TpacketStats, error) { + var value TpacketStats + vallen := _Socklen(SizeofTpacketStats) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptTpacketStatsV3(fd, level, opt int) (*TpacketStatsV3, error) { + var value TpacketStatsV3 + vallen := _Socklen(SizeofTpacketStatsV3) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) } +func SetsockoptPacketMreq(fd, level, opt int, mreq *PacketMreq) error { + return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) +} + // SetsockoptSockFprog attaches a classic BPF or an extended BPF program to a // socket to filter incoming packets. See 'man 7 socket' for usage information. func SetsockoptSockFprog(fd, level, opt int, fprog *SockFprog) error { @@ -1008,6 +1040,14 @@ func SetsockoptCanRawFilter(fd, level, opt int, filter []CanFilter) error { return setsockopt(fd, level, opt, p, uintptr(len(filter)*SizeofCanFilter)) } +func SetsockoptTpacketReq(fd, level, opt int, tp *TpacketReq) error { + return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp)) +} + +func SetsockoptTpacketReq3(fd, level, opt int, tp *TpacketReq3) error { + return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp)) +} + // Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html) // KeyctlInt calls keyctl commands in which each argument is an int. diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go index cda3559419..3a3c37b4c8 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go @@ -19,12 +19,18 @@ func setTimeval(sec, usec int64) Timeval { return Timeval{Sec: int32(sec), Usec: int32(usec)} } +//sysnb pipe(p *[2]_C_int) (err error) + func Pipe(p []int) (err error) { if len(p) != 2 { return EINVAL } var pp [2]_C_int + // Try pipe2 first for Android O, then try pipe for kernel 2.6.23. err = pipe2(&pp, 0) + if err == ENOSYS { + err = pipe(&pp) + } p[0] = int(pp[0]) p[1] = int(pp[1]) return diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index 6d56722401..cb20b15d5d 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -208,3 +208,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { } return ppoll(&fds[0], len(fds), ts, nil) } + +//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) + +func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { + cmdlineLen := len(cmdline) + if cmdlineLen > 0 { + // Account for the additional NULL byte added by + // BytePtrFromString in kexecFileLoad. The kexec_file_load + // syscall expects a NULL-terminated string. + cmdlineLen++ + } + return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go index f23ca451c7..6230f64052 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -211,3 +211,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0) } + +//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) + +func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { + cmdlineLen := len(cmdline) + if cmdlineLen > 0 { + // Account for the additional NULL byte added by + // BytePtrFromString in kexecFileLoad. The kexec_file_load + // syscall expects a NULL-terminated string. + cmdlineLen++ + } + return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/vendor/golang.org/x/sys/unix/syscall_openbsd.go index 687999549c..c8648ec026 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd.go @@ -43,6 +43,23 @@ func nametomib(name string) (mib []_C_int, err error) { return nil, EINVAL } +func SysctlClockinfo(name string) (*Clockinfo, error) { + mib, err := sysctlmib(name) + if err != nil { + return nil, err + } + + n := uintptr(SizeofClockinfo) + var ci Clockinfo + if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil { + return nil, err + } + if n != SizeofClockinfo { + return nil, EIO + } + return &ci, nil +} + func SysctlUvmexp(name string) (*Uvmexp, error) { mib, err := sysctlmib(name) if err != nil { diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go index 33583a22b6..0ed1d58d57 100644 --- a/vendor/golang.org/x/sys/unix/syscall_unix.go +++ b/vendor/golang.org/x/sys/unix/syscall_unix.go @@ -28,6 +28,11 @@ var ( errENOENT error = syscall.ENOENT ) +var ( + signalNameMapOnce sync.Once + signalNameMap map[string]syscall.Signal +) + // errnoErr returns common boxed Errno values, to prevent // allocations at runtime. func errnoErr(e syscall.Errno) error { @@ -66,6 +71,19 @@ func SignalName(s syscall.Signal) string { return "" } +// SignalNum returns the syscall.Signal for signal named s, +// or 0 if a signal with such name is not found. +// The signal name should start with "SIG". +func SignalNum(s string) syscall.Signal { + signalNameMapOnce.Do(func() { + signalNameMap = make(map[string]syscall.Signal) + for _, signal := range signalList { + signalNameMap[signal.name] = signal.num + } + }) + return signalNameMap[s] +} + // clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte. func clen(n []byte) int { i := bytes.IndexByte(n, 0) @@ -276,6 +294,13 @@ func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) { return &tv, err } +func GetsockoptUint64(fd, level, opt int) (value uint64, err error) { + var n uint64 + vallen := _Socklen(8) + err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen) + return n, err +} + func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { var rsa RawSockaddrAny var len _Socklen = SizeofSockaddrAny @@ -333,6 +358,10 @@ func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) { return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv)) } +func SetsockoptUint64(fd, level, opt int, value uint64) (err error) { + return setsockopt(fd, level, opt, unsafe.Pointer(&value), 8) +} + func Socket(domain, typ, proto int) (fd int, err error) { if domain == AF_INET6 && SocketDisableIPv6 { return -1, EAFNOSUPPORT @@ -377,3 +406,22 @@ func SetNonblock(fd int, nonblocking bool) (err error) { func Exec(argv0 string, argv []string, envv []string) error { return syscall.Exec(argv0, argv, envv) } + +// Lutimes sets the access and modification times tv on path. If path refers to +// a symlink, it is not dereferenced and the timestamps are set on the symlink. +// If tv is nil, the access and modification times are set to the current time. +// Otherwise tv must contain exactly 2 elements, with access time as the first +// element and modification time as the second element. +func Lutimes(path string, tv []Timeval) error { + if tv == nil { + return UtimesNanoAt(AT_FDCWD, path, nil, AT_SYMLINK_NOFOLLOW) + } + if len(tv) != 2 { + return EINVAL + } + ts := []Timespec{ + NsecToTimespec(TimevalToNsec(tv[0])), + NsecToTimespec(TimevalToNsec(tv[1])), + } + return UtimesNanoAt(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW) +} diff --git a/vendor/golang.org/x/sys/unix/types_darwin.go b/vendor/golang.org/x/sys/unix/types_darwin.go index 9fd2aaa6a2..155c2e692b 100644 --- a/vendor/golang.org/x/sys/unix/types_darwin.go +++ b/vendor/golang.org/x/sys/unix/types_darwin.go @@ -275,3 +275,9 @@ const ( // uname type Utsname C.struct_utsname + +// Clockinfo + +const SizeofClockinfo = C.sizeof_struct_clockinfo + +type Clockinfo C.struct_clockinfo diff --git a/vendor/golang.org/x/sys/unix/types_openbsd.go b/vendor/golang.org/x/sys/unix/types_openbsd.go index 4e5e57f9a6..8aafbe4469 100644 --- a/vendor/golang.org/x/sys/unix/types_openbsd.go +++ b/vendor/golang.org/x/sys/unix/types_openbsd.go @@ -274,3 +274,9 @@ type Utsname C.struct_utsname const SizeofUvmexp = C.sizeof_struct_uvmexp type Uvmexp C.struct_uvmexp + +// Clockinfo + +const SizeofClockinfo = C.sizeof_struct_clockinfo + +type Clockinfo C.struct_clockinfo diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index cb89df8f54..9e99d67cb8 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80041270 BLKBSZSET = 0x40041271 @@ -486,6 +487,50 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 @@ -493,6 +538,7 @@ const ( FFDLY = 0x8000 FLUSHO = 0x1000 FP_XSTATE_MAGIC2 = 0x46505845 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -514,7 +560,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1134,7 +1180,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1398,6 +1444,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2232,6 +2284,7 @@ const ( TUNGETVNETBE = 0x800454df TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd + TUNSETCARRIER = 0x400454e2 TUNSETDEBUG = 0x400454c9 TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 73c9b88ca7..e3091f1e30 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 @@ -486,6 +487,50 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 @@ -493,6 +538,7 @@ const ( FFDLY = 0x8000 FLUSHO = 0x1000 FP_XSTATE_MAGIC2 = 0x46505845 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -514,7 +560,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1134,7 +1180,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1398,6 +1444,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2233,6 +2285,7 @@ const ( TUNGETVNETBE = 0x800454df TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd + TUNSETCARRIER = 0x400454e2 TUNSETDEBUG = 0x400454c9 TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index f1ef82f57e..a75dfebcc4 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80041270 BLKBSZSET = 0x40041271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x1000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1132,7 +1178,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1396,6 +1442,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2239,6 +2291,7 @@ const ( TUNGETVNETBE = 0x800454df TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd + TUNSETCARRIER = 0x400454e2 TUNSETDEBUG = 0x400454c9 TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index cf17c99069..393ad7c91b 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 @@ -488,6 +489,50 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 @@ -495,6 +540,7 @@ const ( FFDLY = 0x8000 FLUSHO = 0x1000 FPSIMD_MAGIC = 0x46508001 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -516,7 +562,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1135,7 +1181,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1399,6 +1445,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2224,6 +2276,7 @@ const ( TUNGETVNETBE = 0x800454df TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd + TUNSETCARRIER = 0x400454e2 TUNSETDEBUG = 0x400454c9 TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 380913c4fc..ba1beb9093 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40041270 BLKBSZSET = 0x80041271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x2000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1132,7 +1178,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1396,6 +1442,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2234,6 +2286,7 @@ const ( TUNGETVNETBE = 0x400454df TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 TUNSETDEBUG = 0x800454c9 TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index fb82529ac9..efba3e5c9d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x2000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1132,7 +1178,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1396,6 +1442,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2234,6 +2286,7 @@ const ( TUNGETVNETBE = 0x400454df TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 TUNSETDEBUG = 0x800454c9 TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 677d904562..d3f6e90652 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x2000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1132,7 +1178,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1396,6 +1442,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2234,6 +2286,7 @@ const ( TUNGETVNETBE = 0x400454df TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 TUNSETDEBUG = 0x800454c9 TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 7ddd09d782..7275cd876b 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40041270 BLKBSZSET = 0x80041271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x2000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1132,7 +1178,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1396,6 +1442,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2234,6 +2286,7 @@ const ( TUNGETVNETBE = 0x400454df TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 TUNSETDEBUG = 0x800454c9 TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index ebaca417b4..7586a134ef 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x4000 FFDLY = 0x4000 FLUSHO = 0x800000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1131,7 +1177,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1398,6 +1444,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2294,6 +2346,7 @@ const ( TUNGETVNETBE = 0x400454df TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 TUNSETDEBUG = 0x800454c9 TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index 02938cb6ed..b861ec7834 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x4000 FFDLY = 0x4000 FLUSHO = 0x800000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1131,7 +1177,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1398,6 +1444,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2294,6 +2346,7 @@ const ( TUNGETVNETBE = 0x400454df TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 TUNSETDEBUG = 0x800454c9 TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 5aea4b9093..a321ec23f4 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x1000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1132,7 +1178,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1396,6 +1442,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2220,6 +2272,7 @@ const ( TUNGETVNETBE = 0x800454df TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd + TUNSETCARRIER = 0x400454e2 TUNSETDEBUG = 0x400454c9 TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 7f7c2e3e2f..f6c99164ff 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -174,6 +174,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 @@ -486,12 +487,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x1000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -513,7 +559,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1132,7 +1178,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1396,6 +1442,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2293,6 +2345,7 @@ const ( TUNGETVNETBE = 0x800454df TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd + TUNSETCARRIER = 0x400454e2 TUNSETDEBUG = 0x400454c9 TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 968e21fd68..c1e95e29cb 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -177,6 +177,7 @@ const ( B9600 = 0xd BALLOON_KVM_MAGIC = 0x13661366 BDEVFS_MAGIC = 0x62646576 + BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 @@ -490,12 +491,57 @@ const ( FALLOC_FL_PUNCH_HOLE = 0x2 FALLOC_FL_UNSHARE_RANGE = 0x40 FALLOC_FL_ZERO_RANGE = 0x10 + FANOTIFY_METADATA_VERSION = 0x3 + FAN_ACCESS = 0x1 + FAN_ACCESS_PERM = 0x20000 + FAN_ALLOW = 0x1 + FAN_ALL_CLASS_BITS = 0xc + FAN_ALL_EVENTS = 0x3b + FAN_ALL_INIT_FLAGS = 0x3f + FAN_ALL_MARK_FLAGS = 0xff + FAN_ALL_OUTGOING_EVENTS = 0x3403b + FAN_ALL_PERM_EVENTS = 0x30000 + FAN_AUDIT = 0x10 + FAN_CLASS_CONTENT = 0x4 + FAN_CLASS_NOTIF = 0x0 + FAN_CLASS_PRE_CONTENT = 0x8 + FAN_CLOEXEC = 0x1 + FAN_CLOSE = 0x18 + FAN_CLOSE_NOWRITE = 0x10 + FAN_CLOSE_WRITE = 0x8 + FAN_DENY = 0x2 + FAN_ENABLE_AUDIT = 0x40 + FAN_EVENT_METADATA_LEN = 0x18 + FAN_EVENT_ON_CHILD = 0x8000000 + FAN_MARK_ADD = 0x1 + FAN_MARK_DONT_FOLLOW = 0x4 + FAN_MARK_FILESYSTEM = 0x100 + FAN_MARK_FLUSH = 0x80 + FAN_MARK_IGNORED_MASK = 0x20 + FAN_MARK_IGNORED_SURV_MODIFY = 0x40 + FAN_MARK_INODE = 0x0 + FAN_MARK_MOUNT = 0x10 + FAN_MARK_ONLYDIR = 0x8 + FAN_MARK_REMOVE = 0x2 + FAN_MODIFY = 0x2 + FAN_NOFD = -0x1 + FAN_NONBLOCK = 0x2 + FAN_ONDIR = 0x40000000 + FAN_OPEN = 0x20 + FAN_OPEN_EXEC = 0x1000 + FAN_OPEN_EXEC_PERM = 0x40000 + FAN_OPEN_PERM = 0x10000 + FAN_Q_OVERFLOW = 0x4000 + FAN_REPORT_TID = 0x100 + FAN_UNLIMITED_MARKS = 0x20 + FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 FD_SETSIZE = 0x400 FF0 = 0x0 FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x1000 + FS_ENCRYPTION_MODE_ADIANTUM = 0x9 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -517,7 +563,7 @@ const ( FS_POLICY_FLAGS_PAD_4 = 0x0 FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 - FS_POLICY_FLAGS_VALID = 0x3 + FS_POLICY_FLAGS_VALID = 0x7 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -1136,7 +1182,7 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 - NETNSA_MAX = 0x3 + NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 @@ -1400,6 +1446,12 @@ const ( PR_MCE_KILL_SET = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_PAC_APDAKEY = 0x4 + PR_PAC_APDBKEY = 0x8 + PR_PAC_APGAKEY = 0x10 + PR_PAC_APIAKEY = 0x1 + PR_PAC_APIBKEY = 0x2 + PR_PAC_RESET_KEYS = 0x36 PR_SET_CHILD_SUBREAPER = 0x24 PR_SET_DUMPABLE = 0x4 PR_SET_ENDIAN = 0x14 @@ -2282,6 +2334,7 @@ const ( TUNGETVNETBE = 0x400454df TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 TUNSETDEBUG = 0x800454c9 TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go index e645a05cbe..52802bfc17 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go @@ -1367,6 +1367,14 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsystemcfg(label int) (n uint64) { + r0, _ := callgetsystemcfg(label) + n = uint64(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getrlimit(resource int, rlim *Rlimit) (err error) { _, e1 := callgetrlimit(resource, uintptr(unsafe.Pointer(rlim))) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go index 0b8eb72102..a2b24e4a43 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go @@ -120,6 +120,7 @@ import ( //go:cgo_import_dynamic libc_gettimeofday gettimeofday "libc.a/shr_64.o" //go:cgo_import_dynamic libc_time time "libc.a/shr_64.o" //go:cgo_import_dynamic libc_utime utime "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o" //go:cgo_import_dynamic libc_getrlimit getrlimit "libc.a/shr_64.o" //go:cgo_import_dynamic libc_setrlimit setrlimit "libc.a/shr_64.o" //go:cgo_import_dynamic libc_lseek lseek "libc.a/shr_64.o" @@ -235,6 +236,7 @@ import ( //go:linkname libc_gettimeofday libc_gettimeofday //go:linkname libc_time libc_time //go:linkname libc_utime libc_utime +//go:linkname libc_getsystemcfg libc_getsystemcfg //go:linkname libc_getrlimit libc_getrlimit //go:linkname libc_setrlimit libc_setrlimit //go:linkname libc_lseek libc_lseek @@ -353,6 +355,7 @@ var ( libc_gettimeofday, libc_time, libc_utime, + libc_getsystemcfg, libc_getrlimit, libc_setrlimit, libc_lseek, @@ -1135,6 +1138,13 @@ func callutime(_p0 uintptr, buf uintptr) (r1 uintptr, e1 Errno) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func callgetsystemcfg(label int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func callgetrlimit(resource int, rlim uintptr) (r1 uintptr, e1 Errno) { r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getrlimit)), 2, uintptr(resource), rlim, 0, 0, 0, 0) return diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go index e88a442787..5491c89e96 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go @@ -118,6 +118,7 @@ int poll(uintptr_t, int, int); int gettimeofday(uintptr_t, uintptr_t); int time(uintptr_t); int utime(uintptr_t, uintptr_t); +unsigned long long getsystemcfg(int); int getrlimit(int, uintptr_t); int setrlimit(int, uintptr_t); long long lseek(int, long long, int); @@ -1011,6 +1012,14 @@ func callutime(_p0 uintptr, buf uintptr) (r1 uintptr, e1 Errno) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func callgetsystemcfg(label int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getsystemcfg(C.int(label))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func callgetrlimit(resource int, rlim uintptr) (r1 uintptr, e1 Errno) { r1 = uintptr(C.getrlimit(C.int(resource), C.uintptr_t(rlim))) e1 = syscall.GetErrno() diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go index c8b451000b..9855afa767 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(mask>>32), uintptr(dirFd), uintptr(unsafe.Pointer(pathname))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go index 2aac3184bc..773e251185 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go index 13c06c2815..ccea621d48 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(mask>>32), uintptr(dirFd), uintptr(unsafe.Pointer(pathname))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1658,6 +1679,16 @@ func faccessat(dirfd int, path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func pipe(p *[2]_C_int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go index 737fa8d181..712c7a3265 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2206,3 +2227,18 @@ func pipe2(p *[2]_C_int, flags int) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(cmdline) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_KEXEC_FILE_LOAD, uintptr(kernelFd), uintptr(initrdFd), uintptr(cmdlineLen), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go index 0a85f3f8db..68b325100b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask>>32), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go index ec7007e781..a8be4076cf 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go index c5bb25d964..1351028adc 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go index 26ada0478f..327b4f97a8 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(mask>>32), uintptr(dirFd), uintptr(unsafe.Pointer(pathname))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go index 2da9cb700a..c145bd3cec 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go index 772733d83f..cd8179c7a5 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go index 996eba517a..2e90cf0f27 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2186,3 +2207,18 @@ func pipe2(p *[2]_C_int, flags int) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(cmdline) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_KEXEC_FILE_LOAD, uintptr(kernelFd), uintptr(initrdFd), uintptr(cmdlineLen), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go index cb9072a33a..fe9c7e12b0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go index 5e48a1001b..d4a2100b09 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go @@ -14,6 +14,27 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) { + r0, _, e1 := Syscall(SYS_FANOTIFY_INIT, uintptr(flags), uintptr(event_f_flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 3206967896..b81d508a73 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -285,4 +285,5 @@ const ( SYS_STATX = 291 SYS_IO_PGETEVENTS = 292 SYS_RSEQ = 293 + SYS_KEXEC_FILE_LOAD = 294 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 473c74613f..2c8c46a2fc 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -284,4 +284,5 @@ const ( SYS_STATX = 291 SYS_IO_PGETEVENTS = 292 SYS_RSEQ = 293 + SYS_KEXEC_FILE_LOAD = 294 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 93480fcb16..6ed306370a 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -253,6 +253,7 @@ const ( SYS_TIMER_GETOVERRUN = 264 SYS_TIMER_DELETE = 265 SYS_TIMER_CREATE = 266 + SYS_VSERVER = 267 SYS_IO_SETUP = 268 SYS_IO_DESTROY = 269 SYS_IO_SUBMIT = 270 diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go index 2aeb52a886..cefe2f8eae 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go @@ -487,3 +487,13 @@ type Utsname struct { Version [256]byte Machine [256]byte } + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go index 0d0d9f2ccb..c6bb883c39 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go @@ -497,3 +497,13 @@ type Utsname struct { Version [256]byte Machine [256]byte } + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go index 04e344b78d..94c23bc2d4 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go @@ -488,3 +488,13 @@ type Utsname struct { Version [256]byte Machine [256]byte } + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go index 9fec185c18..c82a930cdc 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go @@ -497,3 +497,13 @@ type Utsname struct { Version [256]byte Machine [256]byte } + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index 3e9c18e681..6dfe56be76 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -575,6 +575,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -640,6 +641,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x8 @@ -961,7 +973,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1064,6 +1077,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1085,21 +1099,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1112,6 +1143,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1416,6 +1448,9 @@ const ( SizeofTpacketHdr = 0x18 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2031,3 +2066,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index 14365ff6cf..9f8cbf4cb3 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -576,6 +576,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -641,6 +642,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -972,7 +984,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1075,6 +1088,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1096,21 +1110,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1123,6 +1154,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1428,6 +1460,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2044,3 +2079,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index 80ad473c61..cbbf19a447 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -579,6 +579,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -644,6 +645,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x8 @@ -950,7 +962,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1053,6 +1066,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1074,21 +1088,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1101,6 +1132,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1406,6 +1438,9 @@ const ( SizeofTpacketHdr = 0x18 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2022,3 +2057,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index 20e78cc1f6..be21189dbd 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -577,6 +577,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -642,6 +643,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -951,7 +963,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1054,6 +1067,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1075,21 +1089,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1102,6 +1133,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1407,6 +1439,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2023,3 +2058,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index bdeb0cb24f..d599ca2759 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -578,6 +578,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -643,6 +644,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x8 @@ -955,7 +967,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1058,6 +1071,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1079,21 +1093,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1106,6 +1137,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1412,6 +1444,9 @@ const ( SizeofTpacketHdr = 0x18 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2028,3 +2063,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index 2d3f591129..011be86bae 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -577,6 +577,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -642,6 +643,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -953,7 +965,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1056,6 +1069,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1077,21 +1091,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1104,6 +1135,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1409,6 +1441,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2025,3 +2060,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index 5fb57ff2a3..8163445163 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -577,6 +577,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -642,6 +643,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -953,7 +965,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1056,6 +1069,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1077,21 +1091,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1104,6 +1135,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1409,6 +1441,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2025,3 +2060,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index b46b26f6ce..4ecf7a8c77 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -578,6 +578,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -643,6 +644,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x8 @@ -955,7 +967,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1058,6 +1071,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1079,21 +1093,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1106,6 +1137,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1412,6 +1444,9 @@ const ( SizeofTpacketHdr = 0x18 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2028,3 +2063,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index e14e3c90ab..ea817bafba 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -578,6 +578,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -643,6 +644,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -961,7 +973,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1064,6 +1077,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1085,21 +1099,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1112,6 +1143,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1417,6 +1449,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2033,3 +2068,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 2332e8fd12..192ea3b105 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -578,6 +578,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -643,6 +644,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -961,7 +973,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1064,6 +1077,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1085,21 +1099,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1112,6 +1143,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1417,6 +1449,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2033,3 +2068,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index efec4f8193..673e5e7919 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -577,6 +577,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -642,6 +643,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -978,7 +990,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1081,6 +1094,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1102,21 +1116,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1129,6 +1160,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1434,6 +1466,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2050,3 +2085,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index 71cc23f2e1..faafcddfcc 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -576,6 +576,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -641,6 +642,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -974,7 +986,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1077,6 +1090,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1098,21 +1112,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1125,6 +1156,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1431,6 +1463,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2047,3 +2082,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index 48805ba195..392dd7375c 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -580,6 +580,7 @@ const ( SizeofIfAddrmsg = 0x8 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 + SizeofNdUseroptmsg = 0x10 ) type NlMsghdr struct { @@ -645,6 +646,17 @@ type RtNexthop struct { Ifindex int32 } +type NdUseroptmsg struct { + Family uint8 + Pad1 uint8 + Opts_len uint16 + Ifindex int32 + Icmp_type uint8 + Icmp_code uint8 + Pad2 uint16 + Pad3 uint32 +} + const ( SizeofSockFilter = 0x8 SizeofSockFprog = 0x10 @@ -956,7 +968,8 @@ type PerfEventAttr struct { Clockid int32 Sample_regs_intr uint64 Aux_watermark uint32 - _ uint32 + Sample_max_stack uint16 + _ uint16 } type PerfEventMmapPage struct { @@ -1059,6 +1072,7 @@ const ( PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 PERF_COUNT_SW_EMULATION_FAULTS = 0x8 PERF_COUNT_SW_DUMMY = 0x9 + PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_SAMPLE_IP = 0x1 PERF_SAMPLE_TID = 0x2 @@ -1080,21 +1094,38 @@ const ( PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + PERF_SAMPLE_BRANCH_ABORT_TX = 0x80 + PERF_SAMPLE_BRANCH_IN_TX = 0x100 + PERF_SAMPLE_BRANCH_NO_TX = 0x200 + PERF_SAMPLE_BRANCH_COND = 0x400 + PERF_SAMPLE_BRANCH_CALL_STACK = 0x800 + PERF_SAMPLE_BRANCH_IND_JUMP = 0x1000 + PERF_SAMPLE_BRANCH_CALL = 0x2000 + PERF_SAMPLE_BRANCH_NO_FLAGS = 0x4000 + PERF_SAMPLE_BRANCH_NO_CYCLES = 0x8000 + PERF_SAMPLE_BRANCH_TYPE_SAVE = 0x10000 PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 PERF_FORMAT_ID = 0x4 PERF_FORMAT_GROUP = 0x8 - PERF_RECORD_MMAP = 0x1 - PERF_RECORD_LOST = 0x2 - PERF_RECORD_COMM = 0x3 - PERF_RECORD_EXIT = 0x4 - PERF_RECORD_THROTTLE = 0x5 - PERF_RECORD_UNTHROTTLE = 0x6 - PERF_RECORD_FORK = 0x7 - PERF_RECORD_READ = 0x8 - PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + PERF_RECORD_MMAP2 = 0xa + PERF_RECORD_AUX = 0xb + PERF_RECORD_ITRACE_START = 0xc + PERF_RECORD_LOST_SAMPLES = 0xd + PERF_RECORD_SWITCH = 0xe + PERF_RECORD_SWITCH_CPU_WIDE = 0xf + PERF_RECORD_NAMESPACES = 0x10 PERF_CONTEXT_HV = -0x20 PERF_CONTEXT_KERNEL = -0x80 @@ -1107,6 +1138,7 @@ const ( PERF_FLAG_FD_NO_GROUP = 0x1 PERF_FLAG_FD_OUTPUT = 0x2 PERF_FLAG_PID_CGROUP = 0x4 + PERF_FLAG_FD_CLOEXEC = 0x8 ) const ( @@ -1412,6 +1444,9 @@ const ( SizeofTpacketHdr = 0x20 SizeofTpacket2Hdr = 0x20 SizeofTpacket3Hdr = 0x30 + + SizeofTpacketStats = 0x8 + SizeofTpacketStatsV3 = 0xc ) const ( @@ -2028,3 +2063,18 @@ type SockExtendedErr struct { Info uint32 Data uint32 } + +type FanotifyEventMetadata struct { + Event_len uint32 + Vers uint8 + Reserved uint8 + Metadata_len uint16 + Mask uint64 + Fd int32 + Pid int32 +} + +type FanotifyResponse struct { + Fd int32 + Response uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go index 8b37d83992..900fb44622 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go @@ -558,3 +558,13 @@ type Uvmexp struct { Fpswtch int32 Kmapent int32 } + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go index 6efea46355..028fa78d74 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go @@ -558,3 +558,13 @@ type Uvmexp struct { Fpswtch int32 Kmapent int32 } + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go index 510efc3eaa..b45d5eedff 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go @@ -559,3 +559,13 @@ type Uvmexp struct { Fpswtch int32 Kmapent int32 } + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go index e92c05b213..ba67658db1 100644 --- a/vendor/golang.org/x/sys/windows/dll_windows.go +++ b/vendor/golang.org/x/sys/windows/dll_windows.go @@ -359,11 +359,11 @@ func loadLibraryEx(name string, system bool) (*DLL, error) { // trying to load "foo.dll" out of the system // folder, but LoadLibraryEx doesn't support // that yet on their system, so emulate it. - windir, _ := Getenv("WINDIR") // old var; apparently works on XP - if windir == "" { - return nil, errString("%WINDIR% not defined") + systemdir, err := GetSystemDirectory() + if err != nil { + return nil, err } - loadDLL = windir + "\\System32\\" + name + loadDLL = systemdir + "\\" + name } } h, err := LoadLibraryEx(loadDLL, 0, flags) diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go index 9f946da6fe..da06406c44 100644 --- a/vendor/golang.org/x/sys/windows/security_windows.go +++ b/vendor/golang.org/x/sys/windows/security_windows.go @@ -169,6 +169,7 @@ const ( //sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid //sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid //sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid +//sys createWellKnownSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID, sid *SID, sizeSid *uint32) (err error) = advapi32.CreateWellKnownSid //sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid //sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid @@ -286,6 +287,158 @@ func (sid *SID) LookupAccount(system string) (account, domain string, accType ui } } +// Various types of pre-specified sids that can be synthesized at runtime. +type WELL_KNOWN_SID_TYPE uint32 + +const ( + WinNullSid = 0 + WinWorldSid = 1 + WinLocalSid = 2 + WinCreatorOwnerSid = 3 + WinCreatorGroupSid = 4 + WinCreatorOwnerServerSid = 5 + WinCreatorGroupServerSid = 6 + WinNtAuthoritySid = 7 + WinDialupSid = 8 + WinNetworkSid = 9 + WinBatchSid = 10 + WinInteractiveSid = 11 + WinServiceSid = 12 + WinAnonymousSid = 13 + WinProxySid = 14 + WinEnterpriseControllersSid = 15 + WinSelfSid = 16 + WinAuthenticatedUserSid = 17 + WinRestrictedCodeSid = 18 + WinTerminalServerSid = 19 + WinRemoteLogonIdSid = 20 + WinLogonIdsSid = 21 + WinLocalSystemSid = 22 + WinLocalServiceSid = 23 + WinNetworkServiceSid = 24 + WinBuiltinDomainSid = 25 + WinBuiltinAdministratorsSid = 26 + WinBuiltinUsersSid = 27 + WinBuiltinGuestsSid = 28 + WinBuiltinPowerUsersSid = 29 + WinBuiltinAccountOperatorsSid = 30 + WinBuiltinSystemOperatorsSid = 31 + WinBuiltinPrintOperatorsSid = 32 + WinBuiltinBackupOperatorsSid = 33 + WinBuiltinReplicatorSid = 34 + WinBuiltinPreWindows2000CompatibleAccessSid = 35 + WinBuiltinRemoteDesktopUsersSid = 36 + WinBuiltinNetworkConfigurationOperatorsSid = 37 + WinAccountAdministratorSid = 38 + WinAccountGuestSid = 39 + WinAccountKrbtgtSid = 40 + WinAccountDomainAdminsSid = 41 + WinAccountDomainUsersSid = 42 + WinAccountDomainGuestsSid = 43 + WinAccountComputersSid = 44 + WinAccountControllersSid = 45 + WinAccountCertAdminsSid = 46 + WinAccountSchemaAdminsSid = 47 + WinAccountEnterpriseAdminsSid = 48 + WinAccountPolicyAdminsSid = 49 + WinAccountRasAndIasServersSid = 50 + WinNTLMAuthenticationSid = 51 + WinDigestAuthenticationSid = 52 + WinSChannelAuthenticationSid = 53 + WinThisOrganizationSid = 54 + WinOtherOrganizationSid = 55 + WinBuiltinIncomingForestTrustBuildersSid = 56 + WinBuiltinPerfMonitoringUsersSid = 57 + WinBuiltinPerfLoggingUsersSid = 58 + WinBuiltinAuthorizationAccessSid = 59 + WinBuiltinTerminalServerLicenseServersSid = 60 + WinBuiltinDCOMUsersSid = 61 + WinBuiltinIUsersSid = 62 + WinIUserSid = 63 + WinBuiltinCryptoOperatorsSid = 64 + WinUntrustedLabelSid = 65 + WinLowLabelSid = 66 + WinMediumLabelSid = 67 + WinHighLabelSid = 68 + WinSystemLabelSid = 69 + WinWriteRestrictedCodeSid = 70 + WinCreatorOwnerRightsSid = 71 + WinCacheablePrincipalsGroupSid = 72 + WinNonCacheablePrincipalsGroupSid = 73 + WinEnterpriseReadonlyControllersSid = 74 + WinAccountReadonlyControllersSid = 75 + WinBuiltinEventLogReadersGroup = 76 + WinNewEnterpriseReadonlyControllersSid = 77 + WinBuiltinCertSvcDComAccessGroup = 78 + WinMediumPlusLabelSid = 79 + WinLocalLogonSid = 80 + WinConsoleLogonSid = 81 + WinThisOrganizationCertificateSid = 82 + WinApplicationPackageAuthoritySid = 83 + WinBuiltinAnyPackageSid = 84 + WinCapabilityInternetClientSid = 85 + WinCapabilityInternetClientServerSid = 86 + WinCapabilityPrivateNetworkClientServerSid = 87 + WinCapabilityPicturesLibrarySid = 88 + WinCapabilityVideosLibrarySid = 89 + WinCapabilityMusicLibrarySid = 90 + WinCapabilityDocumentsLibrarySid = 91 + WinCapabilitySharedUserCertificatesSid = 92 + WinCapabilityEnterpriseAuthenticationSid = 93 + WinCapabilityRemovableStorageSid = 94 + WinBuiltinRDSRemoteAccessServersSid = 95 + WinBuiltinRDSEndpointServersSid = 96 + WinBuiltinRDSManagementServersSid = 97 + WinUserModeDriversSid = 98 + WinBuiltinHyperVAdminsSid = 99 + WinAccountCloneableControllersSid = 100 + WinBuiltinAccessControlAssistanceOperatorsSid = 101 + WinBuiltinRemoteManagementUsersSid = 102 + WinAuthenticationAuthorityAssertedSid = 103 + WinAuthenticationServiceAssertedSid = 104 + WinLocalAccountSid = 105 + WinLocalAccountAndAdministratorSid = 106 + WinAccountProtectedUsersSid = 107 + WinCapabilityAppointmentsSid = 108 + WinCapabilityContactsSid = 109 + WinAccountDefaultSystemManagedSid = 110 + WinBuiltinDefaultSystemManagedGroupSid = 111 + WinBuiltinStorageReplicaAdminsSid = 112 + WinAccountKeyAdminsSid = 113 + WinAccountEnterpriseKeyAdminsSid = 114 + WinAuthenticationKeyTrustSid = 115 + WinAuthenticationKeyPropertyMFASid = 116 + WinAuthenticationKeyPropertyAttestationSid = 117 + WinAuthenticationFreshKeyAuthSid = 118 + WinBuiltinDeviceOwnersSid = 119 +) + +// Creates a sid for a well-known predefined alias, generally using the constants of the form +// Win*Sid, for the local machine. +func CreateWellKnownSid(sidType WELL_KNOWN_SID_TYPE) (*SID, error) { + return CreateWellKnownDomainSid(sidType, nil) +} + +// Creates a sid for a well-known predefined alias, generally using the constants of the form +// Win*Sid, for the domain specified by the domainSid parameter. +func CreateWellKnownDomainSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID) (*SID, error) { + n := uint32(50) + for { + b := make([]byte, n) + sid := (*SID)(unsafe.Pointer(&b[0])) + err := createWellKnownSid(sidType, domainSid, sid, &n) + if err == nil { + return sid, nil + } + if err != ERROR_INSUFFICIENT_BUFFER { + return nil, err + } + if n <= uint32(len(b)) { + return nil, err + } + } +} + const ( // do not reorder TOKEN_ASSIGN_PRIMARY = 1 << iota @@ -372,6 +525,7 @@ type Tokengroups struct { //sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken //sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation //sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW +//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW // An access token contains the security information for a logon session. // The system creates an access token when a user logs on, and every @@ -468,6 +622,23 @@ func (t Token) GetUserProfileDirectory() (string, error) { } } +// GetSystemDirectory retrieves path to current location of the system +// directory, which is typically, though not always, C:\Windows\System32. +func GetSystemDirectory() (string, error) { + n := uint32(MAX_PATH) + for { + b := make([]uint16, n) + l, e := getSystemDirectory(&b[0], n) + if e != nil { + return "", e + } + if l <= n { + return UTF16ToString(b[:l]), nil + } + n = l + } +} + // IsMember reports whether the access token t is a member of the provided SID. func (t Token) IsMember(sid *SID) (bool, error) { var b int32 diff --git a/vendor/golang.org/x/sys/windows/svc/service.go b/vendor/golang.org/x/sys/windows/svc/service.go index cda26b54b3..38b147d5fe 100644 --- a/vendor/golang.org/x/sys/windows/svc/service.go +++ b/vendor/golang.org/x/sys/windows/svc/service.go @@ -80,6 +80,7 @@ type ChangeRequest struct { EventType uint32 EventData uintptr CurrentStatus Status + Context uintptr } // Handler is the interface that must be implemented to build Windows service. @@ -114,19 +115,18 @@ var ( ) func init() { - k := syscall.MustLoadDLL("kernel32.dll") - cSetEvent = k.MustFindProc("SetEvent").Addr() - cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr() - a := syscall.MustLoadDLL("advapi32.dll") - cRegisterServiceCtrlHandlerExW = a.MustFindProc("RegisterServiceCtrlHandlerExW").Addr() + k := windows.NewLazySystemDLL("kernel32.dll") + cSetEvent = k.NewProc("SetEvent").Addr() + cWaitForSingleObject = k.NewProc("WaitForSingleObject").Addr() + a := windows.NewLazySystemDLL("advapi32.dll") + cRegisterServiceCtrlHandlerExW = a.NewProc("RegisterServiceCtrlHandlerExW").Addr() } -// The HandlerEx prototype also has a context pointer but since we don't use -// it at start-up time we don't have to pass it over either. type ctlEvent struct { cmd Cmd eventType uint32 eventData uintptr + context uintptr errno uint32 } @@ -238,13 +238,12 @@ func (s *service) run() { exitFromHandler <- exitCode{ss, errno} }() - status := Status{State: Stopped} ec := exitCode{isSvcSpecific: true, errno: 0} + outcr := ChangeRequest{ + CurrentStatus: Status{State: Stopped}, + } var outch chan ChangeRequest inch := s.c - var cmd Cmd - var evtype uint32 - var evdata uintptr loop: for { select { @@ -255,10 +254,11 @@ loop: } inch = nil outch = cmdsToHandler - cmd = r.cmd - evtype = r.eventType - evdata = r.eventData - case outch <- ChangeRequest{cmd, evtype, evdata, status}: + outcr.Cmd = r.cmd + outcr.EventType = r.eventType + outcr.EventData = r.eventData + outcr.Context = r.context + case outch <- outcr: inch = s.c outch = nil case c := <-changesFromHandler: @@ -271,7 +271,7 @@ loop: } break loop } - status = c + outcr.CurrentStatus = c case ec = <-exitFromHandler: break loop } @@ -315,8 +315,8 @@ func Run(name string, handler Handler) error { return err } - ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr { - e := ctlEvent{cmd: Cmd(ctl), eventType: evtype, eventData: evdata} + ctlHandler := func(ctl, evtype, evdata, context uintptr) uintptr { + e := ctlEvent{cmd: Cmd(ctl), eventType: uint32(evtype), eventData: evdata, context: context} // We assume that this callback function is running on // the same thread as Run. Nowhere in MS documentation // I could find statement to guarantee that. So putting diff --git a/vendor/golang.org/x/sys/windows/svc/sys_386.s b/vendor/golang.org/x/sys/windows/svc/sys_386.s index 2c82a9d91d..c8a583d737 100644 --- a/vendor/golang.org/x/sys/windows/svc/sys_386.s +++ b/vendor/golang.org/x/sys/windows/svc/sys_386.s @@ -22,7 +22,8 @@ TEXT ·servicemain(SB),7,$0 MOVL AX, (SP) MOVL $·servicectlhandler(SB), AX MOVL AX, 4(SP) - MOVL $0, 8(SP) + // Set context to 123456 to test issue #25660. + MOVL $123456, 8(SP) MOVL ·cRegisterServiceCtrlHandlerExW(SB), AX MOVL SP, BP CALL AX diff --git a/vendor/golang.org/x/sys/windows/svc/sys_amd64.s b/vendor/golang.org/x/sys/windows/svc/sys_amd64.s index bde25e9c48..2f7609c5b6 100644 --- a/vendor/golang.org/x/sys/windows/svc/sys_amd64.s +++ b/vendor/golang.org/x/sys/windows/svc/sys_amd64.s @@ -14,6 +14,8 @@ TEXT ·servicemain(SB),7,$0 MOVQ ·sName(SB), CX MOVQ $·servicectlhandler(SB), DX // BUG(pastarmovj): Figure out a way to pass in context in R8. + // Set context to 123456 to test issue #25660. + MOVQ $123456, R8 MOVQ ·cRegisterServiceCtrlHandlerExW(SB), AX CALL AX CMPQ AX, $0 diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index f72fa55f3e..7aff0d0225 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -137,6 +137,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW //sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) //sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) +//sys GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) //sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff] //sys CloseHandle(handle Handle) (err error) //sys GetStdHandle(stdhandle uint32) (handle Handle, err error) [failretval==InvalidHandle] diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index 141ca81bd7..bbf19f0dcd 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -126,9 +126,19 @@ const ( OPEN_ALWAYS = 4 TRUNCATE_EXISTING = 5 - FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 - FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 - FILE_FLAG_OVERLAPPED = 0x40000000 + FILE_FLAG_OPEN_REQUIRING_OPLOCK = 0x00040000 + FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000 + FILE_FLAG_OPEN_NO_RECALL = 0x00100000 + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 + FILE_FLAG_SESSION_AWARE = 0x00800000 + FILE_FLAG_POSIX_SEMANTICS = 0x01000000 + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 + FILE_FLAG_DELETE_ON_CLOSE = 0x04000000 + FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000 + FILE_FLAG_RANDOM_ACCESS = 0x10000000 + FILE_FLAG_NO_BUFFERING = 0x20000000 + FILE_FLAG_OVERLAPPED = 0x40000000 + FILE_FLAG_WRITE_THROUGH = 0x80000000 HANDLE_FLAG_INHERIT = 0x00000001 STARTF_USESTDHANDLES = 0x00000100 diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index e4b54e2d92..eb9f06296e 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -77,6 +77,7 @@ var ( procCreateFileW = modkernel32.NewProc("CreateFileW") procReadFile = modkernel32.NewProc("ReadFile") procWriteFile = modkernel32.NewProc("WriteFile") + procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") procSetFilePointer = modkernel32.NewProc("SetFilePointer") procCloseHandle = modkernel32.NewProc("CloseHandle") procGetStdHandle = modkernel32.NewProc("GetStdHandle") @@ -246,12 +247,14 @@ var ( procGetLengthSid = modadvapi32.NewProc("GetLengthSid") procCopySid = modadvapi32.NewProc("CopySid") procAllocateAndInitializeSid = modadvapi32.NewProc("AllocateAndInitializeSid") + procCreateWellKnownSid = modadvapi32.NewProc("CreateWellKnownSid") procFreeSid = modadvapi32.NewProc("FreeSid") procEqualSid = modadvapi32.NewProc("EqualSid") procCheckTokenMembership = modadvapi32.NewProc("CheckTokenMembership") procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") + procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW") ) func RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) { @@ -652,6 +655,24 @@ func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) return } +func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) { + var _p0 uint32 + if wait { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(done)), uintptr(_p0), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) { r0, _, e1 := syscall.Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) newlowoffset = uint32(r0) @@ -2653,6 +2674,18 @@ func AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, s return } +func createWellKnownSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID, sid *SID, sizeSid *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procCreateWellKnownSid.Addr(), 4, uintptr(sidType), uintptr(unsafe.Pointer(domainSid)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sizeSid)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func FreeSid(sid *SID) (err error) { r1, _, e1 := syscall.Syscall(procFreeSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) if r1 != 0 { @@ -2718,3 +2751,16 @@ func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) { } return } + +func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0) + len = uint32(r0) + if len == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/gopkg.in/ini.v1/.travis.yml b/vendor/gopkg.in/ini.v1/.travis.yml index b097527e1a..c8ea49ccc6 100644 --- a/vendor/gopkg.in/ini.v1/.travis.yml +++ b/vendor/gopkg.in/ini.v1/.travis.yml @@ -1,15 +1,17 @@ sudo: false language: go go: - - 1.5.x - 1.6.x - 1.7.x - 1.8.x - 1.9.x + - 1.10.x + - 1.11.x -script: +script: - go get golang.org/x/tools/cmd/cover - go get github.com/smartystreets/goconvey - mkdir -p $HOME/gopath/src/gopkg.in - ln -s $HOME/gopath/src/github.com/go-ini/ini $HOME/gopath/src/gopkg.in/ini.v1 + - cd $HOME/gopath/src/gopkg.in/ini.v1 - go test -v -cover -race diff --git a/vendor/gopkg.in/ini.v1/Makefile b/vendor/gopkg.in/ini.v1/Makefile index 1316911d2d..af27ff0768 100644 --- a/vendor/gopkg.in/ini.v1/Makefile +++ b/vendor/gopkg.in/ini.v1/Makefile @@ -12,4 +12,4 @@ vet: go vet coverage: - go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out \ No newline at end of file + go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out diff --git a/vendor/gopkg.in/ini.v1/README.md b/vendor/gopkg.in/ini.v1/README.md index f4ff27cd30..ae4dfc3a5a 100644 --- a/vendor/gopkg.in/ini.v1/README.md +++ b/vendor/gopkg.in/ini.v1/README.md @@ -1,15 +1,13 @@ -INI [![Build Status](https://travis-ci.org/go-ini/ini.svg?branch=master)](https://travis-ci.org/go-ini/ini) [![Sourcegraph](https://sourcegraph.com/github.com/go-ini/ini/-/badge.svg)](https://sourcegraph.com/github.com/go-ini/ini?badge) +INI [![Build Status](https://travis-ci.org/go-ini/ini.svg?branch=master)](https://travis-ci.org/go-ini/ini) [![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg)](https://sourcegraph.com/github.com/go-ini/ini) === ![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) Package ini provides INI file read and write functionality in Go. -[简体中文](README_ZH.md) +## Features -## Feature - -- Load multiple data sources(`[]byte`, file and `io.ReadCloser`) with overwrites. +- Load from multiple data sources(`[]byte`, file and `io.ReadCloser`) with overwrites. - Read with recursion values. - Read with parent-child sections. - Read with auto-increment key names. @@ -22,741 +20,26 @@ Package ini provides INI file read and write functionality in Go. ## Installation +The minimum requirement of Go is **1.6**. + To use a tagged revision: - go get gopkg.in/ini.v1 +```sh +$ go get gopkg.in/ini.v1 +``` To use with latest changes: - go get github.com/go-ini/ini +```sh +$ go get github.com/go-ini/ini +``` Please add `-u` flag to update in the future. -### Testing - -If you want to test on your machine, please apply `-t` flag: - - go get -t gopkg.in/ini.v1 - -Please add `-u` flag to update in the future. - -## Getting Started - -### Loading from data sources - -A **Data Source** is either raw data in type `[]byte`, a file name with type `string` or `io.ReadCloser`. You can load **as many data sources as you want**. Passing other types will simply return an error. - -```go -cfg, err := ini.Load([]byte("raw data"), "filename", ioutil.NopCloser(bytes.NewReader([]byte("some other data")))) -``` - -Or start with an empty object: - -```go -cfg := ini.Empty() -``` - -When you cannot decide how many data sources to load at the beginning, you will still be able to **Append()** them later. - -```go -err := cfg.Append("other file", []byte("other raw data")) -``` - -If you have a list of files with possibilities that some of them may not available at the time, and you don't know exactly which ones, you can use `LooseLoad` to ignore nonexistent files without returning error. - -```go -cfg, err := ini.LooseLoad("filename", "filename_404") -``` - -The cool thing is, whenever the file is available to load while you're calling `Reload` method, it will be counted as usual. - -#### Ignore cases of key name - -When you do not care about cases of section and key names, you can use `InsensitiveLoad` to force all names to be lowercased while parsing. - -```go -cfg, err := ini.InsensitiveLoad("filename") -//... - -// sec1 and sec2 are the exactly same section object -sec1, err := cfg.GetSection("Section") -sec2, err := cfg.GetSection("SecTIOn") - -// key1 and key2 are the exactly same key object -key1, err := sec1.GetKey("Key") -key2, err := sec2.GetKey("KeY") -``` - -#### MySQL-like boolean key - -MySQL's configuration allows a key without value as follows: - -```ini -[mysqld] -... -skip-host-cache -skip-name-resolve -``` - -By default, this is considered as missing value. But if you know you're going to deal with those cases, you can assign advanced load options: - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf")) -``` - -The value of those keys are always `true`, and when you save to a file, it will keep in the same foramt as you read. - -To generate such keys in your program, you could use `NewBooleanKey`: - -```go -key, err := sec.NewBooleanKey("skip-host-cache") -``` - -#### Comment - -Take care that following format will be treated as comment: - -1. Line begins with `#` or `;` -2. Words after `#` or `;` -3. Words after section name (i.e words after `[some section name]`) - -If you want to save a value with `#` or `;`, please quote them with ``` ` ``` or ``` """ ```. - -Alternatively, you can use following `LoadOptions` to completely ignore inline comments: - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini")) -``` - -### Working with sections - -To get a section, you would need to: - -```go -section, err := cfg.GetSection("section name") -``` - -For a shortcut for default section, just give an empty string as name: - -```go -section, err := cfg.GetSection("") -``` - -When you're pretty sure the section exists, following code could make your life easier: - -```go -section := cfg.Section("section name") -``` - -What happens when the section somehow does not exist? Don't panic, it automatically creates and returns a new section to you. - -To create a new section: - -```go -err := cfg.NewSection("new section") -``` - -To get a list of sections or section names: - -```go -sections := cfg.Sections() -names := cfg.SectionStrings() -``` - -### Working with keys - -To get a key under a section: - -```go -key, err := cfg.Section("").GetKey("key name") -``` - -Same rule applies to key operations: - -```go -key := cfg.Section("").Key("key name") -``` - -To check if a key exists: - -```go -yes := cfg.Section("").HasKey("key name") -``` - -To create a new key: - -```go -err := cfg.Section("").NewKey("name", "value") -``` - -To get a list of keys or key names: - -```go -keys := cfg.Section("").Keys() -names := cfg.Section("").KeyStrings() -``` - -To get a clone hash of keys and corresponding values: - -```go -hash := cfg.Section("").KeysHash() -``` - -### Working with values - -To get a string value: - -```go -val := cfg.Section("").Key("key name").String() -``` - -To validate key value on the fly: - -```go -val := cfg.Section("").Key("key name").Validate(func(in string) string { - if len(in) == 0 { - return "default" - } - return in -}) -``` - -If you do not want any auto-transformation (such as recursive read) for the values, you can get raw value directly (this way you get much better performance): - -```go -val := cfg.Section("").Key("key name").Value() -``` - -To check if raw value exists: - -```go -yes := cfg.Section("").HasValue("test value") -``` - -To get value with types: - -```go -// For boolean values: -// true when value is: 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On -// false when value is: 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off -v, err = cfg.Section("").Key("BOOL").Bool() -v, err = cfg.Section("").Key("FLOAT64").Float64() -v, err = cfg.Section("").Key("INT").Int() -v, err = cfg.Section("").Key("INT64").Int64() -v, err = cfg.Section("").Key("UINT").Uint() -v, err = cfg.Section("").Key("UINT64").Uint64() -v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) -v, err = cfg.Section("").Key("TIME").Time() // RFC3339 - -v = cfg.Section("").Key("BOOL").MustBool() -v = cfg.Section("").Key("FLOAT64").MustFloat64() -v = cfg.Section("").Key("INT").MustInt() -v = cfg.Section("").Key("INT64").MustInt64() -v = cfg.Section("").Key("UINT").MustUint() -v = cfg.Section("").Key("UINT64").MustUint64() -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) -v = cfg.Section("").Key("TIME").MustTime() // RFC3339 - -// Methods start with Must also accept one argument for default value -// when key not found or fail to parse value to given type. -// Except method MustString, which you have to pass a default value. - -v = cfg.Section("").Key("String").MustString("default") -v = cfg.Section("").Key("BOOL").MustBool(true) -v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) -v = cfg.Section("").Key("INT").MustInt(10) -v = cfg.Section("").Key("INT64").MustInt64(99) -v = cfg.Section("").Key("UINT").MustUint(3) -v = cfg.Section("").Key("UINT64").MustUint64(6) -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) -v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 -``` - -What if my value is three-line long? - -```ini -[advance] -ADDRESS = """404 road, -NotFound, State, 5000 -Earth""" -``` - -Not a problem! - -```go -cfg.Section("advance").Key("ADDRESS").String() - -/* --- start --- -404 road, -NotFound, State, 5000 -Earth ------- end --- */ -``` - -That's cool, how about continuation lines? - -```ini -[advance] -two_lines = how about \ - continuation lines? -lots_of_lines = 1 \ - 2 \ - 3 \ - 4 -``` - -Piece of cake! - -```go -cfg.Section("advance").Key("two_lines").String() // how about continuation lines? -cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 -``` - -Well, I hate continuation lines, how do I disable that? - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{ - IgnoreContinuation: true, -}, "filename") -``` - -Holy crap! - -Note that single quotes around values will be stripped: - -```ini -foo = "some value" // foo: some value -bar = 'some value' // bar: some value -``` - -Sometimes you downloaded file from [Crowdin](https://crowdin.com/) has values like the following (value is surrounded by double quotes and quotes in the value are escaped): - -```ini -create_repo="created repository %s" -``` - -How do you transform this to regular format automatically? - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini")) -cfg.Section("").Key("create_repo").String() -// You got: created repository %s -``` - -That's all? Hmm, no. - -#### Helper methods of working with values - -To get value with given candidates: - -```go -v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) -v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) -v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) -v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) -v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) -v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) -v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) -v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 -``` - -Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates. - -To validate value in a given range: - -```go -vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) -vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) -vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) -vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) -vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) -vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) -vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 -``` - -##### Auto-split values into a slice - -To use zero value of type for invalid inputs: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] -vals = cfg.Section("").Key("STRINGS").Strings(",") -vals = cfg.Section("").Key("FLOAT64S").Float64s(",") -vals = cfg.Section("").Key("INTS").Ints(",") -vals = cfg.Section("").Key("INT64S").Int64s(",") -vals = cfg.Section("").Key("UINTS").Uints(",") -vals = cfg.Section("").Key("UINT64S").Uint64s(",") -vals = cfg.Section("").Key("TIMES").Times(",") -``` - -To exclude invalid values out of result slice: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [2.2] -vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") -vals = cfg.Section("").Key("INTS").ValidInts(",") -vals = cfg.Section("").Key("INT64S").ValidInt64s(",") -vals = cfg.Section("").Key("UINTS").ValidUints(",") -vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") -vals = cfg.Section("").Key("TIMES").ValidTimes(",") -``` - -Or to return nothing but error when have invalid inputs: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> error -vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") -vals = cfg.Section("").Key("INTS").StrictInts(",") -vals = cfg.Section("").Key("INT64S").StrictInt64s(",") -vals = cfg.Section("").Key("UINTS").StrictUints(",") -vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") -vals = cfg.Section("").Key("TIMES").StrictTimes(",") -``` - -### Save your configuration - -Finally, it's time to save your configuration to somewhere. - -A typical way to save configuration is writing it to a file: - -```go -// ... -err = cfg.SaveTo("my.ini") -err = cfg.SaveToIndent("my.ini", "\t") -``` - -Another way to save is writing to a `io.Writer` interface: - -```go -// ... -cfg.WriteTo(writer) -cfg.WriteToIndent(writer, "\t") -``` - -By default, spaces are used to align "=" sign between key and values, to disable that: - -```go -ini.PrettyFormat = false -``` - -## Advanced Usage - -### Recursive Values - -For all value of keys, there is a special syntax `%()s`, where `` is the key name in same section or default section, and `%()s` will be replaced by corresponding value(empty string if key not found). You can use this syntax at most 99 level of recursions. - -```ini -NAME = ini - -[author] -NAME = Unknwon -GITHUB = https://github.com/%(NAME)s - -[package] -FULL_NAME = github.com/go-ini/%(NAME)s -``` - -```go -cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon -cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini -``` - -### Parent-child Sections - -You can use `.` in section name to indicate parent-child relationship between two or more sections. If the key not found in the child section, library will try again on its parent section until there is no parent section. - -```ini -NAME = ini -VERSION = v1 -IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s - -[package] -CLONE_URL = https://%(IMPORT_PATH)s - -[package.sub] -``` - -```go -cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 -``` - -#### Retrieve parent keys available to a child section - -```go -cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] -``` - -### Unparseable Sections - -Sometimes, you have sections that do not contain key-value pairs but raw content, to handle such case, you can use `LoadOptions.UnparsableSections`: - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS] -<1> This slide has the fuel listed in the wrong units `)) - -body := cfg.Section("COMMENTS").Body() - -/* --- start --- -<1> This slide has the fuel listed in the wrong units ------- end --- */ -``` - -### Auto-increment Key Names - -If key name is `-` in data source, then it would be seen as special syntax for auto-increment key name start from 1, and every section is independent on counter. - -```ini -[features] --: Support read/write comments of keys and sections --: Support auto-increment of key names --: Support load multiple files to overwrite key values -``` - -```go -cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} -``` - -### Map To Struct - -Want more objective way to play with INI? Cool. - -```ini -Name = Unknwon -age = 21 -Male = true -Born = 1993-01-01T20:17:05Z - -[Note] -Content = Hi is a good man! -Cities = HangZhou, Boston -``` - -```go -type Note struct { - Content string - Cities []string -} - -type Person struct { - Name string - Age int `ini:"age"` - Male bool - Born time.Time - Note - Created time.Time `ini:"-"` -} - -func main() { - cfg, err := ini.Load("path/to/ini") - // ... - p := new(Person) - err = cfg.MapTo(p) - // ... - - // Things can be simpler. - err = ini.MapTo(p, "path/to/ini") - // ... - - // Just map a section? Fine. - n := new(Note) - err = cfg.Section("Note").MapTo(n) - // ... -} -``` - -Can I have default value for field? Absolutely. - -Assign it before you map to struct. It will keep the value as it is if the key is not presented or got wrong type. - -```go -// ... -p := &Person{ - Name: "Joe", -} -// ... -``` - -It's really cool, but what's the point if you can't give me my file back from struct? - -### Reflect From Struct - -Why not? - -```go -type Embeded struct { - Dates []time.Time `delim:"|" comment:"Time data"` - Places []string `ini:"places,omitempty"` - None []int `ini:",omitempty"` -} - -type Author struct { - Name string `ini:"NAME"` - Male bool - Age int `comment:"Author's age"` - GPA float64 - NeverMind string `ini:"-"` - *Embeded `comment:"Embeded section"` -} - -func main() { - a := &Author{"Unknwon", true, 21, 2.8, "", - &Embeded{ - []time.Time{time.Now(), time.Now()}, - []string{"HangZhou", "Boston"}, - []int{}, - }} - cfg := ini.Empty() - err = ini.ReflectFrom(cfg, a) - // ... -} -``` - -So, what do I get? - -```ini -NAME = Unknwon -Male = true -; Author's age -Age = 21 -GPA = 2.8 - -; Embeded section -[Embeded] -; Time data -Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 -places = HangZhou,Boston -``` - -#### Name Mapper - -To save your time and make your code cleaner, this library supports [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) between struct field and actual section and key name. - -There are 2 built-in name mappers: - -- `AllCapsUnderscore`: it converts to format `ALL_CAPS_UNDERSCORE` then match section or key. -- `TitleUnderscore`: it converts to format `title_underscore` then match section or key. - -To use them: - -```go -type Info struct { - PackageName string -} - -func main() { - err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) - // ... - - cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) - // ... - info := new(Info) - cfg.NameMapper = ini.AllCapsUnderscore - err = cfg.MapTo(info) - // ... -} -``` - -Same rules of name mapper apply to `ini.ReflectFromWithMapper` function. - -#### Value Mapper - -To expand values (e.g. from environment variables), you can use the `ValueMapper` to transform values: - -```go -type Env struct { - Foo string `ini:"foo"` -} - -func main() { - cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") - cfg.ValueMapper = os.ExpandEnv - // ... - env := &Env{} - err = cfg.Section("env").MapTo(env) -} -``` - -This would set the value of `env.Foo` to the value of the environment variable `MY_VAR`. - -#### Other Notes On Map/Reflect - -Any embedded struct is treated as a section by default, and there is no automatic parent-child relations in map/reflect feature: - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child -} - -type Config struct { - City string - Parent -} -``` - -Example configuration: - -```ini -City = Boston - -[Parent] -Name = Unknwon - -[Child] -Age = 21 -``` - -What if, yes, I'm paranoid, I want embedded struct to be in the same section. Well, all roads lead to Rome. - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child `ini:"Parent"` -} - -type Config struct { - City string - Parent -} -``` - -Example configuration: - -```ini -City = Boston - -[Parent] -Name = Unknwon -Age = 21 -``` - ## Getting Help +- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) - [API Documentation](https://gowalker.org/gopkg.in/ini.v1) -- [File An Issue](https://github.com/go-ini/ini/issues/new) - -## FAQs - -### What does `BlockMode` field do? - -By default, library lets you read and write values so we need a locker to make sure your data is safe. But in cases that you are very sure about only reading data through the library, you can set `cfg.BlockMode = false` to speed up read operations about **50-70%** faster. - -### Why another INI library? - -Many people are using my another INI library [goconfig](https://github.com/Unknwon/goconfig), so the reason for this one is I would like to make more Go style code. Also when you set `cfg.BlockMode = false`, this one is about **10-30%** faster. - -To make those changes I have to confirm API broken, so it's safer to keep it in another place and start using `gopkg.in` to version my package at this time.(PS: shorter import path) ## License diff --git a/vendor/gopkg.in/ini.v1/README_ZH.md b/vendor/gopkg.in/ini.v1/README_ZH.md deleted file mode 100644 index 69aefef12e..0000000000 --- a/vendor/gopkg.in/ini.v1/README_ZH.md +++ /dev/null @@ -1,750 +0,0 @@ -本包提供了 Go 语言中读写 INI 文件的功能。 - -## 功能特性 - -- 支持覆盖加载多个数据源(`[]byte`、文件和 `io.ReadCloser`) -- 支持递归读取键值 -- 支持读取父子分区 -- 支持读取自增键名 -- 支持读取多行的键值 -- 支持大量辅助方法 -- 支持在读取时直接转换为 Go 语言类型 -- 支持读取和 **写入** 分区和键的注释 -- 轻松操作分区、键值和注释 -- 在保存文件时分区和键值会保持原有的顺序 - -## 下载安装 - -使用一个特定版本: - - go get gopkg.in/ini.v1 - -使用最新版: - - go get github.com/go-ini/ini - -如需更新请添加 `-u` 选项。 - -### 测试安装 - -如果您想要在自己的机器上运行测试,请使用 `-t` 标记: - - go get -t gopkg.in/ini.v1 - -如需更新请添加 `-u` 选项。 - -## 开始使用 - -### 从数据源加载 - -一个 **数据源** 可以是 `[]byte` 类型的原始数据,`string` 类型的文件路径或 `io.ReadCloser`。您可以加载 **任意多个** 数据源。如果您传递其它类型的数据源,则会直接返回错误。 - -```go -cfg, err := ini.Load([]byte("raw data"), "filename", ioutil.NopCloser(bytes.NewReader([]byte("some other data")))) -``` - -或者从一个空白的文件开始: - -```go -cfg := ini.Empty() -``` - -当您在一开始无法决定需要加载哪些数据源时,仍可以使用 **Append()** 在需要的时候加载它们。 - -```go -err := cfg.Append("other file", []byte("other raw data")) -``` - -当您想要加载一系列文件,但是不能够确定其中哪些文件是不存在的,可以通过调用函数 `LooseLoad` 来忽略它们(`Load` 会因为文件不存在而返回错误): - -```go -cfg, err := ini.LooseLoad("filename", "filename_404") -``` - -更牛逼的是,当那些之前不存在的文件在重新调用 `Reload` 方法的时候突然出现了,那么它们会被正常加载。 - -#### 忽略键名的大小写 - -有时候分区和键的名称大小写混合非常烦人,这个时候就可以通过 `InsensitiveLoad` 将所有分区和键名在读取里强制转换为小写: - -```go -cfg, err := ini.InsensitiveLoad("filename") -//... - -// sec1 和 sec2 指向同一个分区对象 -sec1, err := cfg.GetSection("Section") -sec2, err := cfg.GetSection("SecTIOn") - -// key1 和 key2 指向同一个键对象 -key1, err := sec1.GetKey("Key") -key2, err := sec2.GetKey("KeY") -``` - -#### 类似 MySQL 配置中的布尔值键 - -MySQL 的配置文件中会出现没有具体值的布尔类型的键: - -```ini -[mysqld] -... -skip-host-cache -skip-name-resolve -``` - -默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理: - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf")) -``` - -这些键的值永远为 `true`,且在保存到文件时也只会输出键名。 - -如果您想要通过程序来生成此类键,则可以使用 `NewBooleanKey`: - -```go -key, err := sec.NewBooleanKey("skip-host-cache") -``` - -#### 关于注释 - -下述几种情况的内容将被视为注释: - -1. 所有以 `#` 或 `;` 开头的行 -2. 所有在 `#` 或 `;` 之后的内容 -3. 分区标签后的文字 (即 `[分区名]` 之后的内容) - -如果你希望使用包含 `#` 或 `;` 的值,请使用 ``` ` ``` 或 ``` """ ``` 进行包覆。 - -除此之外,您还可以通过 `LoadOptions` 完全忽略行内注释: - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini")) -``` - -### 操作分区(Section) - -获取指定分区: - -```go -section, err := cfg.GetSection("section name") -``` - -如果您想要获取默认分区,则可以用空字符串代替分区名: - -```go -section, err := cfg.GetSection("") -``` - -当您非常确定某个分区是存在的,可以使用以下简便方法: - -```go -section := cfg.Section("section name") -``` - -如果不小心判断错了,要获取的分区其实是不存在的,那会发生什么呢?没事的,它会自动创建并返回一个对应的分区对象给您。 - -创建一个分区: - -```go -err := cfg.NewSection("new section") -``` - -获取所有分区对象或名称: - -```go -sections := cfg.Sections() -names := cfg.SectionStrings() -``` - -### 操作键(Key) - -获取某个分区下的键: - -```go -key, err := cfg.Section("").GetKey("key name") -``` - -和分区一样,您也可以直接获取键而忽略错误处理: - -```go -key := cfg.Section("").Key("key name") -``` - -判断某个键是否存在: - -```go -yes := cfg.Section("").HasKey("key name") -``` - -创建一个新的键: - -```go -err := cfg.Section("").NewKey("name", "value") -``` - -获取分区下的所有键或键名: - -```go -keys := cfg.Section("").Keys() -names := cfg.Section("").KeyStrings() -``` - -获取分区下的所有键值对的克隆: - -```go -hash := cfg.Section("").KeysHash() -``` - -### 操作键值(Value) - -获取一个类型为字符串(string)的值: - -```go -val := cfg.Section("").Key("key name").String() -``` - -获取值的同时通过自定义函数进行处理验证: - -```go -val := cfg.Section("").Key("key name").Validate(func(in string) string { - if len(in) == 0 { - return "default" - } - return in -}) -``` - -如果您不需要任何对值的自动转变功能(例如递归读取),可以直接获取原值(这种方式性能最佳): - -```go -val := cfg.Section("").Key("key name").Value() -``` - -判断某个原值是否存在: - -```go -yes := cfg.Section("").HasValue("test value") -``` - -获取其它类型的值: - -```go -// 布尔值的规则: -// true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On -// false 当值为:0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off -v, err = cfg.Section("").Key("BOOL").Bool() -v, err = cfg.Section("").Key("FLOAT64").Float64() -v, err = cfg.Section("").Key("INT").Int() -v, err = cfg.Section("").Key("INT64").Int64() -v, err = cfg.Section("").Key("UINT").Uint() -v, err = cfg.Section("").Key("UINT64").Uint64() -v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) -v, err = cfg.Section("").Key("TIME").Time() // RFC3339 - -v = cfg.Section("").Key("BOOL").MustBool() -v = cfg.Section("").Key("FLOAT64").MustFloat64() -v = cfg.Section("").Key("INT").MustInt() -v = cfg.Section("").Key("INT64").MustInt64() -v = cfg.Section("").Key("UINT").MustUint() -v = cfg.Section("").Key("UINT64").MustUint64() -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) -v = cfg.Section("").Key("TIME").MustTime() // RFC3339 - -// 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值, -// 当键不存在或者转换失败时,则会直接返回该默认值。 -// 但是,MustString 方法必须传递一个默认值。 - -v = cfg.Seciont("").Key("String").MustString("default") -v = cfg.Section("").Key("BOOL").MustBool(true) -v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) -v = cfg.Section("").Key("INT").MustInt(10) -v = cfg.Section("").Key("INT64").MustInt64(99) -v = cfg.Section("").Key("UINT").MustUint(3) -v = cfg.Section("").Key("UINT64").MustUint64(6) -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) -v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 -``` - -如果我的值有好多行怎么办? - -```ini -[advance] -ADDRESS = """404 road, -NotFound, State, 5000 -Earth""" -``` - -嗯哼?小 case! - -```go -cfg.Section("advance").Key("ADDRESS").String() - -/* --- start --- -404 road, -NotFound, State, 5000 -Earth ------- end --- */ -``` - -赞爆了!那要是我属于一行的内容写不下想要写到第二行怎么办? - -```ini -[advance] -two_lines = how about \ - continuation lines? -lots_of_lines = 1 \ - 2 \ - 3 \ - 4 -``` - -简直是小菜一碟! - -```go -cfg.Section("advance").Key("two_lines").String() // how about continuation lines? -cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 -``` - -可是我有时候觉得两行连在一起特别没劲,怎么才能不自动连接两行呢? - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{ - IgnoreContinuation: true, -}, "filename") -``` - -哇靠给力啊! - -需要注意的是,值两侧的单引号会被自动剔除: - -```ini -foo = "some value" // foo: some value -bar = 'some value' // bar: some value -``` - -有时您会获得像从 [Crowdin](https://crowdin.com/) 网站下载的文件那样具有特殊格式的值(值使用双引号括起来,内部的双引号被转义): - -```ini -create_repo="创建了仓库 %s" -``` - -那么,怎么自动地将这类值进行处理呢? - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini")) -cfg.Section("").Key("create_repo").String() -// You got: 创建了仓库 %s -``` - -这就是全部了?哈哈,当然不是。 - -#### 操作键值的辅助方法 - -获取键值时设定候选值: - -```go -v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) -v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) -v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) -v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) -v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) -v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) -v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) -v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 -``` - -如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。 - -验证获取的值是否在指定范围内: - -```go -vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) -vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) -vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) -vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) -vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) -vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) -vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 -``` - -##### 自动分割键值到切片(slice) - -当存在无效输入时,使用零值代替: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] -vals = cfg.Section("").Key("STRINGS").Strings(",") -vals = cfg.Section("").Key("FLOAT64S").Float64s(",") -vals = cfg.Section("").Key("INTS").Ints(",") -vals = cfg.Section("").Key("INT64S").Int64s(",") -vals = cfg.Section("").Key("UINTS").Uints(",") -vals = cfg.Section("").Key("UINT64S").Uint64s(",") -vals = cfg.Section("").Key("TIMES").Times(",") -``` - -从结果切片中剔除无效输入: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [2.2] -vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") -vals = cfg.Section("").Key("INTS").ValidInts(",") -vals = cfg.Section("").Key("INT64S").ValidInt64s(",") -vals = cfg.Section("").Key("UINTS").ValidUints(",") -vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") -vals = cfg.Section("").Key("TIMES").ValidTimes(",") -``` - -当存在无效输入时,直接返回错误: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> error -vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") -vals = cfg.Section("").Key("INTS").StrictInts(",") -vals = cfg.Section("").Key("INT64S").StrictInt64s(",") -vals = cfg.Section("").Key("UINTS").StrictUints(",") -vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") -vals = cfg.Section("").Key("TIMES").StrictTimes(",") -``` - -### 保存配置 - -终于到了这个时刻,是时候保存一下配置了。 - -比较原始的做法是输出配置到某个文件: - -```go -// ... -err = cfg.SaveTo("my.ini") -err = cfg.SaveToIndent("my.ini", "\t") -``` - -另一个比较高级的做法是写入到任何实现 `io.Writer` 接口的对象中: - -```go -// ... -cfg.WriteTo(writer) -cfg.WriteToIndent(writer, "\t") -``` - -默认情况下,空格将被用于对齐键值之间的等号以美化输出结果,以下代码可以禁用该功能: - -```go -ini.PrettyFormat = false -``` - -## 高级用法 - -### 递归读取键值 - -在获取所有键值的过程中,特殊语法 `%()s` 会被应用,其中 `` 可以是相同分区或者默认分区下的键名。字符串 `%()s` 会被相应的键值所替代,如果指定的键不存在,则会用空字符串替代。您可以最多使用 99 层的递归嵌套。 - -```ini -NAME = ini - -[author] -NAME = Unknwon -GITHUB = https://github.com/%(NAME)s - -[package] -FULL_NAME = github.com/go-ini/%(NAME)s -``` - -```go -cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon -cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini -``` - -### 读取父子分区 - -您可以在分区名称中使用 `.` 来表示两个或多个分区之间的父子关系。如果某个键在子分区中不存在,则会去它的父分区中再次寻找,直到没有父分区为止。 - -```ini -NAME = ini -VERSION = v1 -IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s - -[package] -CLONE_URL = https://%(IMPORT_PATH)s - -[package.sub] -``` - -```go -cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 -``` - -#### 获取上级父分区下的所有键名 - -```go -cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] -``` - -### 无法解析的分区 - -如果遇到一些比较特殊的分区,它们不包含常见的键值对,而是没有固定格式的纯文本,则可以使用 `LoadOptions.UnparsableSections` 进行处理: - -```go -cfg, err := LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS] -<1> This slide has the fuel listed in the wrong units `)) - -body := cfg.Section("COMMENTS").Body() - -/* --- start --- -<1> This slide has the fuel listed in the wrong units ------- end --- */ -``` - -### 读取自增键名 - -如果数据源中的键名为 `-`,则认为该键使用了自增键名的特殊语法。计数器从 1 开始,并且分区之间是相互独立的。 - -```ini -[features] --: Support read/write comments of keys and sections --: Support auto-increment of key names --: Support load multiple files to overwrite key values -``` - -```go -cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} -``` - -### 映射到结构 - -想要使用更加面向对象的方式玩转 INI 吗?好主意。 - -```ini -Name = Unknwon -age = 21 -Male = true -Born = 1993-01-01T20:17:05Z - -[Note] -Content = Hi is a good man! -Cities = HangZhou, Boston -``` - -```go -type Note struct { - Content string - Cities []string -} - -type Person struct { - Name string - Age int `ini:"age"` - Male bool - Born time.Time - Note - Created time.Time `ini:"-"` -} - -func main() { - cfg, err := ini.Load("path/to/ini") - // ... - p := new(Person) - err = cfg.MapTo(p) - // ... - - // 一切竟可以如此的简单。 - err = ini.MapTo(p, "path/to/ini") - // ... - - // 嗯哼?只需要映射一个分区吗? - n := new(Note) - err = cfg.Section("Note").MapTo(n) - // ... -} -``` - -结构的字段怎么设置默认值呢?很简单,只要在映射之前对指定字段进行赋值就可以了。如果键未找到或者类型错误,该值不会发生改变。 - -```go -// ... -p := &Person{ - Name: "Joe", -} -// ... -``` - -这样玩 INI 真的好酷啊!然而,如果不能还给我原来的配置文件,有什么卵用? - -### 从结构反射 - -可是,我有说不能吗? - -```go -type Embeded struct { - Dates []time.Time `delim:"|" comment:"Time data"` - Places []string `ini:"places,omitempty"` - None []int `ini:",omitempty"` -} - -type Author struct { - Name string `ini:"NAME"` - Male bool - Age int `comment:"Author's age"` - GPA float64 - NeverMind string `ini:"-"` - *Embeded `comment:"Embeded section"` -} - -func main() { - a := &Author{"Unknwon", true, 21, 2.8, "", - &Embeded{ - []time.Time{time.Now(), time.Now()}, - []string{"HangZhou", "Boston"}, - []int{}, - }} - cfg := ini.Empty() - err = ini.ReflectFrom(cfg, a) - // ... -} -``` - -瞧瞧,奇迹发生了。 - -```ini -NAME = Unknwon -Male = true -; Author's age -Age = 21 -GPA = 2.8 - -; Embeded section -[Embeded] -; Time data -Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 -places = HangZhou,Boston -``` - -#### 名称映射器(Name Mapper) - -为了节省您的时间并简化代码,本库支持类型为 [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) 的名称映射器,该映射器负责结构字段名与分区名和键名之间的映射。 - -目前有 2 款内置的映射器: - -- `AllCapsUnderscore`:该映射器将字段名转换至格式 `ALL_CAPS_UNDERSCORE` 后再去匹配分区名和键名。 -- `TitleUnderscore`:该映射器将字段名转换至格式 `title_underscore` 后再去匹配分区名和键名。 - -使用方法: - -```go -type Info struct{ - PackageName string -} - -func main() { - err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) - // ... - - cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) - // ... - info := new(Info) - cfg.NameMapper = ini.AllCapsUnderscore - err = cfg.MapTo(info) - // ... -} -``` - -使用函数 `ini.ReflectFromWithMapper` 时也可应用相同的规则。 - -#### 值映射器(Value Mapper) - -值映射器允许使用一个自定义函数自动展开值的具体内容,例如:运行时获取环境变量: - -```go -type Env struct { - Foo string `ini:"foo"` -} - -func main() { - cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") - cfg.ValueMapper = os.ExpandEnv - // ... - env := &Env{} - err = cfg.Section("env").MapTo(env) -} -``` - -本例中,`env.Foo` 将会是运行时所获取到环境变量 `MY_VAR` 的值。 - -#### 映射/反射的其它说明 - -任何嵌入的结构都会被默认认作一个不同的分区,并且不会自动产生所谓的父子分区关联: - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child -} - -type Config struct { - City string - Parent -} -``` - -示例配置文件: - -```ini -City = Boston - -[Parent] -Name = Unknwon - -[Child] -Age = 21 -``` - -很好,但是,我就是要嵌入结构也在同一个分区。好吧,你爹是李刚! - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child `ini:"Parent"` -} - -type Config struct { - City string - Parent -} -``` - -示例配置文件: - -```ini -City = Boston - -[Parent] -Name = Unknwon -Age = 21 -``` - -## 获取帮助 - -- [API 文档](https://gowalker.org/gopkg.in/ini.v1) -- [创建工单](https://github.com/go-ini/ini/issues/new) - -## 常见问题 - -### 字段 `BlockMode` 是什么? - -默认情况下,本库会在您进行读写操作时采用锁机制来确保数据时间。但在某些情况下,您非常确定只进行读操作。此时,您可以通过设置 `cfg.BlockMode = false` 来将读操作提升大约 **50-70%** 的性能。 - -### 为什么要写另一个 INI 解析库? - -许多人都在使用我的 [goconfig](https://github.com/Unknwon/goconfig) 来完成对 INI 文件的操作,但我希望使用更加 Go 风格的代码。并且当您设置 `cfg.BlockMode = false` 时,会有大约 **10-30%** 的性能提升。 - -为了做出这些改变,我必须对 API 进行破坏,所以新开一个仓库是最安全的做法。除此之外,本库直接使用 `gopkg.in` 来进行版本化发布。(其实真相是导入路径更短了) diff --git a/vendor/gopkg.in/ini.v1/file.go b/vendor/gopkg.in/ini.v1/file.go index 93ac50836c..0ed0eafd02 100644 --- a/vendor/gopkg.in/ini.v1/file.go +++ b/vendor/gopkg.in/ini.v1/file.go @@ -45,6 +45,9 @@ type File struct { // newFile initializes File object with given data sources. func newFile(dataSources []dataSource, opts LoadOptions) *File { + if len(opts.KeyValueDelimiters) == 0 { + opts.KeyValueDelimiters = "=:" + } return &File{ BlockMode: true, dataSources: dataSources, @@ -140,9 +143,14 @@ func (f *File) Section(name string) *Section { // Section returns list of Section. func (f *File) Sections() []*Section { + if f.BlockMode { + f.lock.RLock() + defer f.lock.RUnlock() + } + sections := make([]*Section, len(f.sectionList)) - for i := range f.sectionList { - sections[i] = f.Section(f.sectionList[i]) + for i, name := range f.sectionList { + sections[i] = f.sections[name] } return sections } @@ -222,8 +230,9 @@ func (f *File) Append(source interface{}, others ...interface{}) error { } func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { - equalSign := "=" - if PrettyFormat { + equalSign := DefaultFormatLeft + "=" + DefaultFormatRight + + if PrettyFormat || PrettyEqual { equalSign = " = " } @@ -232,13 +241,18 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { for i, sname := range f.sectionList { sec := f.Section(sname) if len(sec.Comment) > 0 { - if sec.Comment[0] != '#' && sec.Comment[0] != ';' { - sec.Comment = "; " + sec.Comment - } else { - sec.Comment = sec.Comment[:1] + " " + strings.TrimSpace(sec.Comment[1:]) - } - if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil { - return nil, err + // Support multiline comments + lines := strings.Split(sec.Comment, LineBreak) + for i := range lines { + if lines[i][0] != '#' && lines[i][0] != ';' { + lines[i] = "; " + lines[i] + } else { + lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) + } + + if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { + return nil, err + } } } @@ -275,7 +289,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { for _, kname := range sec.keyList { keyLength := len(kname) // First case will surround key by ` and second by """ - if strings.ContainsAny(kname, "\"=:") { + if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) { keyLength += 2 } else if strings.Contains(kname, "`") { keyLength += 6 @@ -295,13 +309,19 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { if len(indent) > 0 && sname != DEFAULT_SECTION { buf.WriteString(indent) } - if key.Comment[0] != '#' && key.Comment[0] != ';' { - key.Comment = "; " + key.Comment - } else { - key.Comment = key.Comment[:1] + " " + strings.TrimSpace(key.Comment[1:]) - } - if _, err := buf.WriteString(key.Comment + LineBreak); err != nil { - return nil, err + + // Support multiline comments + lines := strings.Split(key.Comment, LineBreak) + for i := range lines { + if lines[i][0] != '#' && lines[i][0] != ';' { + lines[i] = "; " + strings.TrimSpace(lines[i]) + } else { + lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) + } + + if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { + return nil, err + } } } @@ -312,7 +332,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { switch { case key.isAutoIncrement: kname = "-" - case strings.ContainsAny(kname, "\"=:"): + case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters): kname = "`" + kname + "`" case strings.Contains(kname, "`"): kname = `"""` + kname + `"""` @@ -345,6 +365,12 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { return nil, err } } + + for _, val := range key.nestedValues { + if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil { + return nil, err + } + } } if PrettySection { diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go index cd7c8a1355..f827a1ef99 100644 --- a/vendor/gopkg.in/ini.v1/ini.go +++ b/vendor/gopkg.in/ini.v1/ini.go @@ -1,3 +1,5 @@ +// +build go1.6 + // Copyright 2014 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may @@ -32,7 +34,7 @@ const ( // Maximum allowed depth when recursively substituing variable names. _DEPTH_VALUES = 99 - _VERSION = "1.31.1" + _VERSION = "1.42.0" ) // Version returns current package version literal. @@ -46,6 +48,10 @@ var ( // at package init time. LineBreak = "\n" + // Place custom spaces when PrettyFormat and PrettyEqual are both disabled + DefaultFormatLeft = "" + DefaultFormatRight = "" + // Variable regexp pattern: %(variable)s varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`) @@ -53,6 +59,9 @@ var ( // or reduce all possible spaces for compact format. PrettyFormat = true + // Place spaces around "=" sign even when PrettyFormat is false + PrettyEqual = false + // Explicitly write DEFAULT section header DefaultHeader = false @@ -129,11 +138,26 @@ type LoadOptions struct { IgnoreContinuation bool // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. IgnoreInlineComment bool + // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs. + SkipUnrecognizableLines bool // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool // AllowShadows indicates whether to keep track of keys with same name under same section. AllowShadows bool + // AllowNestedValues indicates whether to allow AWS-like nested values. + // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values + AllowNestedValues bool + // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values. + // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure + // Relevant quote: Values can also span multiple lines, as long as they are indented deeper + // than the first line of the value. + AllowPythonMultilineValues bool + // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value. + // Docs: https://docs.python.org/2/library/configparser.html + // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names. + // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment. + SpaceBeforeInlineComment bool // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" UnescapeValueDoubleQuotes bool @@ -141,9 +165,13 @@ type LoadOptions struct { // when value is NOT surrounded by any quotes. // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. UnescapeValueCommentSymbols bool - // Some INI formats allow group blocks that store a block of raw content that doesn't otherwise + // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise // conform to key/value pairs. Specify the names of those blocks here. UnparseableSections []string + // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". + KeyValueDelimiters string + // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes). + PreserveSurroundedQuote bool } func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { @@ -184,7 +212,7 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Insensitive: true}, source, others...) } -// InsensitiveLoad has exactly same functionality as Load function +// ShadowLoad has exactly same functionality as Load function // except it allows have shadow keys. func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{AllowShadows: true}, source, others...) diff --git a/vendor/gopkg.in/ini.v1/key.go b/vendor/gopkg.in/ini.v1/key.go index d3eac4776c..0fee0dc7e4 100644 --- a/vendor/gopkg.in/ini.v1/key.go +++ b/vendor/gopkg.in/ini.v1/key.go @@ -34,6 +34,8 @@ type Key struct { isShadow bool shadows []*Key + + nestedValues []string } // newKey simply return a key object with given values. @@ -66,6 +68,22 @@ func (k *Key) AddShadow(val string) error { return k.addShadow(val) } +func (k *Key) addNestedValue(val string) error { + if k.isAutoIncrement || k.isBooleanType { + return errors.New("cannot add nested value to auto-increment or boolean key") + } + + k.nestedValues = append(k.nestedValues, val) + return nil +} + +func (k *Key) AddNestedValue(val string) error { + if !k.s.f.options.AllowNestedValues { + return errors.New("nested value is not allowed") + } + return k.addNestedValue(val) +} + // ValueMapper represents a mapping function for values, e.g. os.ExpandEnv type ValueMapper func(string) string @@ -92,6 +110,12 @@ func (k *Key) ValueWithShadows() []string { return vals } +// NestedValues returns nested values stored in the key. +// It is possible returned value is nil if no nested values stored in the key. +func (k *Key) NestedValues() []string { + return k.nestedValues +} + // transformValue takes a raw value and transforms to its final string. func (k *Key) transformValue(val string) string { if k.s.f.ValueMapper != nil { @@ -109,8 +133,7 @@ func (k *Key) transformValue(val string) string { } // Take off leading '%(' and trailing ')s'. - noption := strings.TrimLeft(vr, "%(") - noption = strings.TrimRight(noption, ")s") + noption := vr[2 : len(vr)-2] // Search in the same section. nk, err := k.s.GetKey(noption) @@ -163,23 +186,24 @@ func (k *Key) Float64() (float64, error) { // Int returns int type value. func (k *Key) Int() (int, error) { - return strconv.Atoi(k.String()) + v, err := strconv.ParseInt(k.String(), 0, 64) + return int(v), err } // Int64 returns int64 type value. func (k *Key) Int64() (int64, error) { - return strconv.ParseInt(k.String(), 10, 64) + return strconv.ParseInt(k.String(), 0, 64) } // Uint returns uint type valued. func (k *Key) Uint() (uint, error) { - u, e := strconv.ParseUint(k.String(), 10, 64) + u, e := strconv.ParseUint(k.String(), 0, 64) return uint(u), e } // Uint64 returns uint64 type value. func (k *Key) Uint64() (uint64, error) { - return strconv.ParseUint(k.String(), 10, 64) + return strconv.ParseUint(k.String(), 0, 64) } // Duration returns time.Duration type value. @@ -644,7 +668,8 @@ func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([] func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { vals := make([]int, 0, len(strs)) for _, str := range strs { - val, err := strconv.Atoi(str) + valInt64, err := strconv.ParseInt(str, 0, 64) + val := int(valInt64) if err != nil && returnOnInvalid { return nil, err } @@ -659,7 +684,7 @@ func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { vals := make([]int64, 0, len(strs)) for _, str := range strs { - val, err := strconv.ParseInt(str, 10, 64) + val, err := strconv.ParseInt(str, 0, 64) if err != nil && returnOnInvalid { return nil, err } @@ -674,7 +699,7 @@ func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]in func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { vals := make([]uint, 0, len(strs)) for _, str := range strs { - val, err := strconv.ParseUint(str, 10, 0) + val, err := strconv.ParseUint(str, 0, 0) if err != nil && returnOnInvalid { return nil, err } @@ -689,7 +714,7 @@ func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uin func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { vals := make([]uint64, 0, len(strs)) for _, str := range strs { - val, err := strconv.ParseUint(str, 10, 64) + val, err := strconv.ParseUint(str, 0, 64) if err != nil && returnOnInvalid { return nil, err } diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/gopkg.in/ini.v1/parser.go index 6bd3cd3401..f20073d1b4 100644 --- a/vendor/gopkg.in/ini.v1/parser.go +++ b/vendor/gopkg.in/ini.v1/parser.go @@ -19,11 +19,14 @@ import ( "bytes" "fmt" "io" + "regexp" "strconv" "strings" "unicode" ) +var pythonMultiline = regexp.MustCompile("^(\\s+)([^\n]+)") + type tokenType int const ( @@ -97,7 +100,7 @@ func cleanComment(in []byte) ([]byte, bool) { return in[i:], true } -func readKeyName(in []byte) (string, int, error) { +func readKeyName(delimiters string, in []byte) (string, int, error) { line := string(in) // Check if key name surrounded by quotes. @@ -124,7 +127,7 @@ func readKeyName(in []byte) (string, int, error) { pos += startIdx // Find key-value delimiter - i := strings.IndexAny(line[pos+startIdx:], "=:") + i := strings.IndexAny(line[pos+startIdx:], delimiters) if i < 0 { return "", -1, ErrDelimiterNotFound{line} } @@ -132,7 +135,7 @@ func readKeyName(in []byte) (string, int, error) { return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil } - endIdx = strings.IndexAny(line, "=:") + endIdx = strings.IndexAny(line, delimiters) if endIdx < 0 { return "", -1, ErrDelimiterNotFound{line} } @@ -194,7 +197,8 @@ func hasSurroundedQuote(in string, quote byte) bool { } func (p *parser) readValue(in []byte, - ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols bool) (string, error) { + parserBufferSize int, + ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols, allowPythonMultilines, spaceBeforeInlineComment, preserveSurroundedQuote bool) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { @@ -224,26 +228,39 @@ func (p *parser) readValue(in []byte, return line[startIdx : pos+startIdx], nil } + lastChar := line[len(line)-1] // Won't be able to reach here if value only contains whitespace line = strings.TrimSpace(line) + trimmedLastChar := line[len(line)-1] // Check continuation lines when desired - if !ignoreContinuation && line[len(line)-1] == '\\' { + if !ignoreContinuation && trimmedLastChar == '\\' { return p.readContinuationLines(line[:len(line)-1]) } // Check if ignore inline comment if !ignoreInlineComment { - i := strings.IndexAny(line, "#;") + var i int + if spaceBeforeInlineComment { + i = strings.Index(line, " #") + if i == -1 { + i = strings.Index(line, " ;") + } + + } else { + i = strings.IndexAny(line, "#;") + } + if i > -1 { p.comment.WriteString(line[i:]) line = strings.TrimSpace(line[:i]) } + } // Trim single and double quotes - if hasSurroundedQuote(line, '\'') || - hasSurroundedQuote(line, '"') { + if (hasSurroundedQuote(line, '\'') || + hasSurroundedQuote(line, '"')) && !preserveSurroundedQuote { line = line[1 : len(line)-1] } else if len(valQuote) == 0 && unescapeValueCommentSymbols { if strings.Contains(line, `\;`) { @@ -252,7 +269,42 @@ func (p *parser) readValue(in []byte, if strings.Contains(line, `\#`) { line = strings.Replace(line, `\#`, "#", -1) } + } else if allowPythonMultilines && lastChar == '\n' { + parserBufferPeekResult, _ := p.buf.Peek(parserBufferSize) + peekBuffer := bytes.NewBuffer(parserBufferPeekResult) + + val := line + + for { + peekData, peekErr := peekBuffer.ReadBytes('\n') + if peekErr != nil { + if peekErr == io.EOF { + return val, nil + } + return "", peekErr + } + + peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) + if len(peekMatches) != 3 { + return val, nil + } + + // NOTE: Return if not a python-ini multi-line value. + currentIdentSize := len(peekMatches[1]) + if currentIdentSize <= 0 { + return val, nil + } + + // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. + _, err := p.readUntil('\n') + if err != nil { + return "", err + } + + val += fmt.Sprintf("\n%s", peekMatches[2]) + } } + return line, nil } @@ -270,14 +322,48 @@ func (f *File) parse(reader io.Reader) (err error) { } section, _ := f.NewSection(name) + // This "last" is not strictly equivalent to "previous one" if current key is not the first nested key + var isLastValueEmpty bool + var lastRegularKey *Key + var line []byte var inUnparseableSection bool + + // NOTE: Iterate and increase `currentPeekSize` until + // the size of the parser buffer is found. + // TODO(unknwon): When Golang 1.10 is the lowest version supported, replace with `parserBufferSize := p.buf.Size()`. + parserBufferSize := 0 + // NOTE: Peek 1kb at a time. + currentPeekSize := 1024 + + if f.options.AllowPythonMultilineValues { + for { + peekBytes, _ := p.buf.Peek(currentPeekSize) + peekBytesLength := len(peekBytes) + + if parserBufferSize >= peekBytesLength { + break + } + + currentPeekSize *= 2 + parserBufferSize = peekBytesLength + } + } + for !p.isEOF { line, err = p.readUntil('\n') if err != nil { return err } + if f.options.AllowNestedValues && + isLastValueEmpty && len(line) > 0 { + if line[0] == ' ' || line[0] == '\t' { + lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) + continue + } + } + line = bytes.TrimLeftFunc(line, unicode.IsSpace) if len(line) == 0 { continue @@ -295,8 +381,7 @@ func (f *File) parse(reader io.Reader) (err error) { // Section if line[0] == '[' { // Read to the next ']' (TODO: support quoted strings) - // TODO(unknwon): use LastIndexByte when stop supporting Go1.4 - closeIdx := bytes.LastIndex(line, []byte("]")) + closeIdx := bytes.LastIndexByte(line, ']') if closeIdx == -1 { return fmt.Errorf("unclosed section: %s", line) } @@ -335,25 +420,35 @@ func (f *File) parse(reader io.Reader) (err error) { continue } - kname, offset, err := readKeyName(line) + kname, offset, err := readKeyName(f.options.KeyValueDelimiters, line) if err != nil { // Treat as boolean key when desired, and whole line is key name. - if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { - kname, err := p.readValue(line, - f.options.IgnoreContinuation, - f.options.IgnoreInlineComment, - f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols) - if err != nil { - return err + if IsErrDelimiterNotFound(err) { + switch { + case f.options.AllowBooleanKeys: + kname, err := p.readValue(line, + parserBufferSize, + f.options.IgnoreContinuation, + f.options.IgnoreInlineComment, + f.options.UnescapeValueDoubleQuotes, + f.options.UnescapeValueCommentSymbols, + f.options.AllowPythonMultilineValues, + f.options.SpaceBeforeInlineComment, + f.options.PreserveSurroundedQuote) + if err != nil { + return err + } + key, err := section.NewBooleanKey(kname) + if err != nil { + return err + } + key.Comment = strings.TrimSpace(p.comment.String()) + p.comment.Reset() + continue + + case f.options.SkipUnrecognizableLines: + continue } - key, err := section.NewBooleanKey(kname) - if err != nil { - return err - } - key.Comment = strings.TrimSpace(p.comment.String()) - p.comment.Reset() - continue } return err } @@ -367,13 +462,18 @@ func (f *File) parse(reader io.Reader) (err error) { } value, err := p.readValue(line[offset:], + parserBufferSize, f.options.IgnoreContinuation, f.options.IgnoreInlineComment, f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols) + f.options.UnescapeValueCommentSymbols, + f.options.AllowPythonMultilineValues, + f.options.SpaceBeforeInlineComment, + f.options.PreserveSurroundedQuote) if err != nil { return err } + isLastValueEmpty = len(value) == 0 key, err := section.NewKey(kname, value) if err != nil { @@ -382,6 +482,7 @@ func (f *File) parse(reader io.Reader) (err error) { key.isAutoIncrement = isAutoIncr key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() + lastRegularKey = key } return nil } diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/gopkg.in/ini.v1/section.go index d8a4026192..bc32c620d6 100644 --- a/vendor/gopkg.in/ini.v1/section.go +++ b/vendor/gopkg.in/ini.v1/section.go @@ -82,6 +82,7 @@ func (s *Section) NewKey(name, val string) (*Key, error) { } } else { s.keys[name].value = val + s.keysHash[name] = val } return s.keys[name], nil } @@ -237,6 +238,7 @@ func (s *Section) DeleteKey(name string) { if k == name { s.keyList = append(s.keyList[:i], s.keyList[i+1:]...) delete(s.keys, name) + delete(s.keysHash, name) return } } diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/gopkg.in/ini.v1/struct.go index 9719dc6985..a9dfed078a 100644 --- a/vendor/gopkg.in/ini.v1/struct.go +++ b/vendor/gopkg.in/ini.v1/struct.go @@ -180,7 +180,7 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: durationVal, err := key.Duration() // Skip zero value - if err == nil && int(durationVal) > 0 { + if err == nil && uint64(durationVal) > 0 { field.Set(reflect.ValueOf(durationVal)) return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 4d427e5a74..0013ea356f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -7,7 +7,7 @@ github.com/RoaringBitmap/roaring # github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca github.com/Unknwon/cae/zip github.com/Unknwon/cae -# github.com/Unknwon/com v0.0.0-20170819223952-7677a1d7c113 +# github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 github.com/Unknwon/com # github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 github.com/Unknwon/i18n @@ -125,6 +125,8 @@ github.com/go-macaron/cache/memcache github.com/go-macaron/cache/redis # github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab github.com/go-macaron/captcha +# github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 +github.com/go-macaron/cors # github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 github.com/go-macaron/csrf # github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f @@ -331,7 +333,7 @@ github.com/willf/bitset github.com/xanzy/ssh-agent # github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 github.com/yohcop/openid-go -# golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 +# golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 golang.org/x/crypto/acme/autocert golang.org/x/crypto/bcrypt golang.org/x/crypto/pbkdf2 @@ -363,10 +365,11 @@ golang.org/x/net/context # golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 +# golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e golang.org/x/sys/windows golang.org/x/sys/windows/svc golang.org/x/sys/unix +golang.org/x/sys/cpu # golang.org/x/text v0.3.0 golang.org/x/text/transform golang.org/x/text/encoding @@ -403,7 +406,7 @@ gopkg.in/bufio.v1 gopkg.in/editorconfig/editorconfig-core-go.v1 # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/gomail.v2 -# gopkg.in/ini.v1 v1.31.1 +# gopkg.in/ini.v1 v1.42.0 gopkg.in/ini.v1 # gopkg.in/ldap.v3 v3.0.2 gopkg.in/ldap.v3 From 5df5bfbd134b4348c333cf81b5bd9ff16ec667e0 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 13 May 2019 15:41:18 +0000 Subject: [PATCH 005/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-BR.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 7905699e58..66ada006d8 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1268,7 +1268,9 @@ settings.protected_branch_can_push_yes=Você pode fazer push settings.protected_branch_can_push_no=Você não pode fazer push settings.branch_protection=Proteção de branch para '%s' settings.protect_this_branch=Habilitar proteção de branch +settings.protect_this_branch_desc=Prevenir exclusão e desabilitar qualquer push neste branch. settings.protect_whitelist_committers=Habilitar controle de permissão de push +settings.protect_whitelist_committers_desc=Permitir que usuários ou times realizem push neste branch (exceto push forçado). settings.protect_whitelist_users=Usuários com permissão para realizar push: settings.protect_whitelist_search_users=Pesquisar usuários... settings.protect_whitelist_teams=Equipes com permissão para realizar push: From 06ae9a3a963cff8d296ca5806df611d1091847df Mon Sep 17 00:00:00 2001 From: Xaver Maierhofer Date: Mon, 13 May 2019 21:25:21 +0200 Subject: [PATCH 006/220] Use single line per selector & don't strip license comments (#6919) --- Makefile | 4 +- public/css/index.css | 979 ++++++++++++++++++++++++++++++++- public/css/theme-arc-green.css | 241 +++++++- 3 files changed, 1220 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index de625ce243..424ea9dedb 100644 --- a/Makefile +++ b/Makefile @@ -388,8 +388,8 @@ generate-stylesheets: exit 1; \ fi; $(eval BROWSERS := "> 1%, last 2 firefox versions, last 2 safari versions, ie 11") - npx lessc --clean-css public/less/index.less public/css/index.css - $(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;) + npx lessc --clean-css="--s0 -b" public/less/index.less public/css/index.css + $(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css="--s0 -b" public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;) $(foreach file, $(wildcard public/css/*),npx postcss --use autoprefixer --autoprefixer.browsers $(BROWSERS) -o $(file) $(file);) .PHONY: swagger-ui diff --git a/public/css/index.css b/public/css/index.css index 1e4598ddb1..a50fe43c8f 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -1 +1,978 @@ -.tribute-container{box-shadow:0 1px 3px 1px #c7c7c7}.tribute-container ul{background:#fff}.tribute-container li{padding:8px 12px;border-bottom:1px solid #dcdcdc}.tribute-container li img{display:inline-block;vertical-align:middle;width:28px;height:28px;margin-right:5px}.tribute-container li span.fullname{font-weight:400;font-size:.8rem;margin-left:3px}.tribute-container li.highlight,.tribute-container li:hover{background:#2185D0;color:#fff}.emoji{width:1.5em;height:1.5em;display:inline-block;background-size:contain}.ui.label .emoji{height:1.2em!important}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-regular.eot);src:url(../vendor/assets/lato-fonts/lato-regular.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-regular.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-regular.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-italic.eot);src:url(../vendor/assets/lato-fonts/lato-italic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-italic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-italic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bold.eot);src:url(../vendor/assets/lato-fonts/lato-bold.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bold.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bold.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot);src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bolditalic.ttf) format('truetype');font-weight:700;font-style:italic}@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Medium');font-weight:400}@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Bold');font-weight:700}textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}h1,h2,h3,h4,h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.home .hero h1,.home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.ui.accordion .title:not(.ui),.ui.button,.ui.card>.content>.header.ui.card>.content>.header,.ui.category.search>.results .category>.name,.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=file],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url],.ui.header,.ui.input input,.ui.input>input,.ui.items>.item>.content>.header,.ui.language>.menu>.item,.ui.list .list>.item .header,.ui.list>.item .header,.ui.menu,.ui.message .header,.ui.modal>.header,.ui.popup>.header,.ui.search>.results .result .title,.ui.search>.results>.message .header,.ui.statistic>.label,.ui.statistic>.value,.ui.statistics .statistic>.label,.ui.statistics .statistic>.value,.ui.steps .step .title,.ui.text.container,body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}body{background-color:#fff;overflow-y:auto;-webkit-font-smoothing:antialiased;display:flex;flex-direction:column}:lang(ja) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) h1,:lang(ja) h2,:lang(ja) h3,:lang(ja) h4,:lang(ja) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(ja) .home .hero h1,:lang(ja) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}.ui.language>.menu>.item:lang(ja),:lang(ja) .ui.accordion .title:not(.ui),:lang(ja) .ui.button,:lang(ja) .ui.card>.content>.header.ui.card>.content>.header,:lang(ja) .ui.category.search>.results .category>.name,:lang(ja) .ui.form input:not([type]),:lang(ja) .ui.form input[type=date],:lang(ja) .ui.form input[type=datetime-local],:lang(ja) .ui.form input[type=email],:lang(ja) .ui.form input[type=file],:lang(ja) .ui.form input[type=number],:lang(ja) .ui.form input[type=password],:lang(ja) .ui.form input[type=search],:lang(ja) .ui.form input[type=tel],:lang(ja) .ui.form input[type=text],:lang(ja) .ui.form input[type=time],:lang(ja) .ui.form input[type=url],:lang(ja) .ui.header,:lang(ja) .ui.input input,:lang(ja) .ui.input>input,:lang(ja) .ui.items>.item>.content>.header,:lang(ja) .ui.list .list>.item .header,:lang(ja) .ui.list>.item .header,:lang(ja) .ui.menu,:lang(ja) .ui.message .header,:lang(ja) .ui.modal>.header,:lang(ja) .ui.popup>.header,:lang(ja) .ui.search>.results .result .title,:lang(ja) .ui.search>.results>.message .header,:lang(ja) .ui.statistic>.label,:lang(ja) .ui.statistic>.value,:lang(ja) .ui.statistics .statistic>.label,:lang(ja) .ui.statistics .statistic>.value,:lang(ja) .ui.steps .step .title,:lang(ja) .ui.text.container,:lang(ja) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif}:lang(zh-CN) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) h1,:lang(zh-CN) h2,:lang(zh-CN) h3,:lang(zh-CN) h4,:lang(zh-CN) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-CN) .home .hero h1,:lang(zh-CN) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}.ui.language>.menu>.item:lang(zh-CN),:lang(zh-CN) .ui.accordion .title:not(.ui),:lang(zh-CN) .ui.button,:lang(zh-CN) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-CN) .ui.category.search>.results .category>.name,:lang(zh-CN) .ui.form input:not([type]),:lang(zh-CN) .ui.form input[type=date],:lang(zh-CN) .ui.form input[type=datetime-local],:lang(zh-CN) .ui.form input[type=email],:lang(zh-CN) .ui.form input[type=file],:lang(zh-CN) .ui.form input[type=number],:lang(zh-CN) .ui.form input[type=password],:lang(zh-CN) .ui.form input[type=search],:lang(zh-CN) .ui.form input[type=tel],:lang(zh-CN) .ui.form input[type=text],:lang(zh-CN) .ui.form input[type=time],:lang(zh-CN) .ui.form input[type=url],:lang(zh-CN) .ui.header,:lang(zh-CN) .ui.input input,:lang(zh-CN) .ui.input>input,:lang(zh-CN) .ui.items>.item>.content>.header,:lang(zh-CN) .ui.list .list>.item .header,:lang(zh-CN) .ui.list>.item .header,:lang(zh-CN) .ui.menu,:lang(zh-CN) .ui.message .header,:lang(zh-CN) .ui.modal>.header,:lang(zh-CN) .ui.popup>.header,:lang(zh-CN) .ui.search>.results .result .title,:lang(zh-CN) .ui.search>.results>.message .header,:lang(zh-CN) .ui.statistic>.label,:lang(zh-CN) .ui.statistic>.value,:lang(zh-CN) .ui.statistics .statistic>.label,:lang(zh-CN) .ui.statistics .statistic>.value,:lang(zh-CN) .ui.steps .step .title,:lang(zh-CN) .ui.text.container,:lang(zh-CN) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif}:lang(zh-TW) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) h1,:lang(zh-TW) h2,:lang(zh-TW) h3,:lang(zh-TW) h4,:lang(zh-TW) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-TW) .home .hero h1,:lang(zh-TW) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}.ui.language>.menu>.item:lang(zh-TW),:lang(zh-TW) .ui.accordion .title:not(.ui),:lang(zh-TW) .ui.button,:lang(zh-TW) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-TW) .ui.category.search>.results .category>.name,:lang(zh-TW) .ui.form input:not([type]),:lang(zh-TW) .ui.form input[type=date],:lang(zh-TW) .ui.form input[type=datetime-local],:lang(zh-TW) .ui.form input[type=email],:lang(zh-TW) .ui.form input[type=file],:lang(zh-TW) .ui.form input[type=number],:lang(zh-TW) .ui.form input[type=password],:lang(zh-TW) .ui.form input[type=search],:lang(zh-TW) .ui.form input[type=tel],:lang(zh-TW) .ui.form input[type=text],:lang(zh-TW) .ui.form input[type=time],:lang(zh-TW) .ui.form input[type=url],:lang(zh-TW) .ui.header,:lang(zh-TW) .ui.input input,:lang(zh-TW) .ui.input>input,:lang(zh-TW) .ui.items>.item>.content>.header,:lang(zh-TW) .ui.list .list>.item .header,:lang(zh-TW) .ui.list>.item .header,:lang(zh-TW) .ui.menu,:lang(zh-TW) .ui.message .header,:lang(zh-TW) .ui.modal>.header,:lang(zh-TW) .ui.popup>.header,:lang(zh-TW) .ui.search>.results .result .title,:lang(zh-TW) .ui.search>.results>.message .header,:lang(zh-TW) .ui.statistic>.label,:lang(zh-TW) .ui.statistic>.value,:lang(zh-TW) .ui.statistics .statistic>.label,:lang(zh-TW) .ui.statistics .statistic>.value,:lang(zh-TW) .ui.steps .step .title,:lang(zh-TW) .ui.text.container,:lang(zh-TW) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif}:lang(zh-HK) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) h1,:lang(zh-HK) h2,:lang(zh-HK) h3,:lang(zh-HK) h4,:lang(zh-HK) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(zh-HK) .home .hero h1,:lang(zh-HK) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}.ui.language>.menu>.item:lang(zh-HK),:lang(zh-HK) .ui.accordion .title:not(.ui),:lang(zh-HK) .ui.button,:lang(zh-HK) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-HK) .ui.category.search>.results .category>.name,:lang(zh-HK) .ui.form input:not([type]),:lang(zh-HK) .ui.form input[type=date],:lang(zh-HK) .ui.form input[type=datetime-local],:lang(zh-HK) .ui.form input[type=email],:lang(zh-HK) .ui.form input[type=file],:lang(zh-HK) .ui.form input[type=number],:lang(zh-HK) .ui.form input[type=password],:lang(zh-HK) .ui.form input[type=search],:lang(zh-HK) .ui.form input[type=tel],:lang(zh-HK) .ui.form input[type=text],:lang(zh-HK) .ui.form input[type=time],:lang(zh-HK) .ui.form input[type=url],:lang(zh-HK) .ui.header,:lang(zh-HK) .ui.input input,:lang(zh-HK) .ui.input>input,:lang(zh-HK) .ui.items>.item>.content>.header,:lang(zh-HK) .ui.list .list>.item .header,:lang(zh-HK) .ui.list>.item .header,:lang(zh-HK) .ui.menu,:lang(zh-HK) .ui.message .header,:lang(zh-HK) .ui.modal>.header,:lang(zh-HK) .ui.popup>.header,:lang(zh-HK) .ui.search>.results .result .title,:lang(zh-HK) .ui.search>.results>.message .header,:lang(zh-HK) .ui.statistic>.label,:lang(zh-HK) .ui.statistic>.value,:lang(zh-HK) .ui.statistics .statistic>.label,:lang(zh-HK) .ui.statistics .statistic>.value,:lang(zh-HK) .ui.steps .step .title,:lang(zh-HK) .ui.text.container,:lang(zh-HK) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif}:lang(ko) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) h1,:lang(ko) h2,:lang(ko) h3,:lang(ko) h4,:lang(ko) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}:lang(ko) .home .hero h1,:lang(ko) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}.ui.language>.menu>.item:lang(ko),:lang(ko) .ui.accordion .title:not(.ui),:lang(ko) .ui.button,:lang(ko) .ui.card>.content>.header.ui.card>.content>.header,:lang(ko) .ui.category.search>.results .category>.name,:lang(ko) .ui.form input:not([type]),:lang(ko) .ui.form input[type=date],:lang(ko) .ui.form input[type=datetime-local],:lang(ko) .ui.form input[type=email],:lang(ko) .ui.form input[type=file],:lang(ko) .ui.form input[type=number],:lang(ko) .ui.form input[type=password],:lang(ko) .ui.form input[type=search],:lang(ko) .ui.form input[type=tel],:lang(ko) .ui.form input[type=text],:lang(ko) .ui.form input[type=time],:lang(ko) .ui.form input[type=url],:lang(ko) .ui.header,:lang(ko) .ui.input input,:lang(ko) .ui.input>input,:lang(ko) .ui.items>.item>.content>.header,:lang(ko) .ui.list .list>.item .header,:lang(ko) .ui.list>.item .header,:lang(ko) .ui.menu,:lang(ko) .ui.message .header,:lang(ko) .ui.modal>.header,:lang(ko) .ui.popup>.header,:lang(ko) .ui.search>.results .result .title,:lang(ko) .ui.search>.results>.message .header,:lang(ko) .ui.statistic>.label,:lang(ko) .ui.statistic>.value,:lang(ko) .ui.statistics .statistic>.label,:lang(ko) .ui.statistics .statistic>.value,:lang(ko) .ui.steps .step .title,:lang(ko) .ui.text.container,:lang(ko) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif}img{border-radius:3px}table{border-collapse:collapse}a{cursor:pointer}.rounded{border-radius:.28571429rem!important}code,pre{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto}code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word}.dont-break-out{overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.full.height{flex-grow:1;padding-bottom:80px}.following.bar{z-index:900;left:0;margin:0!important}.following.bar.light{background-color:#fff;border-bottom:1px solid #DDD;box-shadow:0 2px 3px rgba(0,0,0,.04)}.following.bar .column .menu{margin-top:0}.following.bar .top.menu a.item.brand{padding-left:0}.following.bar .brand .ui.mini.image{width:30px}.following.bar .top.menu .dropdown.item.active,.following.bar .top.menu .dropdown.item:hover,.following.bar .top.menu a.item:hover{background-color:transparent}.following.bar .top.menu a.item:hover{color:rgba(0,0,0,.45)}.following.bar .top.menu .menu{z-index:900}.following.bar .octicon{margin-right:.75em}.following.bar .octicon.fitted{margin-right:0}.following.bar .searchbox{background-color:#f4f4f4!important}.following.bar .searchbox:focus{background-color:#e9e9e9!important}.following.bar .text .octicon{width:16px;text-align:center}.following.bar #navbar{width:100vw;min-height:52px;padding:0 .5rem}.following.bar #navbar .brand{margin:0}@media only screen and (max-width:767px){.following.bar #navbar:not(.shown)>:not(:first-child){display:none}}.right.stackable.menu{margin-left:auto;display:flex;align-items:inherit;flex-direction:inherit}.ui.left{float:left}.ui.right{float:right}.ui.button,.ui.menu .item{-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto}.ui.container.fluid.padded{padding:0 10px 0 10px}.ui.form .ui.button{font-weight:400}.ui.floating.label{z-index:10}.ui.transparent.label{background-color:transparent}.ui.menu,.ui.segment,.ui.vertical.menu{box-shadow:none}.ui .menu:not(.vertical) .item>.button.compact{padding:.58928571em 1.125em}.ui .menu:not(.vertical) .item>.button.small{font-size:.92857143rem}.ui.menu .ui.dropdown.item .menu .item{margin-right:auto}.ui.dropdown .menu>.item>.floating.label{z-index:11}.ui.dropdown .menu .menu>.item>.floating.label{z-index:21}.ui .text.red{color:#d95c5c!important}.ui .text.red a{color:#d95c5c!important}.ui .text.red a:hover{color:#E67777!important}.ui .text.blue{color:#428bca!important}.ui .text.blue a{color:#15c!important}.ui .text.blue a:hover{color:#428bca!important}.ui .text.black{color:#444}.ui .text.black:hover{color:#000}.ui .text.grey{color:#767676!important}.ui .text.grey a{color:#444!important}.ui .text.grey a:hover{color:#000!important}.ui .text.light.grey{color:#888!important}.ui .text.green{color:#6cc644!important}.ui .text.purple{color:#6e5494!important}.ui .text.yellow{color:#FBBD08!important}.ui .text.gold{color:#a1882b!important}.ui .text.left{text-align:left!important}.ui .text.right{text-align:right!important}.ui .text.small{font-size:.75em}.ui .text.normal{font-weight:400}.ui .text.bold{font-weight:700}.ui .text.italic{font-style:italic}.ui .text.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}.ui .text.thin{font-weight:400}.ui .text.middle{vertical-align:middle}.ui .message{text-align:center}.ui.bottom.attached.message{font-weight:700;text-align:left;color:#000}.ui.bottom.attached.message .pull-right{color:#000}.ui.bottom.attached.message .pull-right>span,.ui.bottom.attached.message>span{color:#21ba45}.ui .header>i+.content{padding-left:.75rem;vertical-align:middle}.ui .warning.header{background-color:#F9EDBE!important;border-color:#F0C36D}.ui .warning.segment{border-color:#F0C36D}.ui .info.segment{border:1px solid #c5d5dd}.ui .info.segment.top{background-color:#e6f1f6!important}.ui .info.segment.top h3,.ui .info.segment.top h4{margin-top:0}.ui .info.segment.top h3:last-child{margin-top:4px}.ui .info.segment.top>:last-child{margin-bottom:0}.ui .normal.header{font-weight:400}.ui .avatar.image{border-radius:3px}.ui .form .fake{display:none!important}.ui .form .sub.field{margin-left:25px}.ui .sha.label{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;font-size:13px;padding:6px 10px 4px 10px;font-weight:400;margin:0 6px}.ui.status.buttons .octicon{margin-right:4px}.ui.inline.delete-button{padding:8px 15px;font-weight:400}.ui .background.red{background-color:#d95c5c!important}.ui .background.blue{background-color:#428bca!important}.ui .background.black{background-color:#444}.ui .background.grey{background-color:#767676!important}.ui .background.light.grey{background-color:#888!important}.ui .background.green{background-color:#6cc644!important}.ui .background.purple{background-color:#6e5494!important}.ui .background.yellow{background-color:#FBBD08!important}.ui .background.gold{background-color:#a1882b!important}.ui .branch-tag-choice{line-height:20px}@media only screen and (max-width:767px){.ui.pagination.menu .item.navigation span.navigation_label,.ui.pagination.menu .item:not(.active):not(.navigation){display:none}}.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)}.ui.floating.dropdown .overflow.menu .scrolling.menu.items{border-radius:0!important;box-shadow:none!important;border-bottom:1px solid rgba(34,36,38,.15)}.user-menu>.item{width:100%;border-radius:0!important}.scrolling.menu .item.selected{font-weight:700!important}footer{background-color:#fff;border-top:1px solid #d6d6d6;width:100%;flex-basis:40px;color:#888}footer .container{width:100vw!important;padding:0 .5rem}footer .container .fa{width:16px;text-align:center;color:#428bca}footer .container .links>*{border-left:1px solid #d6d6d6;padding-left:8px;margin-left:5px}footer .container .links>:first-child{border-left:none}footer .ui.language .menu{max-height:500px;overflow-y:auto;margin-bottom:7px}footer .ui.left,footer .ui.right{line-height:40px}.hide{display:none}.hide.show-outdated{display:none!important}.hide.hide-outdated{display:none!important}.center{text-align:center}.img-1{width:2px!important;height:2px!important}.img-2{width:4px!important;height:4px!important}.img-3{width:6px!important;height:6px!important}.img-4{width:8px!important;height:8px!important}.img-5{width:10px!important;height:10px!important}.img-6{width:12px!important;height:12px!important}.img-7{width:14px!important;height:14px!important}.img-8{width:16px!important;height:16px!important}.img-9{width:18px!important;height:18px!important}.img-10{width:20px!important;height:20px!important}.img-11{width:22px!important;height:22px!important}.img-12{width:24px!important;height:24px!important}.img-13{width:26px!important;height:26px!important}.img-14{width:28px!important;height:28px!important}.img-15{width:30px!important;height:30px!important}.img-16{width:32px!important;height:32px!important}@media only screen and (min-width:768px){.mobile-only,.ui.button.mobile-only{display:none}.sr-mobile-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}}@media only screen and (max-width:767px){.not-mobile{display:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}@media only screen and (max-width:991px) and (min-width:768px){.ui.container{width:95%}}.hljs{background:inherit!important;padding:0!important}.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}@media only screen and (max-width:1200px){.ui.menu.new-menu{overflow-x:auto!important;justify-content:left!important;padding-bottom:5px}.ui.menu.new-menu::-webkit-scrollbar{height:8px;display:none}.ui.menu.new-menu:hover::-webkit-scrollbar{display:block}.ui.menu.new-menu::-webkit-scrollbar-track{background:rgba(0,0,0,.01)}.ui.menu.new-menu::-webkit-scrollbar-thumb{background:rgba(0,0,0,.2)}.ui.menu.new-menu:after{position:absolute;margin-top:-15px;display:block;background-image:linear-gradient(to right,rgba(255,255,255,0),#fff 100%);content:' ';right:0;height:53px;z-index:1000;width:60px;clear:none;visibility:visible}.ui.menu.new-menu a.item:last-child{padding-right:30px!important}}[v-cloak]{display:none!important}.repos-search{padding-bottom:0!important}.repos-filter{margin-top:0!important;border-bottom-width:0!important;margin-bottom:2px!important}#user-heatmap{width:107%;text-align:center}#user-heatmap svg:not(:root){overflow:inherit;padding:0!important}@media only screen and (max-width:1200px){#user-heatmap{display:none}}.heatmap-color-0{background-color:#f4f4f4}.heatmap-color-1{background-color:#d7e5db}.heatmap-color-2{background-color:#adc7ab}.heatmap-color-3{background-color:#83a87b}.heatmap-color-4{background-color:#598a4b}.heatmap-color-5{background-color:#2f6b1b}.archived-icon{color:#b3b3b3!important}.oauth2-authorize-application-box{margin-top:3em!important}.ui.tabular.menu .item{color:rgba(0,0,0,.5)}.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}.markdown:not(code).ui.segment{padding:3em}.markdown:not(code).file-view{padding:2em 2em 2em!important}.markdown:not(code)>:first-child{margin-top:0!important}.markdown:not(code)>:last-child{margin-bottom:0!important}.markdown:not(code) a:not([href]){color:inherit;text-decoration:none}.markdown:not(code) .absent{color:#c00}.markdown:not(code) .anchor{position:absolute;top:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown:not(code) .anchor:focus{outline:0}.markdown:not(code) h1,.markdown:not(code) h2,.markdown:not(code) h3,.markdown:not(code) h4,.markdown:not(code) h5,.markdown:not(code) h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}.markdown:not(code) h1:first-of-type,.markdown:not(code) h2:first-of-type,.markdown:not(code) h3:first-of-type,.markdown:not(code) h4:first-of-type,.markdown:not(code) h5:first-of-type,.markdown:not(code) h6:first-of-type{margin-top:0!important}.markdown:not(code) h1 .octicon-link,.markdown:not(code) h2 .octicon-link,.markdown:not(code) h3 .octicon-link,.markdown:not(code) h4 .octicon-link,.markdown:not(code) h5 .octicon-link,.markdown:not(code) h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown:not(code) h1:hover .anchor,.markdown:not(code) h2:hover .anchor,.markdown:not(code) h3:hover .anchor,.markdown:not(code) h4:hover .anchor,.markdown:not(code) h5:hover .anchor,.markdown:not(code) h6:hover .anchor{padding-left:8px;margin-left:-30px;text-decoration:none}.markdown:not(code) h1:hover .anchor .octicon-link,.markdown:not(code) h2:hover .anchor .octicon-link,.markdown:not(code) h3:hover .anchor .octicon-link,.markdown:not(code) h4:hover .anchor .octicon-link,.markdown:not(code) h5:hover .anchor .octicon-link,.markdown:not(code) h6:hover .anchor .octicon-link{display:inline-block}.markdown:not(code) h1 code,.markdown:not(code) h1 tt,.markdown:not(code) h2 code,.markdown:not(code) h2 tt,.markdown:not(code) h3 code,.markdown:not(code) h3 tt,.markdown:not(code) h4 code,.markdown:not(code) h4 tt,.markdown:not(code) h5 code,.markdown:not(code) h5 tt,.markdown:not(code) h6 code,.markdown:not(code) h6 tt{font-size:inherit}.markdown:not(code) h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee}.markdown:not(code) h1 .anchor{line-height:1}.markdown:not(code) h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee}.markdown:not(code) h2 .anchor{line-height:1}.markdown:not(code) h3{font-size:1.5em;line-height:1.43}.markdown:not(code) h3 .anchor{line-height:1.2}.markdown:not(code) h4{font-size:1.25em}.markdown:not(code) h4 .anchor{line-height:1.2}.markdown:not(code) h5{font-size:1em}.markdown:not(code) h5 .anchor{line-height:1.1}.markdown:not(code) h6{font-size:1em;color:#777}.markdown:not(code) h6 .anchor{line-height:1.1}.markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px}.markdown:not(code) blockquote{margin-left:0}.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none}.markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em}.markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none}.markdown:not(code) ol ol,.markdown:not(code) ol ul,.markdown:not(code) ul ol,.markdown:not(code) ul ul{margin-top:0;margin-bottom:0}.markdown:not(code) ol ol,.markdown:not(code) ul ol{list-style-type:lower-roman}.markdown:not(code) li>p{margin-top:0}.markdown:not(code) dl{padding:0}.markdown:not(code) dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown:not(code) dl dd{padding:0 16px;margin-bottom:16px}.markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown:not(code) blockquote>:first-child{margin-top:0}.markdown:not(code) blockquote>:last-child{margin-bottom:0}.markdown:not(code) table{width:auto;overflow:auto;word-break:normal;word-break:keep-all;display:block}.markdown:not(code) table th{font-weight:700}.markdown:not(code) table td,.markdown:not(code) table th{padding:6px 13px!important;border:1px solid #ddd!important}.markdown:not(code) table tr{background-color:#fff;border-top:1px solid #ccc}.markdown:not(code) table tr:nth-child(2n){background-color:#f8f8f8}.markdown:not(code) img{max-width:100%;box-sizing:border-box}.markdown:not(code) .emoji{max-width:none}.markdown:not(code) span.frame{display:block;overflow:hidden}.markdown:not(code) span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown:not(code) span.frame span img{display:block;float:left}.markdown:not(code) span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown:not(code) span.align-center{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown:not(code) span.align-center span img{margin:0 auto;text-align:center}.markdown:not(code) span.align-right{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown:not(code) span.align-right span img{margin:0;text-align:right}.markdown:not(code) span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown:not(code) span.float-left span{margin:13px 0 0}.markdown:not(code) span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown:not(code) span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown:not(code) code,.markdown:not(code) tt{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown:not(code) code:after,.markdown:not(code) code:before,.markdown:not(code) tt:after,.markdown:not(code) tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown:not(code) code br,.markdown:not(code) tt br{display:none}.markdown:not(code) del code{text-decoration:inherit}.markdown:not(code) pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown:not(code) .highlight{margin-bottom:16px}.markdown:not(code) .highlight pre,.markdown:not(code) pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown:not(code) .highlight pre{margin-bottom:0;word-break:normal}.markdown:not(code) pre{word-wrap:normal}.markdown:not(code) pre code,.markdown:not(code) pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown:not(code) pre code:after,.markdown:not(code) pre code:before,.markdown:not(code) pre tt:after,.markdown:not(code) pre tt:before{content:normal}.markdown:not(code) kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:solid 1px #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown:not(code) input[type=checkbox]{vertical-align:middle!important}.markdown:not(code) .csv-data td,.markdown:not(code) .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown:not(code) .csv-data .blob-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown:not(code) .csv-data tr{border-top:0}.markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em}.home .logo{max-width:220px}@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em}.home .hero h2{font-size:2em}}@media only screen and (min-width:768px){.home .hero h1{font-size:5.5em}.home .hero h2{font-size:3em}}.home .hero .octicon{color:#5aa509;font-size:40px;width:50px}.home .hero.header{font-size:20px}.home p.large{font-size:16px}.home .stackable{padding-top:30px}.home a{color:#5aa509}.signup{padding-top:15px}@media only screen and (max-width:880px){footer .ui.container .left,footer .ui.container .right{display:block;text-align:center;float:none}}.install{padding-top:45px}.install form label{text-align:right;width:320px!important}.install form input{width:35%!important}.install form .field{text-align:left}.install form .field .help{margin-left:335px!important}.install form .field.optional .title{margin-left:38%}.install .ui .checkbox{margin-left:40%!important}.install .ui .checkbox label{width:auto!important}.form .help{color:#999;padding-top:.6em;padding-bottom:.6em;display:inline-block}.ui.attached.header{background:#f0f0f0}.ui.attached.header .right{margin-top:-5px}.ui.attached.header .right .button{padding:8px 10px;font-weight:400}#create-page-form form{margin:auto}#create-page-form form .ui.message{text-align:center}@media only screen and (min-width:768px){#create-page-form form{width:800px!important}#create-page-form form .header{padding-left:280px!important}#create-page-form form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}#create-page-form form .help{margin-left:265px!important}#create-page-form form .optional .title{margin-left:250px!important}#create-page-form form input,#create-page-form form textarea{width:50%!important}}@media only screen and (max-width:767px){#create-page-form form .optional .title{margin-left:15px}#create-page-form form .inline.field>label{display:block}}.signin .oauth2 div{display:inline-block}.signin .oauth2 div p{margin:10px 5px 0 0;float:left}.signin .oauth2 a{margin-right:3px}.signin .oauth2 a:last-child{margin-right:0}.signin .oauth2 img{width:32px;height:32px}.signin .oauth2 img.openidConnect{width:auto}@media only screen and (min-width:768px){.g-recaptcha{margin:0 auto!important;width:304px;padding-left:30px}}@media screen and (max-height:575px){#rc-imageselect,.g-recaptcha{transform:scale(.77);transform-origin:0 0}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{margin:auto}.user.activate form .ui.message,.user.forgot.password form .ui.message,.user.reset.password form .ui.message,.user.signin form .ui.message,.user.signup form .ui.message{text-align:center}@media only screen and (min-width:768px){.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:800px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:280px!important}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.user.activate form .help,.user.forgot.password form .help,.user.reset.password form .help,.user.signin form .help,.user.signup form .help{margin-left:265px!important}.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:250px!important}.user.activate form input,.user.activate form textarea,.user.forgot.password form input,.user.forgot.password form textarea,.user.reset.password form input,.user.reset.password form textarea,.user.signin form input,.user.signin form textarea,.user.signup form input,.user.signup form textarea{width:50%!important}}@media only screen and (max-width:767px){.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:15px}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{display:block}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:700px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:0!important;text-align:center}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{width:200px}@media only screen and (max-width:768px){.user.activate form .inline.field>label,.user.activate form input,.user.forgot.password form .inline.field>label,.user.forgot.password form input,.user.reset.password form .inline.field>label,.user.reset.password form input,.user.signin form .inline.field>label,.user.signin form input,.user.signup form .inline.field>label,.user.signup form input{width:100%!important}}.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{margin:auto}.repository.new.fork form .ui.message,.repository.new.migrate form .ui.message,.repository.new.repo form .ui.message{text-align:center}@media only screen and (min-width:768px){.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{width:800px!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:280px!important}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.repository.new.fork form .help,.repository.new.migrate form .help,.repository.new.repo form .help{margin-left:265px!important}.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:250px!important}.repository.new.fork form input,.repository.new.fork form textarea,.repository.new.migrate form input,.repository.new.migrate form textarea,.repository.new.repo form input,.repository.new.repo form textarea{width:50%!important}}@media only screen and (max-width:767px){.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:15px}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{display:block}}.repository.new.fork form .dropdown .dropdown.icon,.repository.new.migrate form .dropdown .dropdown.icon,.repository.new.repo form .dropdown .dropdown.icon{margin-top:-7px!important;padding-bottom:5px}.repository.new.fork form .dropdown .text,.repository.new.migrate form .dropdown .text,.repository.new.repo form .dropdown .text{margin-right:0!important}.repository.new.fork form .dropdown .text i,.repository.new.migrate form .dropdown .text i,.repository.new.repo form .dropdown .text i{margin-right:0!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:0!important;text-align:center}@media only screen and (max-width:768px){.repository.new.fork form .selection.dropdown,.repository.new.fork form input,.repository.new.fork form label,.repository.new.migrate form .selection.dropdown,.repository.new.migrate form input,.repository.new.migrate form label,.repository.new.repo form .selection.dropdown,.repository.new.repo form input,.repository.new.repo form label{width:100%!important}.repository.new.fork form .field a,.repository.new.fork form .field button,.repository.new.migrate form .field a,.repository.new.migrate form .field button,.repository.new.repo form .field a,.repository.new.repo form .field button{margin-bottom:1em;width:100%}}@media only screen and (min-width:768px){.repository.new.repo .ui.form #auto-init{margin-left:265px!important}}.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:50%!important}@media only screen and (max-width:768px){.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:100%!important}}.new.webhook form .help{margin-left:25px}.new.webhook .events.fields .column{padding-left:40px}.githook textarea{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}@media only screen and (max-width:768px){.new.org .ui.form .field a,.new.org .ui.form .field button{margin-bottom:1em;width:100%}.new.org .ui.form .field input{width:100%!important}}.repository{padding-top:15px}.repository .repo-header .ui.compact.menu{margin-left:1rem}.repository .repo-header .ui.header{margin-top:0}.repository .repo-header .mega-octicon{width:30px;font-size:30px}.repository .repo-header .ui.huge.breadcrumb{font-weight:400;font-size:1.5rem}.repository .repo-header .fork-flag{margin-left:36px;margin-top:3px;display:block;font-size:12px;white-space:nowrap}.repository .repo-header .octicon.octicon-repo-forked{margin-top:-1px;font-size:15px}.repository .repo-header .button{margin-top:2px;margin-bottom:2px}.repository .tabs .navbar{justify-content:initial}.repository .navbar{display:flex;justify-content:space-between}.repository .navbar .ui.label{margin-left:7px;padding:3px 5px}.repository .owner.dropdown{min-width:40%!important}.repository #file-buttons{margin-left:auto!important;font-weight:400}.repository #file-buttons .ui.button{padding:8px 10px;font-weight:400}.repository .metas .menu{max-height:300px;overflow-x:auto}.repository .metas .ui.list .hide{display:none!important}.repository .metas .ui.list .item{padding:0}.repository .metas .ui.list .label.color{padding:0 8px;margin-right:5px}.repository .metas .ui.list a{margin:2px 0}.repository .metas .ui.list a .text{color:#444}.repository .metas .ui.list a .text:hover{color:#000}.repository .metas #deadlineForm input{width:12.8rem;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap}.repository .header-wrapper{background-color:#FAFAFA;margin-top:-15px;padding-top:15px}.repository .header-wrapper .ui.tabs.divider{border-bottom:none}.repository .header-wrapper .ui.tabular .octicon{margin-right:5px}.repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px}.repository .filter.menu .octicon{float:left;margin:5px -7px 0 -5px;width:16px}.repository .filter.menu.labels .octicon{margin:-2px -7px 0 -5px}.repository .filter.menu .text{margin-left:.9em}.repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}.repository .filter.menu .dropdown.item{margin:1px;padding-right:0}.repository .select-label .item{max-width:250px;overflow:hidden;text-overflow:ellipsis}.repository .select-label .desc{padding-left:16px}.repository .ui.tabs.container{margin-top:14px;margin-bottom:0}.repository .ui.tabs.container .ui.menu{border-bottom:none}.repository .ui.tabs.divider{margin-top:0;margin-bottom:20px}.repository #clone-panel{width:350px}@media only screen and (max-width:768px){.repository #clone-panel{width:100%}}.repository #clone-panel input{border-radius:0;padding:5px 10px;width:50%}.repository #clone-panel .clone.button{font-size:13px;padding:0 5px}.repository #clone-panel .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository #clone-panel .icon.button{padding:0 10px}.repository #clone-panel .dropdown .menu{right:0!important;left:auto!important}.repository.file.list .repo-description{display:flex;justify-content:space-between;align-items:center}.repository.file.list #repo-desc{font-size:1.2em}.repository.file.list .choose.reference .header .icon{font-size:1.4em}.repository.file.list .repo-path .divider,.repository.file.list .repo-path .section{display:inline}.repository.file.list #file-buttons{font-weight:400}.repository.file.list #file-buttons .ui.button{padding:8px 10px;font-weight:400}@media only screen and (max-width:768px){.repository.file.list #file-buttons .ui.tiny.blue.buttons{width:100%}}.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400}.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px}.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777}.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf}.repository.file.list #repo-files-table td{padding-top:8px;padding-bottom:8px;overflow:initial}.repository.file.list #repo-files-table td.name{max-width:150px}.repository.file.list #repo-files-table td.message{max-width:400px}.repository.file.list #repo-files-table td.age{width:120px}.repository.file.list #repo-files-table td .truncate{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap}.repository.file.list #repo-files-table td.message .isSigned{cursor:default}.repository.file.list #repo-files-table tr:hover{background-color:#ffE}.repository.file.list #repo-files-table .jumpable-path{color:#888}.repository.file.list .non-diff-file-content .header .icon{font-size:1em}.repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon{display:inline-block;padding:5px;margin-left:5px;line-height:1;color:#767676;vertical-align:middle;background:0 0;border:0;outline:0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover{color:#4078c0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover{color:#bd2c00}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon.disabled{color:#bbb;cursor:default}.repository.file.list .non-diff-file-content .header .file-actions #delete-file-form{display:inline-block}.repository.file.list .non-diff-file-content .view-raw{padding:5px}.repository.file.list .non-diff-file-content .view-raw *{max-width:100%}.repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px}.repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em}.repository.file.list .non-diff-file-content pre{overflow:auto}.repository.file.list .non-diff-file-content .code-view *{font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px}.repository.file.list .non-diff-file-content .code-view table{width:100%}.repository.file.list .non-diff-file-content .code-view .lines-num{vertical-align:top;text-align:right;color:#999;background:#f5f5f5;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-num span{line-height:20px;padding:0 10px;cursor:pointer;display:block}.repository.file.list .non-diff-file-content .code-view .lines-code,.repository.file.list .non-diff-file-content .code-view .lines-num{padding:0}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs,.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-code pre,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs,.repository.file.list .non-diff-file-content .code-view .lines-num ol,.repository.file.list .non-diff-file-content .code-view .lines-num pre{background-color:#fff;margin:0;padding:0!important}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-code ol li,.repository.file.list .non-diff-file-content .code-view .lines-code pre li,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-num ol li,.repository.file.list .non-diff-file-content .code-view .lines-num pre li{display:block;width:100%}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-code ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-code pre li.active,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-num ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-num pre li.active{background:#ffd}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-code ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-code pre li:before,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-num ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-num pre li:before{content:' '}.repository.file.list .non-diff-file-content .code-view .lines-commit{vertical-align:top;color:#999;padding:0;background:#f5f5f5;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info{width:350px;max-width:350px;display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 0 0 10px}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data{display:flex;font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-message{flex-grow:2;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;line-height:20px}.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-avatar,.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-time{flex-shrink:0}.repository.file.list .non-diff-file-content .code-view .lines-commit .ui.avatar.image{height:18px;width:18px}.repository.file.list .non-diff-file-content .code-view .lines-code .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-commit .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-num .bottom-line{border-bottom:1px solid #eaecef}.repository.file.list .non-diff-file-content .code-view .active{background:#ffd}.repository.file.list .sidebar{padding-left:0}.repository.file.list .sidebar .octicon{width:16px}.repository.file.editor .treepath{width:100%}.repository.file.editor .treepath input{vertical-align:middle;box-shadow:rgba(0,0,0,.0745098) 0 1px 2px inset;width:inherit;padding:7px 8px;margin-right:5px}.repository.file.editor .tabular.menu .octicon{margin-right:5px}.repository.file.editor .commit-form-wrapper{padding-left:64px}.repository.file.editor .commit-form-wrapper .commit-avatar{float:left;margin-left:-64px;width:3em;height:auto}.repository.file.editor .commit-form-wrapper .commit-form{position:relative;padding:15px;margin-bottom:10px;border:1px solid #ddd;border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form:after,.repository.file.editor .commit-form-wrapper .commit-form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#fff}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name{display:inline-block;padding:3px 6px;font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.65);background-color:rgba(209,227,237,.45);border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input{position:relative;margin-left:25px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input input{width:240px!important;padding-left:26px!important}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .octicon-git-branch{position:absolute;top:9px;left:10px;color:#b0c4ce}.repository.options #interval{width:100px!important;min-width:100px}.repository.options .danger .item{padding:20px 15px}.repository.options .danger .ui.divider{margin:0}.repository.new.issue .comment.form .comment .avatar{width:3em}.repository.new.issue .comment.form .content{margin-left:4em}.repository.new.issue .comment.form .content:after,.repository.new.issue .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.new.issue .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.new.issue .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.new.issue .comment.form .content:after{border-right-color:#fff}.repository.new.issue .comment.form .content .markdown{font-size:14px}.repository.new.issue .comment.form .metas{min-width:220px}.repository.new.issue .comment.form .metas .filter.menu{max-height:300px;overflow-x:auto}.repository.view.issue .title{padding-bottom:0!important}.repository.view.issue .title h1{font-weight:300;font-size:2.3rem;margin-bottom:5px}.repository.view.issue .title h1 .ui.input{font-size:.5em;vertical-align:top;width:50%;min-width:600px}.repository.view.issue .title h1 .ui.input input{font-size:1.5em;padding:6px 10px}.repository.view.issue .title .index{font-weight:300;color:#aaa;letter-spacing:-1px}.repository.view.issue .title .label{margin-right:10px}.repository.view.issue .title .edit-zone{margin-top:10px}.repository.view.issue .pull-desc code{color:#0166E6}.repository.view.issue .pull.tabular.menu{margin-bottom:10px}.repository.view.issue .pull.tabular.menu .octicon{margin-right:5px}.repository.view.issue .pull.tab.segment{border:none;padding:10px 0 0;box-shadow:none;background-color:inherit}.repository.view.issue .pull .merge.box .avatar{margin-left:10px;margin-top:10px}.repository.view.issue .pull .review-item .avatar,.repository.view.issue .pull .review-item .type-icon{float:none;display:inline-block;text-align:center;vertical-align:middle}.repository.view.issue .pull .review-item .avatar .octicon,.repository.view.issue .pull .review-item .type-icon .octicon{width:23px;font-size:23px;margin-top:.45em}.repository.view.issue .pull .review-item .text{margin:.3em 0 .5em .5em}.repository.view.issue .pull .review-item .type-icon{float:right;margin-right:1em}.repository.view.issue .pull .review-item .divider{margin:.5rem 0}.repository.view.issue .pull .review-item .review-content{padding:1em 0 1em 3.8em}.repository.view.issue .comment-list:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1}.repository.view.issue .comment-list .comment .avatar{width:3em}.repository.view.issue .comment-list .comment .tag{color:#767676;margin-top:3px;padding:2px 5px;font-size:12px;border:1px solid rgba(0,0,0,.1);border-radius:3px}.repository.view.issue .comment-list .comment .actions .item{float:left}.repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px}.repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px}.repository.view.issue .comment-list .comment .content{margin-left:4em}.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px}.repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px}.repository.view.issue .comment-list .comment .content .markdown{font-size:14px}.repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.images::after{clear:both;content:' ';display:block}.repository.view.issue .comment-list .comment .content>.bottom.segment a{display:block;float:left;margin:5px;padding:5px;height:150px;border:solid 1px #eee;border-radius:3px;max-width:150px;background-color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a:before{content:' ';display:inline-block;height:100%;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.image{max-height:100%;width:auto;margin:0;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image{font-size:128px;color:#000}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image:hover{color:#000}.repository.view.issue .comment-list .comment .ui.form .field:first-child{clear:none}.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:none;padding:10px 0 0}.repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px}.repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px}.repository.view.issue .comment-list .event .octicon{width:30px;float:left;text-align:center}.repository.view.issue .comment-list .event .octicon.octicon-circle-slash{margin-top:5px;margin-left:-34.5px;font-size:20px;color:#bd2c00}.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644}.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:3px;margin-left:-31px;margin-right:-1px;font-size:25px}.repository.view.issue .comment-list .event .octicon.octicon-comment{margin-top:4px;margin-left:-35px;font-size:24px}.repository.view.issue .comment-list .event .octicon.octicon-eye{margin-top:3px;margin-left:-35px;margin-right:0;font-size:22px}.repository.view.issue .comment-list .event .octicon.octicon-x{margin-left:-33px;font-size:25px}.repository.view.issue .comment-list .event .detail{font-size:.9rem;margin-top:5px;margin-left:35px}.repository.view.issue .comment-list .event .detail .octicon.octicon-git-commit{margin-top:2px}.repository.view.issue .ui.segment.metas{margin-top:-3px}.repository.view.issue .ui.participants img{margin-top:5px;margin-right:5px}.repository.view.issue .ui.depending .item.is-closed .title{text-decoration:line-through}.repository .comment.form .ui.comments{margin-top:-12px;max-width:100%}.repository .comment.form .content .field:first-child{clear:none}.repository .comment.form .content .form:after,.repository .comment.form .content .form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository .comment.form .content .form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository .comment.form .content .form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository .comment.form .content .form:after{border-right-color:#fff}.repository .comment.form .content .tab.segment{border:none;padding:10px 0 0}.repository .comment.form .content textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository .label.list{list-style:none;padding-top:15px}.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .label.list .item a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .label.list .item a:hover{color:#000}.repository .label.list .item a.open-issues{margin-right:30px}.repository .label.list .item .ui.label{font-size:1em}.repository .milestone.list{list-style:none;padding-top:15px}.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .milestone.list>.item>a{padding-top:5px;padding-right:10px;color:#000}.repository .milestone.list>.item>a:hover{color:#4078c0}.repository .milestone.list>.item .ui.progress{width:40%;padding:0;border:0;margin:0}.repository .milestone.list>.item .ui.progress .bar{height:20px}.repository .milestone.list>.item .meta{color:#999;padding-top:5px}.repository .milestone.list>.item .meta .issue-stats .octicon{padding-left:5px}.repository .milestone.list>.item .meta .overdue{color:red}.repository .milestone.list>.item .operate{margin-top:-15px}.repository .milestone.list>.item .operate>a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .milestone.list>.item .operate>a:hover{color:#000}.repository .milestone.list>.item .content{padding-top:10px}.repository.new.milestone textarea{height:200px}.repository.new.milestone #deadline{width:150px}.repository.compare.pull .choose.branch .octicon{padding-right:10px}.repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.compare.pull .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.compare.pull .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.compare.pull .comment.form .content:after{border-right-color:#fff}.repository .filter.dropdown .menu{margin-top:1px!important}.repository.branches .commit-divergence .bar-group{position:relative;float:left;padding-bottom:6px;width:90px}.repository.branches .commit-divergence .bar-group:last-child{border-left:1px solid #b4b4b4}.repository.branches .commit-divergence .count{margin:0 3px}.repository.branches .commit-divergence .count.count-ahead{text-align:left}.repository.branches .commit-divergence .count.count-behind{text-align:right}.repository.branches .commit-divergence .bar{height:4px;position:absolute;background-color:#d4d4d5}.repository.branches .commit-divergence .bar.bar-behind{right:0}.repository.branches .commit-divergence .bar.bar-ahead{left:0}.repository.commits .header .search input{font-weight:400;padding:5px 10px}.repository #commits-table thead th:first-of-type{padding-left:15px}.repository #commits-table thead .sha{width:140px}.repository #commits-table thead .shatd{text-align:center}.repository #commits-table td.sha .sha.label{margin:0}.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #BBB}.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#FAFAFA;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #BBB;border-top-left-radius:0;border-bottom-left-radius:0}.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21BA45;background:rgba(33,186,69,.1)}.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon{border-left:1px solid rgba(33,186,69,.5)}.repository .diff-detail-box{padding:7px 0;background:#fff;line-height:30px}.repository .diff-detail-box>div:after{clear:both;content:"";display:block}.repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px}.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #DDD;padding-left:6px}.repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle}.repository .diff-detail-box span.status.modify{background-color:#f0db88}.repository .diff-detail-box span.status.add{background-color:#b4e2b4}.repository .diff-detail-box span.status.del{background-color:#e9aeae}.repository .diff-detail-box span.status.rename{background-color:#dad8ff}.repository .diff-detail-box .detail-files{background:#fff;margin:0}.repository .diff-box .header{display:flex;align-items:center}.repository .diff-box .header .count{margin-right:12px;font-size:13px;flex:0 0 auto}.repository .diff-box .header .count .bar{background-color:#bd2c00;height:12px;width:40px;display:inline-block;margin:2px 4px 0 4px;vertical-align:text-top}.repository .diff-box .header .count .bar .add{background-color:#55a532;height:12px}.repository .diff-box .header .file{flex:1;color:#888;word-break:break-all}.repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto}.repository .diff-file-box .header{background-color:#f7f7f7}.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#A7A7A7;background:#fafafa;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top}.repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #DDD}.repository .diff-file-box .code-diff{font-size:12px}.repository .diff-file-box .code-diff td{padding:0 0 0 10px;border-top:none}.repository .diff-file-box .code-diff pre{margin:0}.repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px}.repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#F0F0F0!important;border-color:#D2CECE!important;padding-top:8px;padding-bottom:8px}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#fafafa}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split tbody tr td:nth-child(3){border-left-width:1px;border-left-style:solid}.repository .diff-file-box.file-content{clear:right}.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}.repository .repo-search-result{padding-top:10px;padding-bottom:10px}.repository .repo-search-result .lines-num a{color:inherit}.repository.quickstart .guide .item{padding:1em}.repository.quickstart .guide .item small{font-weight:400}.repository.quickstart .guide .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository.quickstart .guide .ui.action.small.input{width:100%}.repository.quickstart .guide #repo-clone-url{border-radius:0;padding:5px 10px;font-size:1.2em}.repository.release #release-list{border-top:1px solid #DDD;margin-top:20px;padding-top:15px}.repository.release #release-list>li{list-style:none}.repository.release #release-list>li .detail,.repository.release #release-list>li .meta{padding-top:30px;padding-bottom:40px}.repository.release #release-list>li .meta{text-align:right;position:relative}.repository.release #release-list>li .meta .tag:not(.icon){display:block;margin-top:15px}.repository.release #release-list>li .meta .commit{display:block;margin-top:10px}.repository.release #release-list>li .detail{border-left:1px solid #DDD}.repository.release #release-list>li .detail .author img{margin-bottom:-3px}.repository.release #release-list>li .detail .download{margin-top:20px}.repository.release #release-list>li .detail .download>a .octicon{margin-left:5px;margin-right:5px}.repository.release #release-list>li .detail .download .list{padding-left:0;border-top:1px solid #eee}.repository.release #release-list>li .detail .download .list li{list-style:none;display:block;padding-top:8px;padding-bottom:8px;border-bottom:1px solid #eee}.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #FFF}.repository.new.release .target{min-width:500px}.repository.new.release .target #tag-name{margin-top:-4px}.repository.new.release .target .at{margin-left:-5px;margin-right:5px}.repository.new.release .target .dropdown.icon{margin:0;padding-top:3px}.repository.new.release .target .selection.dropdown{padding-top:10px;padding-bottom:10px}.repository.new.release .prerelease.field{margin-bottom:0}@media only screen and (max-width:438px){.repository.new.release .field button,.repository.new.release .field input{width:100%}}@media only screen and (max-width:768px){.repository.new.release .field button{margin-bottom:1em}}.repository.forks .list{margin-top:0}.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #DDD}.repository.forks .list .item .ui.avatar{float:left;margin-right:5px}.repository.forks .list .item .link{padding-top:5px}.repository.wiki.start .ui.segment{padding-top:70px;padding-bottom:100px}.repository.wiki.start .ui.segment .mega-octicon{font-size:48px}.repository.wiki.new .CodeMirror .CodeMirror-code{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment{background:inherit}.repository.wiki.new .editor-preview{background-color:#fff}.repository.wiki.view .choose.page{margin-top:-5px}.repository.wiki.view .ui.sub.header{text-transform:none}.repository.wiki.view>.markdown{padding:15px 30px}.repository.wiki.view>.markdown h1:first-of-type,.repository.wiki.view>.markdown h2:first-of-type,.repository.wiki.view>.markdown h3:first-of-type,.repository.wiki.view>.markdown h4:first-of-type,.repository.wiki.view>.markdown h5:first-of-type,.repository.wiki.view>.markdown h6:first-of-type{margin-top:0}@media only screen and (max-width:767px){.repository.wiki .dividing.header .stackable.grid .button{margin-top:2px;margin-bottom:2px}}.repository.settings.collaboration .collaborator.list{padding:0}.repository.settings.collaboration .collaborator.list>.item{margin:0;line-height:2em}.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #DDD}.repository.settings.collaboration #repo-collab-form #search-user-box .results{left:7px}.repository.settings.collaboration #repo-collab-form .ui.button{margin-left:5px;margin-top:-3px}.repository.settings.branches .protected-branches .selection.dropdown{width:300px}.repository.settings.branches .protected-branches .item{border:1px solid #eaeaea;padding:10px 15px}.repository.settings.branches .protected-branches .item:not(:last-child){border-bottom:0}.repository.settings.branches .branch-protection .help{margin-left:26px;padding-top:0}.repository.settings.branches .branch-protection .fields{margin-left:20px;display:block}.repository.settings.branches .branch-protection .whitelist{margin-left:26px}.repository.settings.branches .branch-protection .whitelist .dropdown img{display:inline-block}.repository.settings.webhook .events .column{padding-bottom:0}.repository.settings.webhook .events .help{font-size:13px;margin-left:26px;padding-top:0}.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #A3C293;border-right:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #A3C293}.repository .ui.segment.sub-menu{padding:7px;line-height:0}.repository .ui.segment.sub-menu .list{width:100%;display:flex}.repository .ui.segment.sub-menu .list .item{width:100%;border-radius:3px}.repository .ui.segment.sub-menu .list .item a{color:#000}.repository .ui.segment.sub-menu .list .item a:hover{color:#666}.repository .ui.segment.sub-menu .list .item.active{background:rgba(0,0,0,.05)}.repository .segment.reactions.dropdown .menu,.repository .select-reaction.dropdown .menu{right:0!important;left:auto!important}.repository .segment.reactions.dropdown .menu>.header,.repository .select-reaction.dropdown .menu>.header{margin:.75rem 0 .5rem}.repository .segment.reactions.dropdown .menu>.item,.repository .select-reaction.dropdown .menu>.item{float:left;padding:.5rem .5rem!important}.repository .segment.reactions.dropdown .menu>.item img.emoji,.repository .select-reaction.dropdown .menu>.item img.emoji{margin-right:0}.repository .segment.reactions{padding:.3em 1em}.repository .segment.reactions .ui.label{padding:.4em}.repository .segment.reactions .ui.label.disabled{cursor:default}.repository .segment.reactions .ui.label>img{height:1.5em!important}.repository .segment.reactions .select-reaction{float:none}.repository .segment.reactions .select-reaction:not(.active) a{display:none}.repository .segment.reactions:hover .select-reaction a{display:block}.user-cards .list{padding:0}.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}.user-cards .list .item .meta{margin-top:5px}#search-repo-box .results .result .image,#search-user-box .results .result .image{float:left;margin-right:8px;width:2em;height:2em}#search-repo-box .results .result .content,#search-user-box .results .result .content{margin:6px 0}#issue-filters.hide{display:none}#issue-actions{margin-top:-1rem!important}#issue-actions.hide{display:none}.ui.checkbox.issue-checkbox{vertical-align:middle}.issue.list{list-style:none}.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #AAA}.issue.list>.item .title{color:#444;font-size:15px;font-weight:700;margin:0 6px}.issue.list>.item .title:hover{color:#000}.issue.list>.item .comment{padding-right:10px;color:#666}.issue.list>.item .desc{padding-top:5px;color:#999}.issue.list>.item .desc .checklist{padding-left:5px}.issue.list>.item .desc .checklist .progress-bar{margin-left:2px;width:80px;height:6px;display:inline-block;background-color:#eee;overflow:hidden;border-radius:3px;vertical-align:2px!important}.issue.list>.item .desc .checklist .progress-bar .progress{background-color:#ccc;display:block;height:100%}.issue.list>.item .desc a.milestone{padding-left:5px;color:#999!important}.issue.list>.item .desc a.milestone:hover{color:#000!important}.issue.list>.item .desc .assignee{margin-top:-5px;margin-right:5px}.issue.list>.item .desc .overdue{color:red}.page.buttons{padding-top:15px}.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087F7;box-shadow:none!important}.ui.form .dropzone .dz-error-message{top:140px}.settings .content{margin-top:2px}.settings .content .segment,.settings .content>.header{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.settings .list>.item .green{color:#21BA45}.settings .list>.item:not(:first-child){border-top:1px solid #eaeaea;padding:1rem;margin:15px -1rem -1rem -1rem}.settings .list>.item>.mega-octicon{display:table-cell}.settings .list>.item>.mega-octicon+.content{display:table-cell;padding:0 0 0 .5em;vertical-align:top}.settings .list>.item .info{margin-top:10px}.settings .list>.item .info .tab.segment{border:none;padding:10px 0 0}.settings .list.key .meta{padding-top:5px;color:#666}.settings .list.email>.item:not(:first-child){min-height:60px}.settings .list.collaborator>.item{padding:0}.ui.vertical.menu .header.item{font-size:1.1em;background:#f0f0f0}.edit-label.modal .form .column,.new-label.segment .form .column{padding-right:0}.edit-label.modal .form .buttons,.new-label.segment .form .buttons{margin-left:auto;padding-top:15px}.edit-label.modal .form .color.picker.column,.new-label.segment .form .color.picker.column{width:auto}.edit-label.modal .form .color.picker.column .color-picker,.new-label.segment .form .color.picker.column .color-picker{height:35px;width:auto;padding-left:30px}.edit-label.modal .form .minicolors-swatch.minicolors-sprite,.new-label.segment .form .minicolors-swatch.minicolors-sprite{top:10px;left:10px;width:15px;height:15px}.edit-label.modal .form .precolors,.new-label.segment .form .precolors{padding-left:0;padding-right:0;margin:3px 10px auto 10px;width:120px}.edit-label.modal .form .precolors .color,.new-label.segment .form .precolors .color{float:left;width:15px;height:15px}#avatar-arrow:after,#avatar-arrow:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}#avatar-arrow:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}#avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}#delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important}.tab-size-1{-moz-tab-size:1!important;-o-tab-size:1!important;tab-size:1!important}.tab-size-2{-moz-tab-size:2!important;-o-tab-size:2!important;tab-size:2!important}.tab-size-3{-moz-tab-size:3!important;-o-tab-size:3!important;tab-size:3!important}.tab-size-4{-moz-tab-size:4!important;-o-tab-size:4!important;tab-size:4!important}.tab-size-5{-moz-tab-size:5!important;-o-tab-size:5!important;tab-size:5!important}.tab-size-6{-moz-tab-size:6!important;-o-tab-size:6!important;tab-size:6!important}.tab-size-7{-moz-tab-size:7!important;-o-tab-size:7!important;tab-size:7!important}.tab-size-8{-moz-tab-size:8!important;-o-tab-size:8!important;tab-size:8!important}.tab-size-9{-moz-tab-size:9!important;-o-tab-size:9!important;tab-size:9!important}.tab-size-10{-moz-tab-size:10!important;-o-tab-size:10!important;tab-size:10!important}.tab-size-11{-moz-tab-size:11!important;-o-tab-size:11!important;tab-size:11!important}.tab-size-12{-moz-tab-size:12!important;-o-tab-size:12!important;tab-size:12!important}.tab-size-13{-moz-tab-size:13!important;-o-tab-size:13!important;tab-size:13!important}.tab-size-14{-moz-tab-size:14!important;-o-tab-size:14!important;tab-size:14!important}.tab-size-15{-moz-tab-size:15!important;-o-tab-size:15!important;tab-size:15!important}.tab-size-16{-moz-tab-size:16!important;-o-tab-size:16!important;tab-size:16!important}.stats-table{display:table;width:100%}.stats-table .table-cell{display:table-cell}.stats-table .table-cell.tiny{height:.5em}tbody.commit-list{vertical-align:baseline}.commit-body{white-space:pre-wrap}@media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px}.ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0}}#topic_edit{margin-top:5px}#repo-topics{margin-top:5px}.repo-topic{cursor:pointer}#new-dependency-drop-list.ui.selection.dropdown{min-width:0;width:100%;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap}#new-dependency-drop-list .text{width:100%;overflow:hidden}#manage_topic{font-size:12px}.label+#manage_topic{margin-left:5px}.repo-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap}.repo-header .repo-buttons{display:flex;align-items:center}.repo-buttons .disabled-repo-button .label{opacity:.5}.repo-buttons .disabled-repo-button a.button{opacity:.5;cursor:not-allowed}.repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important}.repo-buttons .ui.labeled.button>.label{border-left:none!important;margin:0!important}.CodeMirror{font:14px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.CodeMirror.cm-s-default{border-radius:3px;padding:0!important}.CodeMirror .cm-comment{background:inherit!important}.repository.file.editor .tab[data-tab=write]{padding:0!important}.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:none!important}.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:none;border-right:none;border-bottom:none}.organization{padding-top:15px}.organization .head .ui.header .text{vertical-align:middle;font-size:1.6rem;margin-left:15px}.organization .head .ui.header .ui.right{margin-top:5px}.organization.new.org form{margin:auto}.organization.new.org form .ui.message{text-align:center}@media only screen and (min-width:768px){.organization.new.org form{width:800px!important}.organization.new.org form .header{padding-left:280px!important}.organization.new.org form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.organization.new.org form .help{margin-left:265px!important}.organization.new.org form .optional .title{margin-left:250px!important}.organization.new.org form input,.organization.new.org form textarea{width:50%!important}}@media only screen and (max-width:767px){.organization.new.org form .optional .title{margin-left:15px}.organization.new.org form .inline.field>label{display:block}}.organization.new.org form .header{padding-left:0!important;text-align:center}.organization.options input{min-width:300px}.organization.profile #org-avatar{width:100px;height:100px;margin-right:15px}.organization.profile #org-info .ui.header{font-size:36px;margin-bottom:0}.organization.profile #org-info .desc{font-size:16px;margin-bottom:10px}.organization.profile #org-info .meta .item{display:inline-block;margin-right:10px}.organization.profile #org-info .meta .item .icon{margin-right:5px}.organization.profile .ui.top.header .ui.right{margin-top:0}.organization.profile .teams .item{padding:10px 15px}.organization.profile .members .ui.avatar,.organization.teams .members .ui.avatar{width:48px;height:48px;margin-right:5px}.organization.invite #invite-box{margin:50px auto auto;width:500px!important}.organization.invite #invite-box #search-user-box input{margin-left:0;width:300px}.organization.invite #invite-box .ui.button{margin-left:5px;margin-top:-3px}.organization.members .list .item{margin-left:0;margin-right:0;border-bottom:1px solid #eee}.organization.members .list .item .ui.avatar{width:48px;height:48px}.organization.members .list .item .meta{line-height:24px}.organization.teams .detail .item{padding:10px 15px}.organization.teams .detail .item:not(:last-child){border-bottom:1px solid #eee}.organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px}.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #DDD}.organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px}.organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0}.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px}.user:not(.icon){padding-top:15px}.user.profile .ui.card .username{display:block}.user.profile .ui.card .extra.content{padding:0}.user.profile .ui.card .extra.content ul{margin:0;padding:0}.user.profile .ui.card .extra.content ul li{padding:10px;list-style:none}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #eaeaea}.user.profile .ui.card .extra.content ul li .octicon{margin-left:1px;margin-right:5px}.user.profile .ui.card .extra.content ul li.follow .ui.button{width:100%}@media only screen and (max-width:768px){.user.profile .ui.card #profile-avatar{height:250px;overflow:hidden}.user.profile .ui.card #profile-avatar img{max-height:768px;max-width:768px}}@media only screen and (max-width:768px){.user.profile .ui.card{width:100%}}.user.profile .ui.repository.list{margin-top:25px}.user.profile #loading-heatmap{margin-bottom:1em}.user.followers .header.name{font-size:20px;line-height:24px;vertical-align:middle}.user.followers .follow .ui.button{padding:8px 15px}.user.notification .octicon{float:left;font-size:2em}.user.notification .content{float:left;margin-left:7px}.user.notification table form{display:inline-block}.user.notification table button{padding:3px 3px 3px 5px}.user.notification table tr{cursor:pointer}.user.notification .octicon.green{color:#21ba45}.user.notification .octicon.red{color:#d01919}.user.notification .octicon.purple{color:#a333c8}.user.notification .octicon.blue{color:#2185d0}.user.link-account:not(.icon){padding-top:15px;padding-bottom:5px}.user.settings .iconFloat{float:left}.dashboard{padding-top:15px}.dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px}.dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none}.dashboard.feeds .filter.menu .item,.dashboard.issues .filter.menu .item{text-align:left}.dashboard.feeds .filter.menu .item .text,.dashboard.issues .filter.menu .item .text{height:16px;vertical-align:middle}.dashboard.feeds .filter.menu .item .text.truncate,.dashboard.issues .filter.menu .item .text.truncate{width:85%}.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:7px;left:90%;width:15%}@media only screen and (max-width:768px){.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:10px;left:auto;width:auto;right:13px}}.dashboard.feeds .filter.menu .jump.item,.dashboard.issues .filter.menu .jump.item{margin:1px;padding-right:0}.dashboard.feeds .filter.menu .menu,.dashboard.issues .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}@media only screen and (max-width:768px){.dashboard.feeds .filter.menu,.dashboard.issues .filter.menu{width:100%}}.dashboard.feeds .right.stackable.menu>.item.active,.dashboard.issues .right.stackable.menu>.item.active{color:#d9453d}.dashboard .dashboard-repos{margin:0 1px}.dashboard .dashboard-navbar{width:100vw;padding:0 .5rem}.feeds .news>.ui.grid{margin-left:auto;margin-right:auto}.feeds .news .ui.avatar{margin-top:13px}.feeds .news .time-since{font-size:13px}.feeds .news .issue.title{width:80%}.feeds .news .push.news .content ul{font-size:13px;list-style:none;padding-left:10px}.feeds .news .push.news .content ul img{margin-bottom:-2px}.feeds .news .push.news .content ul .text.truncate{width:80%;margin-bottom:-5px}.feeds .news .commit-id{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace}.feeds .news code{padding:1px;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px;word-break:break-all}.feeds .list .header .ui.label{margin-top:-4px;padding:4px 5px;font-weight:400}.feeds .list .header .plus.icon{margin-top:5px}.feeds .list ul{list-style:none;margin:0;padding-left:0}.feeds .list ul li:not(:last-child){border-bottom:1px solid #EAEAEA}.feeds .list ul li.private{background-color:#fcf8e9}.feeds .list ul li a{padding:6px 1.2em;display:block}.feeds .list ul li a .octicon{color:#888}.feeds .list ul li a .octicon.rear{font-size:15px}.feeds .list ul li a .star-num{font-size:12px}.feeds .list .repo-owner-name-list .item-name{max-width:70%;margin-bottom:-4px}.feeds .list #collaborative-repo-list .owner-and-repo{max-width:80%;margin-bottom:-5px}.feeds .list #collaborative-repo-list .owner-name{max-width:120px;margin-bottom:-5px}.admin{padding-top:15px}.admin .table.segment{padding:0;font-size:13px}.admin .table.segment:not(.striped){padding-top:5px}.admin .table.segment:not(.striped) thead th:last-child{padding-right:5px!important}.admin .table.segment th{padding-top:5px;padding-bottom:5px}.admin .table.segment:not(.select) td:first-of-type,.admin .table.segment:not(.select) th:first-of-type{padding-left:15px!important}.admin .ui.header,.admin .ui.segment{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.admin.user .email{max-width:200px}.admin dl.admin-dl-horizontal{padding:20px;margin:0}.admin dl.admin-dl-horizontal dd{margin-left:275px}.admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin.config #test-mail-btn{margin-left:5px}.explore{padding-top:15px}.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}.explore .navbar .octicon{width:16px;text-align:center;margin-right:5px}.ui.repository.list .item{padding-bottom:25px}.ui.repository.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.repository.list .item .ui.header{font-size:1.5rem;padding-bottom:10px}.ui.repository.list .item .ui.header .name{word-break:break-all}.ui.repository.list .item .ui.header .metas{color:#888;font-size:14px;font-weight:400}.ui.repository.list .item .ui.header .metas span:not(:last-child){margin-right:5px}.ui.repository.list .item .time{font-size:12px;color:grey}.ui.repository.list .item .ui.tags{margin-bottom:1em}.ui.repository.branches .time{font-size:12px;color:grey}.ui.user.list .item{padding-bottom:25px}.ui.user.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.user.list .item .ui.avatar.image{width:40px;height:40px}.ui.user.list .item .description{margin-top:5px}.ui.user.list .item .description .octicon:not(:first-child){margin-left:5px}.ui.user.list .item .description a{color:#333}.ui.user.list .item .description a:hover{text-decoration:underline}.ui.button.add-code-comment{font-size:14px;height:16px;padding:2px 0 0;position:relative;width:16px;z-index:5;float:left;margin:-2px -10px -2px -20px;opacity:0;transition:transform .1s ease-in-out;transform:scale(1,1)}.ui.button.add-code-comment:hover{transform:scale(1.2,1.2)}.focus-lines-new .ui.button.add-code-comment.add-code-comment-right,.focus-lines-old .ui.button.add-code-comment.add-code-comment-left{opacity:1}.comment-code-cloud{padding:4px;position:relative;border:1px solid #f1f1f1;margin:13px 10px 5px auto}.comment-code-cloud:before{content:" ";width:0;height:0;border-left:13px solid transparent;border-right:13px solid transparent;border-bottom:13px solid #f1f1f1;left:20px;position:absolute;top:-13px}.comment-code-cloud .attached.tab{border:none;padding:0;margin:0}.comment-code-cloud .attached.tab.markdown{padding:1em;min-height:168px}.comment-code-cloud .attached.header{padding:.1rem 1rem}.comment-code-cloud .right.menu.options .item{padding:.85714286em .442857em;cursor:pointer}.comment-code-cloud .ui.form textarea{border:0}.comment-code-cloud .ui.attached.tabular.menu{background:#f7f7f7;border:1px solid #d4d4d5;padding-top:5px;padding-left:5px;margin-top:0}.comment-code-cloud .footer{border-top:1px solid #f1f1f1;margin-top:10px}.comment-code-cloud .footer .markdown-info{display:inline-block;margin:5px 0;font-size:12px;color:rgba(0,0,0,.6)}.comment-code-cloud .footer .ui.right.floated{padding-top:6px}.comment-code-cloud .footer:after{clear:both;content:"";display:block}.comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em}.comment-code-cloud form.comment-form-reply{margin:0 0 0 4em}.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} \ No newline at end of file +.tribute-container{box-shadow:0 1px 3px 1px #c7c7c7} +.tribute-container ul{background:#fff} +.tribute-container li{padding:8px 12px;border-bottom:1px solid #dcdcdc} +.tribute-container li img{display:inline-block;vertical-align:middle;width:28px;height:28px;margin-right:5px} +.tribute-container li span.fullname{font-weight:400;font-size:.8rem;margin-left:3px} +.tribute-container li.highlight,.tribute-container li:hover{background:#2185D0;color:#fff} +.emoji{width:1.5em;height:1.5em;display:inline-block;background-size:contain} +.ui.label .emoji{height:1.2em!important} +@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-regular.eot);src:url(../vendor/assets/lato-fonts/lato-regular.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-regular.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-regular.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-regular.ttf) format('truetype');font-weight:400;font-style:normal} +@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-italic.eot);src:url(../vendor/assets/lato-fonts/lato-italic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-italic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-italic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-italic.ttf) format('truetype');font-weight:400;font-style:italic} +@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bold.eot);src:url(../vendor/assets/lato-fonts/lato-bold.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bold.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bold.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bold.ttf) format('truetype');font-weight:700;font-style:normal} +@font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot);src:url(../vendor/assets/lato-fonts/lato-bolditalic.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-bolditalic.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-bolditalic.ttf) format('truetype');font-weight:700;font-style:italic} +@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Medium');font-weight:400} +@font-face{font-family:'Yu Gothic';src:local('Yu Gothic Bold');font-weight:700} +textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif} +.markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif} +h1,h2,h3,h4,h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif} +.home .hero h1,.home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif} +.ui.accordion .title:not(.ui),.ui.button,.ui.card>.content>.header.ui.card>.content>.header,.ui.category.search>.results .category>.name,.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=file],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url],.ui.header,.ui.input input,.ui.input>input,.ui.items>.item>.content>.header,.ui.language>.menu>.item,.ui.list .list>.item .header,.ui.list>.item .header,.ui.menu,.ui.message .header,.ui.modal>.header,.ui.popup>.header,.ui.search>.results .result .title,.ui.search>.results>.message .header,.ui.statistic>.label,.ui.statistic>.value,.ui.statistics .statistic>.label,.ui.statistics .statistic>.value,.ui.steps .step .title,.ui.text.container,body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif} +body{background-color:#fff;overflow-y:auto;-webkit-font-smoothing:antialiased;display:flex;flex-direction:column} +:lang(ja) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif} +:lang(ja) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif} +:lang(ja) h1,:lang(ja) h2,:lang(ja) h3,:lang(ja) h4,:lang(ja) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif} +:lang(ja) .home .hero h1,:lang(ja) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif} +.ui.language>.menu>.item:lang(ja),:lang(ja) .ui.accordion .title:not(.ui),:lang(ja) .ui.button,:lang(ja) .ui.card>.content>.header.ui.card>.content>.header,:lang(ja) .ui.category.search>.results .category>.name,:lang(ja) .ui.form input:not([type]),:lang(ja) .ui.form input[type=date],:lang(ja) .ui.form input[type=datetime-local],:lang(ja) .ui.form input[type=email],:lang(ja) .ui.form input[type=file],:lang(ja) .ui.form input[type=number],:lang(ja) .ui.form input[type=password],:lang(ja) .ui.form input[type=search],:lang(ja) .ui.form input[type=tel],:lang(ja) .ui.form input[type=text],:lang(ja) .ui.form input[type=time],:lang(ja) .ui.form input[type=url],:lang(ja) .ui.header,:lang(ja) .ui.input input,:lang(ja) .ui.input>input,:lang(ja) .ui.items>.item>.content>.header,:lang(ja) .ui.list .list>.item .header,:lang(ja) .ui.list>.item .header,:lang(ja) .ui.menu,:lang(ja) .ui.message .header,:lang(ja) .ui.modal>.header,:lang(ja) .ui.popup>.header,:lang(ja) .ui.search>.results .result .title,:lang(ja) .ui.search>.results>.message .header,:lang(ja) .ui.statistic>.label,:lang(ja) .ui.statistic>.value,:lang(ja) .ui.statistics .statistic>.label,:lang(ja) .ui.statistics .statistic>.value,:lang(ja) .ui.steps .step .title,:lang(ja) .ui.text.container,:lang(ja) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Hiragino Kaku Gothic ProN','Yu Gothic','Source Han Sans JP','Noto Sans CJK JP','Droid Sans Japanese',Meiryo,'MS PGothic',sans-serif} +:lang(zh-CN) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif} +:lang(zh-CN) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif} +:lang(zh-CN) h1,:lang(zh-CN) h2,:lang(zh-CN) h3,:lang(zh-CN) h4,:lang(zh-CN) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif} +:lang(zh-CN) .home .hero h1,:lang(zh-CN) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif} +.ui.language>.menu>.item:lang(zh-CN),:lang(zh-CN) .ui.accordion .title:not(.ui),:lang(zh-CN) .ui.button,:lang(zh-CN) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-CN) .ui.category.search>.results .category>.name,:lang(zh-CN) .ui.form input:not([type]),:lang(zh-CN) .ui.form input[type=date],:lang(zh-CN) .ui.form input[type=datetime-local],:lang(zh-CN) .ui.form input[type=email],:lang(zh-CN) .ui.form input[type=file],:lang(zh-CN) .ui.form input[type=number],:lang(zh-CN) .ui.form input[type=password],:lang(zh-CN) .ui.form input[type=search],:lang(zh-CN) .ui.form input[type=tel],:lang(zh-CN) .ui.form input[type=text],:lang(zh-CN) .ui.form input[type=time],:lang(zh-CN) .ui.form input[type=url],:lang(zh-CN) .ui.header,:lang(zh-CN) .ui.input input,:lang(zh-CN) .ui.input>input,:lang(zh-CN) .ui.items>.item>.content>.header,:lang(zh-CN) .ui.list .list>.item .header,:lang(zh-CN) .ui.list>.item .header,:lang(zh-CN) .ui.menu,:lang(zh-CN) .ui.message .header,:lang(zh-CN) .ui.modal>.header,:lang(zh-CN) .ui.popup>.header,:lang(zh-CN) .ui.search>.results .result .title,:lang(zh-CN) .ui.search>.results>.message .header,:lang(zh-CN) .ui.statistic>.label,:lang(zh-CN) .ui.statistic>.value,:lang(zh-CN) .ui.statistics .statistic>.label,:lang(zh-CN) .ui.statistics .statistic>.value,:lang(zh-CN) .ui.steps .step .title,:lang(zh-CN) .ui.text.container,:lang(zh-CN) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang SC','Hiragino Sans GB','Source Han Sans CN','Source Han Sans SC','Noto Sans CJK SC','Microsoft YaHei','Heiti SC',SimHei,sans-serif} +:lang(zh-TW) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif} +:lang(zh-TW) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif} +:lang(zh-TW) h1,:lang(zh-TW) h2,:lang(zh-TW) h3,:lang(zh-TW) h4,:lang(zh-TW) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif} +:lang(zh-TW) .home .hero h1,:lang(zh-TW) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif} +.ui.language>.menu>.item:lang(zh-TW),:lang(zh-TW) .ui.accordion .title:not(.ui),:lang(zh-TW) .ui.button,:lang(zh-TW) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-TW) .ui.category.search>.results .category>.name,:lang(zh-TW) .ui.form input:not([type]),:lang(zh-TW) .ui.form input[type=date],:lang(zh-TW) .ui.form input[type=datetime-local],:lang(zh-TW) .ui.form input[type=email],:lang(zh-TW) .ui.form input[type=file],:lang(zh-TW) .ui.form input[type=number],:lang(zh-TW) .ui.form input[type=password],:lang(zh-TW) .ui.form input[type=search],:lang(zh-TW) .ui.form input[type=tel],:lang(zh-TW) .ui.form input[type=text],:lang(zh-TW) .ui.form input[type=time],:lang(zh-TW) .ui.form input[type=url],:lang(zh-TW) .ui.header,:lang(zh-TW) .ui.input input,:lang(zh-TW) .ui.input>input,:lang(zh-TW) .ui.items>.item>.content>.header,:lang(zh-TW) .ui.list .list>.item .header,:lang(zh-TW) .ui.list>.item .header,:lang(zh-TW) .ui.menu,:lang(zh-TW) .ui.message .header,:lang(zh-TW) .ui.modal>.header,:lang(zh-TW) .ui.popup>.header,:lang(zh-TW) .ui.search>.results .result .title,:lang(zh-TW) .ui.search>.results>.message .header,:lang(zh-TW) .ui.statistic>.label,:lang(zh-TW) .ui.statistic>.value,:lang(zh-TW) .ui.statistics .statistic>.label,:lang(zh-TW) .ui.statistics .statistic>.value,:lang(zh-TW) .ui.steps .step .title,:lang(zh-TW) .ui.text.container,:lang(zh-TW) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang TC','Hiragino Sans TC','Source Han Sans TW','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU,sans-serif} +:lang(zh-HK) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif} +:lang(zh-HK) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif} +:lang(zh-HK) h1,:lang(zh-HK) h2,:lang(zh-HK) h3,:lang(zh-HK) h4,:lang(zh-HK) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif} +:lang(zh-HK) .home .hero h1,:lang(zh-HK) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif} +.ui.language>.menu>.item:lang(zh-HK),:lang(zh-HK) .ui.accordion .title:not(.ui),:lang(zh-HK) .ui.button,:lang(zh-HK) .ui.card>.content>.header.ui.card>.content>.header,:lang(zh-HK) .ui.category.search>.results .category>.name,:lang(zh-HK) .ui.form input:not([type]),:lang(zh-HK) .ui.form input[type=date],:lang(zh-HK) .ui.form input[type=datetime-local],:lang(zh-HK) .ui.form input[type=email],:lang(zh-HK) .ui.form input[type=file],:lang(zh-HK) .ui.form input[type=number],:lang(zh-HK) .ui.form input[type=password],:lang(zh-HK) .ui.form input[type=search],:lang(zh-HK) .ui.form input[type=tel],:lang(zh-HK) .ui.form input[type=text],:lang(zh-HK) .ui.form input[type=time],:lang(zh-HK) .ui.form input[type=url],:lang(zh-HK) .ui.header,:lang(zh-HK) .ui.input input,:lang(zh-HK) .ui.input>input,:lang(zh-HK) .ui.items>.item>.content>.header,:lang(zh-HK) .ui.list .list>.item .header,:lang(zh-HK) .ui.list>.item .header,:lang(zh-HK) .ui.menu,:lang(zh-HK) .ui.message .header,:lang(zh-HK) .ui.modal>.header,:lang(zh-HK) .ui.popup>.header,:lang(zh-HK) .ui.search>.results .result .title,:lang(zh-HK) .ui.search>.results>.message .header,:lang(zh-HK) .ui.statistic>.label,:lang(zh-HK) .ui.statistic>.value,:lang(zh-HK) .ui.statistics .statistic>.label,:lang(zh-HK) .ui.statistics .statistic>.value,:lang(zh-HK) .ui.steps .step .title,:lang(zh-HK) .ui.text.container,:lang(zh-HK) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'PingFang HK','Hiragino Sans TC','Source Han Sans HK','Source Han Sans TC','Noto Sans CJK TC','Microsoft JhengHei','Heiti TC',PMingLiU_HKSCS,PMingLiU,sans-serif} +:lang(ko) textarea{font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif} +:lang(ko) .markdown:not(code){font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif} +:lang(ko) h1,:lang(ko) h2,:lang(ko) h3,:lang(ko) h4,:lang(ko) h5{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif} +:lang(ko) .home .hero h1,:lang(ko) .home .hero h2{font-family:'PT Sans Narrow',Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif} +.ui.language>.menu>.item:lang(ko),:lang(ko) .ui.accordion .title:not(.ui),:lang(ko) .ui.button,:lang(ko) .ui.card>.content>.header.ui.card>.content>.header,:lang(ko) .ui.category.search>.results .category>.name,:lang(ko) .ui.form input:not([type]),:lang(ko) .ui.form input[type=date],:lang(ko) .ui.form input[type=datetime-local],:lang(ko) .ui.form input[type=email],:lang(ko) .ui.form input[type=file],:lang(ko) .ui.form input[type=number],:lang(ko) .ui.form input[type=password],:lang(ko) .ui.form input[type=search],:lang(ko) .ui.form input[type=tel],:lang(ko) .ui.form input[type=text],:lang(ko) .ui.form input[type=time],:lang(ko) .ui.form input[type=url],:lang(ko) .ui.header,:lang(ko) .ui.input input,:lang(ko) .ui.input>input,:lang(ko) .ui.items>.item>.content>.header,:lang(ko) .ui.list .list>.item .header,:lang(ko) .ui.list>.item .header,:lang(ko) .ui.menu,:lang(ko) .ui.message .header,:lang(ko) .ui.modal>.header,:lang(ko) .ui.popup>.header,:lang(ko) .ui.search>.results .result .title,:lang(ko) .ui.search>.results>.message .header,:lang(ko) .ui.statistic>.label,:lang(ko) .ui.statistic>.value,:lang(ko) .ui.statistics .statistic>.label,:lang(ko) .ui.statistics .statistic>.value,:lang(ko) .ui.steps .step .title,:lang(ko) .ui.text.container,:lang(ko) body{font-family:Lato,-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial,'Apple SD Gothic Neo',NanumBarunGothic,'Malgun Gothic',Gulim,Dotum,'Nanum Gothic','Source Han Sans KR','Noto Sans CJK KR',sans-serif} +img{border-radius:3px} +table{border-collapse:collapse} +a{cursor:pointer} +.rounded{border-radius:.28571429rem!important} +code,pre{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto} +code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word} +.dont-break-out{overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto} +.full.height{flex-grow:1;padding-bottom:80px} +.following.bar{z-index:900;left:0;margin:0!important} +.following.bar.light{background-color:#fff;border-bottom:1px solid #DDD;box-shadow:0 2px 3px rgba(0,0,0,.04)} +.following.bar .column .menu{margin-top:0} +.following.bar .top.menu a.item.brand{padding-left:0} +.following.bar .brand .ui.mini.image{width:30px} +.following.bar .top.menu .dropdown.item.active,.following.bar .top.menu .dropdown.item:hover,.following.bar .top.menu a.item:hover{background-color:transparent} +.following.bar .top.menu a.item:hover{color:rgba(0,0,0,.45)} +.following.bar .top.menu .menu{z-index:900} +.following.bar .octicon{margin-right:.75em} +.following.bar .octicon.fitted{margin-right:0} +.following.bar .searchbox{background-color:#f4f4f4!important} +.following.bar .searchbox:focus{background-color:#e9e9e9!important} +.following.bar .text .octicon{width:16px;text-align:center} +.following.bar #navbar{width:100vw;min-height:52px;padding:0 .5rem} +.following.bar #navbar .brand{margin:0} +@media only screen and (max-width:767px){.following.bar #navbar:not(.shown)>:not(:first-child){display:none} +} +.right.stackable.menu{margin-left:auto;display:flex;align-items:inherit;flex-direction:inherit} +.ui.left{float:left} +.ui.right{float:right} +.ui.button,.ui.menu .item{-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto} +.ui.container.fluid.padded{padding:0 10px 0 10px} +.ui.form .ui.button{font-weight:400} +.ui.floating.label{z-index:10} +.ui.transparent.label{background-color:transparent} +.ui.menu,.ui.segment,.ui.vertical.menu{box-shadow:none} +.ui .menu:not(.vertical) .item>.button.compact{padding:.58928571em 1.125em} +.ui .menu:not(.vertical) .item>.button.small{font-size:.92857143rem} +.ui.menu .ui.dropdown.item .menu .item{margin-right:auto} +.ui.dropdown .menu>.item>.floating.label{z-index:11} +.ui.dropdown .menu .menu>.item>.floating.label{z-index:21} +.ui .text.red{color:#d95c5c!important} +.ui .text.red a{color:#d95c5c!important} +.ui .text.red a:hover{color:#E67777!important} +.ui .text.blue{color:#428bca!important} +.ui .text.blue a{color:#15c!important} +.ui .text.blue a:hover{color:#428bca!important} +.ui .text.black{color:#444} +.ui .text.black:hover{color:#000} +.ui .text.grey{color:#767676!important} +.ui .text.grey a{color:#444!important} +.ui .text.grey a:hover{color:#000!important} +.ui .text.light.grey{color:#888!important} +.ui .text.green{color:#6cc644!important} +.ui .text.purple{color:#6e5494!important} +.ui .text.yellow{color:#FBBD08!important} +.ui .text.gold{color:#a1882b!important} +.ui .text.left{text-align:left!important} +.ui .text.right{text-align:right!important} +.ui .text.small{font-size:.75em} +.ui .text.normal{font-weight:400} +.ui .text.bold{font-weight:700} +.ui .text.italic{font-style:italic} +.ui .text.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block} +.ui .text.thin{font-weight:400} +.ui .text.middle{vertical-align:middle} +.ui .message{text-align:center} +.ui.bottom.attached.message{font-weight:700;text-align:left;color:#000} +.ui.bottom.attached.message .pull-right{color:#000} +.ui.bottom.attached.message .pull-right>span,.ui.bottom.attached.message>span{color:#21ba45} +.ui .header>i+.content{padding-left:.75rem;vertical-align:middle} +.ui .warning.header{background-color:#F9EDBE!important;border-color:#F0C36D} +.ui .warning.segment{border-color:#F0C36D} +.ui .info.segment{border:1px solid #c5d5dd} +.ui .info.segment.top{background-color:#e6f1f6!important} +.ui .info.segment.top h3,.ui .info.segment.top h4{margin-top:0} +.ui .info.segment.top h3:last-child{margin-top:4px} +.ui .info.segment.top>:last-child{margin-bottom:0} +.ui .normal.header{font-weight:400} +.ui .avatar.image{border-radius:3px} +.ui .form .fake{display:none!important} +.ui .form .sub.field{margin-left:25px} +.ui .sha.label{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;font-size:13px;padding:6px 10px 4px 10px;font-weight:400;margin:0 6px} +.ui.status.buttons .octicon{margin-right:4px} +.ui.inline.delete-button{padding:8px 15px;font-weight:400} +.ui .background.red{background-color:#d95c5c!important} +.ui .background.blue{background-color:#428bca!important} +.ui .background.black{background-color:#444} +.ui .background.grey{background-color:#767676!important} +.ui .background.light.grey{background-color:#888!important} +.ui .background.green{background-color:#6cc644!important} +.ui .background.purple{background-color:#6e5494!important} +.ui .background.yellow{background-color:#FBBD08!important} +.ui .background.gold{background-color:#a1882b!important} +.ui .branch-tag-choice{line-height:20px} +@media only screen and (max-width:767px){.ui.pagination.menu .item.navigation span.navigation_label,.ui.pagination.menu .item:not(.active):not(.navigation){display:none} +} +.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} +.ui.floating.dropdown .overflow.menu .scrolling.menu.items{border-radius:0!important;box-shadow:none!important;border-bottom:1px solid rgba(34,36,38,.15)} +.user-menu>.item{width:100%;border-radius:0!important} +.scrolling.menu .item.selected{font-weight:700!important} +footer{background-color:#fff;border-top:1px solid #d6d6d6;width:100%;flex-basis:40px;color:#888} +footer .container{width:100vw!important;padding:0 .5rem} +footer .container .fa{width:16px;text-align:center;color:#428bca} +footer .container .links>*{border-left:1px solid #d6d6d6;padding-left:8px;margin-left:5px} +footer .container .links>:first-child{border-left:none} +footer .ui.language .menu{max-height:500px;overflow-y:auto;margin-bottom:7px} +footer .ui.left,footer .ui.right{line-height:40px} +.hide{display:none} +.hide.show-outdated{display:none!important} +.hide.hide-outdated{display:none!important} +.center{text-align:center} +.img-1{width:2px!important;height:2px!important} +.img-2{width:4px!important;height:4px!important} +.img-3{width:6px!important;height:6px!important} +.img-4{width:8px!important;height:8px!important} +.img-5{width:10px!important;height:10px!important} +.img-6{width:12px!important;height:12px!important} +.img-7{width:14px!important;height:14px!important} +.img-8{width:16px!important;height:16px!important} +.img-9{width:18px!important;height:18px!important} +.img-10{width:20px!important;height:20px!important} +.img-11{width:22px!important;height:22px!important} +.img-12{width:24px!important;height:24px!important} +.img-13{width:26px!important;height:26px!important} +.img-14{width:28px!important;height:28px!important} +.img-15{width:30px!important;height:30px!important} +.img-16{width:32px!important;height:32px!important} +@media only screen and (min-width:768px){.mobile-only,.ui.button.mobile-only{display:none} +.sr-mobile-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0} +} +@media only screen and (max-width:767px){.not-mobile{display:none} +} +.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0} +.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} +@media only screen and (max-width:991px) and (min-width:768px){.ui.container{width:95%} +} +.hljs{background:inherit!important;padding:0!important} +.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important} +@media only screen and (max-width:1200px){.ui.menu.new-menu{overflow-x:auto!important;justify-content:left!important;padding-bottom:5px} +.ui.menu.new-menu::-webkit-scrollbar{height:8px;display:none} +.ui.menu.new-menu:hover::-webkit-scrollbar{display:block} +.ui.menu.new-menu::-webkit-scrollbar-track{background:rgba(0,0,0,.01)} +.ui.menu.new-menu::-webkit-scrollbar-thumb{background:rgba(0,0,0,.2)} +.ui.menu.new-menu:after{position:absolute;margin-top:-15px;display:block;background-image:linear-gradient(to right,rgba(255,255,255,0),#fff 100%);content:' ';right:0;height:53px;z-index:1000;width:60px;clear:none;visibility:visible} +.ui.menu.new-menu a.item:last-child{padding-right:30px!important} +} +[v-cloak]{display:none!important} +.repos-search{padding-bottom:0!important} +.repos-filter{margin-top:0!important;border-bottom-width:0!important;margin-bottom:2px!important} +#user-heatmap{width:107%;text-align:center} +#user-heatmap svg:not(:root){overflow:inherit;padding:0!important} +@media only screen and (max-width:1200px){#user-heatmap{display:none} +} +.heatmap-color-0{background-color:#f4f4f4} +.heatmap-color-1{background-color:#d7e5db} +.heatmap-color-2{background-color:#adc7ab} +.heatmap-color-3{background-color:#83a87b} +.heatmap-color-4{background-color:#598a4b} +.heatmap-color-5{background-color:#2f6b1b} +.archived-icon{color:#b3b3b3!important} +.oauth2-authorize-application-box{margin-top:3em!important} +.ui.tabular.menu .item{color:rgba(0,0,0,.5)} +.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)} +.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)} +.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word} +.markdown:not(code).ui.segment{padding:3em} +.markdown:not(code).file-view{padding:2em 2em 2em!important} +.markdown:not(code)>:first-child{margin-top:0!important} +.markdown:not(code)>:last-child{margin-bottom:0!important} +.markdown:not(code) a:not([href]){color:inherit;text-decoration:none} +.markdown:not(code) .absent{color:#c00} +.markdown:not(code) .anchor{position:absolute;top:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px} +.markdown:not(code) .anchor:focus{outline:0} +.markdown:not(code) h1,.markdown:not(code) h2,.markdown:not(code) h3,.markdown:not(code) h4,.markdown:not(code) h5,.markdown:not(code) h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4} +.markdown:not(code) h1:first-of-type,.markdown:not(code) h2:first-of-type,.markdown:not(code) h3:first-of-type,.markdown:not(code) h4:first-of-type,.markdown:not(code) h5:first-of-type,.markdown:not(code) h6:first-of-type{margin-top:0!important} +.markdown:not(code) h1 .octicon-link,.markdown:not(code) h2 .octicon-link,.markdown:not(code) h3 .octicon-link,.markdown:not(code) h4 .octicon-link,.markdown:not(code) h5 .octicon-link,.markdown:not(code) h6 .octicon-link{display:none;color:#000;vertical-align:middle} +.markdown:not(code) h1:hover .anchor,.markdown:not(code) h2:hover .anchor,.markdown:not(code) h3:hover .anchor,.markdown:not(code) h4:hover .anchor,.markdown:not(code) h5:hover .anchor,.markdown:not(code) h6:hover .anchor{padding-left:8px;margin-left:-30px;text-decoration:none} +.markdown:not(code) h1:hover .anchor .octicon-link,.markdown:not(code) h2:hover .anchor .octicon-link,.markdown:not(code) h3:hover .anchor .octicon-link,.markdown:not(code) h4:hover .anchor .octicon-link,.markdown:not(code) h5:hover .anchor .octicon-link,.markdown:not(code) h6:hover .anchor .octicon-link{display:inline-block} +.markdown:not(code) h1 code,.markdown:not(code) h1 tt,.markdown:not(code) h2 code,.markdown:not(code) h2 tt,.markdown:not(code) h3 code,.markdown:not(code) h3 tt,.markdown:not(code) h4 code,.markdown:not(code) h4 tt,.markdown:not(code) h5 code,.markdown:not(code) h5 tt,.markdown:not(code) h6 code,.markdown:not(code) h6 tt{font-size:inherit} +.markdown:not(code) h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee} +.markdown:not(code) h1 .anchor{line-height:1} +.markdown:not(code) h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee} +.markdown:not(code) h2 .anchor{line-height:1} +.markdown:not(code) h3{font-size:1.5em;line-height:1.43} +.markdown:not(code) h3 .anchor{line-height:1.2} +.markdown:not(code) h4{font-size:1.25em} +.markdown:not(code) h4 .anchor{line-height:1.2} +.markdown:not(code) h5{font-size:1em} +.markdown:not(code) h5 .anchor{line-height:1.1} +.markdown:not(code) h6{font-size:1em;color:#777} +.markdown:not(code) h6 .anchor{line-height:1.1} +.markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px} +.markdown:not(code) blockquote{margin-left:0} +.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none} +.markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em} +.markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none} +.markdown:not(code) ol ol,.markdown:not(code) ol ul,.markdown:not(code) ul ol,.markdown:not(code) ul ul{margin-top:0;margin-bottom:0} +.markdown:not(code) ol ol,.markdown:not(code) ul ol{list-style-type:lower-roman} +.markdown:not(code) li>p{margin-top:0} +.markdown:not(code) dl{padding:0} +.markdown:not(code) dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700} +.markdown:not(code) dl dd{padding:0 16px;margin-bottom:16px} +.markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd} +.markdown:not(code) blockquote>:first-child{margin-top:0} +.markdown:not(code) blockquote>:last-child{margin-bottom:0} +.markdown:not(code) table{width:auto;overflow:auto;word-break:normal;word-break:keep-all;display:block} +.markdown:not(code) table th{font-weight:700} +.markdown:not(code) table td,.markdown:not(code) table th{padding:6px 13px!important;border:1px solid #ddd!important} +.markdown:not(code) table tr{background-color:#fff;border-top:1px solid #ccc} +.markdown:not(code) table tr:nth-child(2n){background-color:#f8f8f8} +.markdown:not(code) img{max-width:100%;box-sizing:border-box} +.markdown:not(code) .emoji{max-width:none} +.markdown:not(code) span.frame{display:block;overflow:hidden} +.markdown:not(code) span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd} +.markdown:not(code) span.frame span img{display:block;float:left} +.markdown:not(code) span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333} +.markdown:not(code) span.align-center{display:block;overflow:hidden;clear:both} +.markdown:not(code) span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center} +.markdown:not(code) span.align-center span img{margin:0 auto;text-align:center} +.markdown:not(code) span.align-right{display:block;overflow:hidden;clear:both} +.markdown:not(code) span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right} +.markdown:not(code) span.align-right span img{margin:0;text-align:right} +.markdown:not(code) span.float-left{display:block;float:left;margin-right:13px;overflow:hidden} +.markdown:not(code) span.float-left span{margin:13px 0 0} +.markdown:not(code) span.float-right{display:block;float:right;margin-left:13px;overflow:hidden} +.markdown:not(code) span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right} +.markdown:not(code) code,.markdown:not(code) tt{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px} +.markdown:not(code) code:after,.markdown:not(code) code:before,.markdown:not(code) tt:after,.markdown:not(code) tt:before{letter-spacing:-.2em;content:"\00a0"} +.markdown:not(code) code br,.markdown:not(code) tt br{display:none} +.markdown:not(code) del code{text-decoration:inherit} +.markdown:not(code) pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0} +.markdown:not(code) .highlight{margin-bottom:16px} +.markdown:not(code) .highlight pre,.markdown:not(code) pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px} +.markdown:not(code) .highlight pre{margin-bottom:0;word-break:normal} +.markdown:not(code) pre{word-wrap:normal} +.markdown:not(code) pre code,.markdown:not(code) pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0} +.markdown:not(code) pre code:after,.markdown:not(code) pre code:before,.markdown:not(code) pre tt:after,.markdown:not(code) pre tt:before{content:normal} +.markdown:not(code) kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:solid 1px #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb} +.markdown:not(code) input[type=checkbox]{vertical-align:middle!important} +.markdown:not(code) .csv-data td,.markdown:not(code) .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap} +.markdown:not(code) .csv-data .blob-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0} +.markdown:not(code) .csv-data tr{border-top:0} +.markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0} +.markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em} +.home .logo{max-width:220px} +@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em} +.home .hero h2{font-size:2em} +} +@media only screen and (min-width:768px){.home .hero h1{font-size:5.5em} +.home .hero h2{font-size:3em} +} +.home .hero .octicon{color:#5aa509;font-size:40px;width:50px} +.home .hero.header{font-size:20px} +.home p.large{font-size:16px} +.home .stackable{padding-top:30px} +.home a{color:#5aa509} +.signup{padding-top:15px} +@media only screen and (max-width:880px){footer .ui.container .left,footer .ui.container .right{display:block;text-align:center;float:none} +} +.install{padding-top:45px} +.install form label{text-align:right;width:320px!important} +.install form input{width:35%!important} +.install form .field{text-align:left} +.install form .field .help{margin-left:335px!important} +.install form .field.optional .title{margin-left:38%} +.install .ui .checkbox{margin-left:40%!important} +.install .ui .checkbox label{width:auto!important} +.form .help{color:#999;padding-top:.6em;padding-bottom:.6em;display:inline-block} +.ui.attached.header{background:#f0f0f0} +.ui.attached.header .right{margin-top:-5px} +.ui.attached.header .right .button{padding:8px 10px;font-weight:400} +#create-page-form form{margin:auto} +#create-page-form form .ui.message{text-align:center} +@media only screen and (min-width:768px){#create-page-form form{width:800px!important} +#create-page-form form .header{padding-left:280px!important} +#create-page-form form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word} +#create-page-form form .help{margin-left:265px!important} +#create-page-form form .optional .title{margin-left:250px!important} +#create-page-form form input,#create-page-form form textarea{width:50%!important} +} +@media only screen and (max-width:767px){#create-page-form form .optional .title{margin-left:15px} +#create-page-form form .inline.field>label{display:block} +} +.signin .oauth2 div{display:inline-block} +.signin .oauth2 div p{margin:10px 5px 0 0;float:left} +.signin .oauth2 a{margin-right:3px} +.signin .oauth2 a:last-child{margin-right:0} +.signin .oauth2 img{width:32px;height:32px} +.signin .oauth2 img.openidConnect{width:auto} +@media only screen and (min-width:768px){.g-recaptcha{margin:0 auto!important;width:304px;padding-left:30px} +} +@media screen and (max-height:575px){#rc-imageselect,.g-recaptcha{transform:scale(.77);transform-origin:0 0} +} +.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{margin:auto} +.user.activate form .ui.message,.user.forgot.password form .ui.message,.user.reset.password form .ui.message,.user.signin form .ui.message,.user.signup form .ui.message{text-align:center} +@media only screen and (min-width:768px){.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:800px!important} +.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:280px!important} +.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word} +.user.activate form .help,.user.forgot.password form .help,.user.reset.password form .help,.user.signin form .help,.user.signup form .help{margin-left:265px!important} +.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:250px!important} +.user.activate form input,.user.activate form textarea,.user.forgot.password form input,.user.forgot.password form textarea,.user.reset.password form input,.user.reset.password form textarea,.user.signin form input,.user.signin form textarea,.user.signup form input,.user.signup form textarea{width:50%!important} +} +@media only screen and (max-width:767px){.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:15px} +.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{display:block} +} +.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:700px!important} +.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:0!important;text-align:center} +.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{width:200px} +@media only screen and (max-width:768px){.user.activate form .inline.field>label,.user.activate form input,.user.forgot.password form .inline.field>label,.user.forgot.password form input,.user.reset.password form .inline.field>label,.user.reset.password form input,.user.signin form .inline.field>label,.user.signin form input,.user.signup form .inline.field>label,.user.signup form input{width:100%!important} +} +.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{margin:auto} +.repository.new.fork form .ui.message,.repository.new.migrate form .ui.message,.repository.new.repo form .ui.message{text-align:center} +@media only screen and (min-width:768px){.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{width:800px!important} +.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:280px!important} +.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word} +.repository.new.fork form .help,.repository.new.migrate form .help,.repository.new.repo form .help{margin-left:265px!important} +.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:250px!important} +.repository.new.fork form input,.repository.new.fork form textarea,.repository.new.migrate form input,.repository.new.migrate form textarea,.repository.new.repo form input,.repository.new.repo form textarea{width:50%!important} +} +@media only screen and (max-width:767px){.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:15px} +.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{display:block} +} +.repository.new.fork form .dropdown .dropdown.icon,.repository.new.migrate form .dropdown .dropdown.icon,.repository.new.repo form .dropdown .dropdown.icon{margin-top:-7px!important;padding-bottom:5px} +.repository.new.fork form .dropdown .text,.repository.new.migrate form .dropdown .text,.repository.new.repo form .dropdown .text{margin-right:0!important} +.repository.new.fork form .dropdown .text i,.repository.new.migrate form .dropdown .text i,.repository.new.repo form .dropdown .text i{margin-right:0!important} +.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:0!important;text-align:center} +@media only screen and (max-width:768px){.repository.new.fork form .selection.dropdown,.repository.new.fork form input,.repository.new.fork form label,.repository.new.migrate form .selection.dropdown,.repository.new.migrate form input,.repository.new.migrate form label,.repository.new.repo form .selection.dropdown,.repository.new.repo form input,.repository.new.repo form label{width:100%!important} +.repository.new.fork form .field a,.repository.new.fork form .field button,.repository.new.migrate form .field a,.repository.new.migrate form .field button,.repository.new.repo form .field a,.repository.new.repo form .field button{margin-bottom:1em;width:100%} +} +@media only screen and (min-width:768px){.repository.new.repo .ui.form #auto-init{margin-left:265px!important} +} +.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:50%!important} +@media only screen and (max-width:768px){.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:100%!important} +} +.new.webhook form .help{margin-left:25px} +.new.webhook .events.fields .column{padding-left:40px} +.githook textarea{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +@media only screen and (max-width:768px){.new.org .ui.form .field a,.new.org .ui.form .field button{margin-bottom:1em;width:100%} +.new.org .ui.form .field input{width:100%!important} +} +.repository{padding-top:15px} +.repository .repo-header .ui.compact.menu{margin-left:1rem} +.repository .repo-header .ui.header{margin-top:0} +.repository .repo-header .mega-octicon{width:30px;font-size:30px} +.repository .repo-header .ui.huge.breadcrumb{font-weight:400;font-size:1.5rem} +.repository .repo-header .fork-flag{margin-left:36px;margin-top:3px;display:block;font-size:12px;white-space:nowrap} +.repository .repo-header .octicon.octicon-repo-forked{margin-top:-1px;font-size:15px} +.repository .repo-header .button{margin-top:2px;margin-bottom:2px} +.repository .tabs .navbar{justify-content:initial} +.repository .navbar{display:flex;justify-content:space-between} +.repository .navbar .ui.label{margin-left:7px;padding:3px 5px} +.repository .owner.dropdown{min-width:40%!important} +.repository #file-buttons{margin-left:auto!important;font-weight:400} +.repository #file-buttons .ui.button{padding:8px 10px;font-weight:400} +.repository .metas .menu{max-height:300px;overflow-x:auto} +.repository .metas .ui.list .hide{display:none!important} +.repository .metas .ui.list .item{padding:0} +.repository .metas .ui.list .label.color{padding:0 8px;margin-right:5px} +.repository .metas .ui.list a{margin:2px 0} +.repository .metas .ui.list a .text{color:#444} +.repository .metas .ui.list a .text:hover{color:#000} +.repository .metas #deadlineForm input{width:12.8rem;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap} +.repository .header-wrapper{background-color:#FAFAFA;margin-top:-15px;padding-top:15px} +.repository .header-wrapper .ui.tabs.divider{border-bottom:none} +.repository .header-wrapper .ui.tabular .octicon{margin-right:5px} +.repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px} +.repository .filter.menu .octicon{float:left;margin:5px -7px 0 -5px;width:16px} +.repository .filter.menu.labels .octicon{margin:-2px -7px 0 -5px} +.repository .filter.menu .text{margin-left:.9em} +.repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important} +.repository .filter.menu .dropdown.item{margin:1px;padding-right:0} +.repository .select-label .item{max-width:250px;overflow:hidden;text-overflow:ellipsis} +.repository .select-label .desc{padding-left:16px} +.repository .ui.tabs.container{margin-top:14px;margin-bottom:0} +.repository .ui.tabs.container .ui.menu{border-bottom:none} +.repository .ui.tabs.divider{margin-top:0;margin-bottom:20px} +.repository #clone-panel{width:350px} +@media only screen and (max-width:768px){.repository #clone-panel{width:100%} +} +.repository #clone-panel input{border-radius:0;padding:5px 10px;width:50%} +.repository #clone-panel .clone.button{font-size:13px;padding:0 5px} +.repository #clone-panel .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem} +.repository #clone-panel .icon.button{padding:0 10px} +.repository #clone-panel .dropdown .menu{right:0!important;left:auto!important} +.repository.file.list .repo-description{display:flex;justify-content:space-between;align-items:center} +.repository.file.list #repo-desc{font-size:1.2em} +.repository.file.list .choose.reference .header .icon{font-size:1.4em} +.repository.file.list .repo-path .divider,.repository.file.list .repo-path .section{display:inline} +.repository.file.list #file-buttons{font-weight:400} +.repository.file.list #file-buttons .ui.button{padding:8px 10px;font-weight:400} +@media only screen and (max-width:768px){.repository.file.list #file-buttons .ui.tiny.blue.buttons{width:100%} +} +.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400} +.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px} +.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777} +.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px} +.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf} +.repository.file.list #repo-files-table td{padding-top:8px;padding-bottom:8px;overflow:initial} +.repository.file.list #repo-files-table td.name{max-width:150px} +.repository.file.list #repo-files-table td.message{max-width:400px} +.repository.file.list #repo-files-table td.age{width:120px} +.repository.file.list #repo-files-table td .truncate{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap} +.repository.file.list #repo-files-table td.message .isSigned{cursor:default} +.repository.file.list #repo-files-table tr:hover{background-color:#ffE} +.repository.file.list #repo-files-table .jumpable-path{color:#888} +.repository.file.list .non-diff-file-content .header .icon{font-size:1em} +.repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px} +.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon{display:inline-block;padding:5px;margin-left:5px;line-height:1;color:#767676;vertical-align:middle;background:0 0;border:0;outline:0} +.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover{color:#4078c0} +.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover{color:#bd2c00} +.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon.disabled{color:#bbb;cursor:default} +.repository.file.list .non-diff-file-content .header .file-actions #delete-file-form{display:inline-block} +.repository.file.list .non-diff-file-content .view-raw{padding:5px} +.repository.file.list .non-diff-file-content .view-raw *{max-width:100%} +.repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px} +.repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em} +.repository.file.list .non-diff-file-content pre{overflow:auto} +.repository.file.list .non-diff-file-content .code-view *{font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px} +.repository.file.list .non-diff-file-content .code-view table{width:100%} +.repository.file.list .non-diff-file-content .code-view .lines-num{vertical-align:top;text-align:right;color:#999;background:#f5f5f5;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} +.repository.file.list .non-diff-file-content .code-view .lines-num span{line-height:20px;padding:0 10px;cursor:pointer;display:block} +.repository.file.list .non-diff-file-content .code-view .lines-code,.repository.file.list .non-diff-file-content .code-view .lines-num{padding:0} +.repository.file.list .non-diff-file-content .code-view .lines-code .hljs,.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-code pre,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs,.repository.file.list .non-diff-file-content .code-view .lines-num ol,.repository.file.list .non-diff-file-content .code-view .lines-num pre{background-color:#fff;margin:0;padding:0!important} +.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-code ol li,.repository.file.list .non-diff-file-content .code-view .lines-code pre li,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-num ol li,.repository.file.list .non-diff-file-content .code-view .lines-num pre li{display:block;width:100%} +.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-code ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-code pre li.active,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-num ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-num pre li.active{background:#ffd} +.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-code ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-code pre li:before,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-num ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-num pre li:before{content:' '} +.repository.file.list .non-diff-file-content .code-view .lines-commit{vertical-align:top;color:#999;padding:0;background:#f5f5f5;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none} +.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info{width:350px;max-width:350px;display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 0 0 10px} +.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data{display:flex;font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial} +.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-message{flex-grow:2;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;line-height:20px} +.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-avatar,.repository.file.list .non-diff-file-content .code-view .lines-commit .blame-info .blame-data .blame-time{flex-shrink:0} +.repository.file.list .non-diff-file-content .code-view .lines-commit .ui.avatar.image{height:18px;width:18px} +.repository.file.list .non-diff-file-content .code-view .lines-code .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-commit .bottom-line,.repository.file.list .non-diff-file-content .code-view .lines-num .bottom-line{border-bottom:1px solid #eaecef} +.repository.file.list .non-diff-file-content .code-view .active{background:#ffd} +.repository.file.list .sidebar{padding-left:0} +.repository.file.list .sidebar .octicon{width:16px} +.repository.file.editor .treepath{width:100%} +.repository.file.editor .treepath input{vertical-align:middle;box-shadow:rgba(0,0,0,.0745098) 0 1px 2px inset;width:inherit;padding:7px 8px;margin-right:5px} +.repository.file.editor .tabular.menu .octicon{margin-right:5px} +.repository.file.editor .commit-form-wrapper{padding-left:64px} +.repository.file.editor .commit-form-wrapper .commit-avatar{float:left;margin-left:-64px;width:3em;height:auto} +.repository.file.editor .commit-form-wrapper .commit-form{position:relative;padding:15px;margin-bottom:10px;border:1px solid #ddd;border-radius:3px} +.repository.file.editor .commit-form-wrapper .commit-form:after,.repository.file.editor .commit-form-wrapper .commit-form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} +.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} +.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#fff} +.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name{display:inline-block;padding:3px 6px;font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.65);background-color:rgba(209,227,237,.45);border-radius:3px} +.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input{position:relative;margin-left:25px} +.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input input{width:240px!important;padding-left:26px!important} +.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .octicon-git-branch{position:absolute;top:9px;left:10px;color:#b0c4ce} +.repository.options #interval{width:100px!important;min-width:100px} +.repository.options .danger .item{padding:20px 15px} +.repository.options .danger .ui.divider{margin:0} +.repository.new.issue .comment.form .comment .avatar{width:3em} +.repository.new.issue .comment.form .content{margin-left:4em} +.repository.new.issue .comment.form .content:after,.repository.new.issue .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} +.repository.new.issue .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.new.issue .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} +.repository.new.issue .comment.form .content:after{border-right-color:#fff} +.repository.new.issue .comment.form .content .markdown{font-size:14px} +.repository.new.issue .comment.form .metas{min-width:220px} +.repository.new.issue .comment.form .metas .filter.menu{max-height:300px;overflow-x:auto} +.repository.view.issue .title{padding-bottom:0!important} +.repository.view.issue .title h1{font-weight:300;font-size:2.3rem;margin-bottom:5px} +.repository.view.issue .title h1 .ui.input{font-size:.5em;vertical-align:top;width:50%;min-width:600px} +.repository.view.issue .title h1 .ui.input input{font-size:1.5em;padding:6px 10px} +.repository.view.issue .title .index{font-weight:300;color:#aaa;letter-spacing:-1px} +.repository.view.issue .title .label{margin-right:10px} +.repository.view.issue .title .edit-zone{margin-top:10px} +.repository.view.issue .pull-desc code{color:#0166E6} +.repository.view.issue .pull.tabular.menu{margin-bottom:10px} +.repository.view.issue .pull.tabular.menu .octicon{margin-right:5px} +.repository.view.issue .pull.tab.segment{border:none;padding:10px 0 0;box-shadow:none;background-color:inherit} +.repository.view.issue .pull .merge.box .avatar{margin-left:10px;margin-top:10px} +.repository.view.issue .pull .review-item .avatar,.repository.view.issue .pull .review-item .type-icon{float:none;display:inline-block;text-align:center;vertical-align:middle} +.repository.view.issue .pull .review-item .avatar .octicon,.repository.view.issue .pull .review-item .type-icon .octicon{width:23px;font-size:23px;margin-top:.45em} +.repository.view.issue .pull .review-item .text{margin:.3em 0 .5em .5em} +.repository.view.issue .pull .review-item .type-icon{float:right;margin-right:1em} +.repository.view.issue .pull .review-item .divider{margin:.5rem 0} +.repository.view.issue .pull .review-item .review-content{padding:1em 0 1em 3.8em} +.repository.view.issue .comment-list:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1} +.repository.view.issue .comment-list .comment .avatar{width:3em} +.repository.view.issue .comment-list .comment .tag{color:#767676;margin-top:3px;padding:2px 5px;font-size:12px;border:1px solid rgba(0,0,0,.1);border-radius:3px} +.repository.view.issue .comment-list .comment .actions .item{float:left} +.repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px} +.repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px} +.repository.view.issue .comment-list .comment .content{margin-left:4em} +.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px} +.repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} +.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} +.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px} +.repository.view.issue .comment-list .comment .content .markdown{font-size:14px} +.repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic} +.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5} +.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.images::after{clear:both;content:' ';display:block} +.repository.view.issue .comment-list .comment .content>.bottom.segment a{display:block;float:left;margin:5px;padding:5px;height:150px;border:solid 1px #eee;border-radius:3px;max-width:150px;background-color:#fff} +.repository.view.issue .comment-list .comment .content>.bottom.segment a:before{content:' ';display:inline-block;height:100%;vertical-align:middle} +.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.image{max-height:100%;width:auto;margin:0;vertical-align:middle} +.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image{font-size:128px;color:#000} +.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image:hover{color:#000} +.repository.view.issue .comment-list .comment .ui.form .field:first-child{clear:none} +.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:none;padding:10px 0 0} +.repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +.repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px} +.repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px} +.repository.view.issue .comment-list .event .octicon{width:30px;float:left;text-align:center} +.repository.view.issue .comment-list .event .octicon.octicon-circle-slash{margin-top:5px;margin-left:-34.5px;font-size:20px;color:#bd2c00} +.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644} +.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:3px;margin-left:-31px;margin-right:-1px;font-size:25px} +.repository.view.issue .comment-list .event .octicon.octicon-comment{margin-top:4px;margin-left:-35px;font-size:24px} +.repository.view.issue .comment-list .event .octicon.octicon-eye{margin-top:3px;margin-left:-35px;margin-right:0;font-size:22px} +.repository.view.issue .comment-list .event .octicon.octicon-x{margin-left:-33px;font-size:25px} +.repository.view.issue .comment-list .event .detail{font-size:.9rem;margin-top:5px;margin-left:35px} +.repository.view.issue .comment-list .event .detail .octicon.octicon-git-commit{margin-top:2px} +.repository.view.issue .ui.segment.metas{margin-top:-3px} +.repository.view.issue .ui.participants img{margin-top:5px;margin-right:5px} +.repository.view.issue .ui.depending .item.is-closed .title{text-decoration:line-through} +.repository .comment.form .ui.comments{margin-top:-12px;max-width:100%} +.repository .comment.form .content .field:first-child{clear:none} +.repository .comment.form .content .form:after,.repository .comment.form .content .form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} +.repository .comment.form .content .form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository .comment.form .content .form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} +.repository .comment.form .content .form:after{border-right-color:#fff} +.repository .comment.form .content .tab.segment{border:none;padding:10px 0 0} +.repository .comment.form .content textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +.repository .label.list{list-style:none;padding-top:15px} +.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA} +.repository .label.list .item a{font-size:15px;padding-top:5px;padding-right:10px;color:#666} +.repository .label.list .item a:hover{color:#000} +.repository .label.list .item a.open-issues{margin-right:30px} +.repository .label.list .item .ui.label{font-size:1em} +.repository .milestone.list{list-style:none;padding-top:15px} +.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA} +.repository .milestone.list>.item>a{padding-top:5px;padding-right:10px;color:#000} +.repository .milestone.list>.item>a:hover{color:#4078c0} +.repository .milestone.list>.item .ui.progress{width:40%;padding:0;border:0;margin:0} +.repository .milestone.list>.item .ui.progress .bar{height:20px} +.repository .milestone.list>.item .meta{color:#999;padding-top:5px} +.repository .milestone.list>.item .meta .issue-stats .octicon{padding-left:5px} +.repository .milestone.list>.item .meta .overdue{color:red} +.repository .milestone.list>.item .operate{margin-top:-15px} +.repository .milestone.list>.item .operate>a{font-size:15px;padding-top:5px;padding-right:10px;color:#666} +.repository .milestone.list>.item .operate>a:hover{color:#000} +.repository .milestone.list>.item .content{padding-top:10px} +.repository.new.milestone textarea{height:200px} +.repository.new.milestone #deadline{width:150px} +.repository.compare.pull .choose.branch .octicon{padding-right:10px} +.repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} +.repository.compare.pull .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.compare.pull .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} +.repository.compare.pull .comment.form .content:after{border-right-color:#fff} +.repository .filter.dropdown .menu{margin-top:1px!important} +.repository.branches .commit-divergence .bar-group{position:relative;float:left;padding-bottom:6px;width:90px} +.repository.branches .commit-divergence .bar-group:last-child{border-left:1px solid #b4b4b4} +.repository.branches .commit-divergence .count{margin:0 3px} +.repository.branches .commit-divergence .count.count-ahead{text-align:left} +.repository.branches .commit-divergence .count.count-behind{text-align:right} +.repository.branches .commit-divergence .bar{height:4px;position:absolute;background-color:#d4d4d5} +.repository.branches .commit-divergence .bar.bar-behind{right:0} +.repository.branches .commit-divergence .bar.bar-ahead{left:0} +.repository.commits .header .search input{font-weight:400;padding:5px 10px} +.repository #commits-table thead th:first-of-type{padding-left:15px} +.repository #commits-table thead .sha{width:140px} +.repository #commits-table thead .shatd{text-align:center} +.repository #commits-table td.sha .sha.label{margin:0} +.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important} +.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #BBB} +.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#FAFAFA;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #BBB;border-top-left-radius:0;border-bottom-left-radius:0} +.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21BA45;background:rgba(33,186,69,.1)} +.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon{border-left:1px solid rgba(33,186,69,.5)} +.repository .diff-detail-box{padding:7px 0;background:#fff;line-height:30px} +.repository .diff-detail-box>div:after{clear:both;content:"";display:block} +.repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px} +.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #DDD;padding-left:6px} +.repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle} +.repository .diff-detail-box span.status.modify{background-color:#f0db88} +.repository .diff-detail-box span.status.add{background-color:#b4e2b4} +.repository .diff-detail-box span.status.del{background-color:#e9aeae} +.repository .diff-detail-box span.status.rename{background-color:#dad8ff} +.repository .diff-detail-box .detail-files{background:#fff;margin:0} +.repository .diff-box .header{display:flex;align-items:center} +.repository .diff-box .header .count{margin-right:12px;font-size:13px;flex:0 0 auto} +.repository .diff-box .header .count .bar{background-color:#bd2c00;height:12px;width:40px;display:inline-block;margin:2px 4px 0 4px;vertical-align:text-top} +.repository .diff-box .header .count .bar .add{background-color:#55a532;height:12px} +.repository .diff-box .header .file{flex:1;color:#888;word-break:break-all} +.repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto} +.repository .diff-file-box .header{background-color:#f7f7f7} +.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#A7A7A7;background:#fafafa;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top} +.repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center} +.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #DDD} +.repository .diff-file-box .code-diff{font-size:12px} +.repository .diff-file-box .code-diff td{padding:0 0 0 10px;border-top:none} +.repository .diff-file-box .code-diff pre{margin:0} +.repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px} +.repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%} +.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#F0F0F0!important;border-color:#D2CECE!important;padding-top:8px;padding-bottom:8px} +.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99} +.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9} +.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important} +.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important} +.repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%} +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#fafafa} +.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#ffe0e0!important;border-color:#f1c0c0!important} +.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#d6fcd6!important;border-color:#c1e9c1!important} +.repository .diff-file-box .code-diff-split tbody tr td:nth-child(3){border-left-width:1px;border-left-style:solid} +.repository .diff-file-box.file-content{clear:right} +.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px} +.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden} +.repository .repo-search-result{padding-top:10px;padding-bottom:10px} +.repository .repo-search-result .lines-num a{color:inherit} +.repository.quickstart .guide .item{padding:1em} +.repository.quickstart .guide .item small{font-weight:400} +.repository.quickstart .guide .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem} +.repository.quickstart .guide .ui.action.small.input{width:100%} +.repository.quickstart .guide #repo-clone-url{border-radius:0;padding:5px 10px;font-size:1.2em} +.repository.release #release-list{border-top:1px solid #DDD;margin-top:20px;padding-top:15px} +.repository.release #release-list>li{list-style:none} +.repository.release #release-list>li .detail,.repository.release #release-list>li .meta{padding-top:30px;padding-bottom:40px} +.repository.release #release-list>li .meta{text-align:right;position:relative} +.repository.release #release-list>li .meta .tag:not(.icon){display:block;margin-top:15px} +.repository.release #release-list>li .meta .commit{display:block;margin-top:10px} +.repository.release #release-list>li .detail{border-left:1px solid #DDD} +.repository.release #release-list>li .detail .author img{margin-bottom:-3px} +.repository.release #release-list>li .detail .download{margin-top:20px} +.repository.release #release-list>li .detail .download>a .octicon{margin-left:5px;margin-right:5px} +.repository.release #release-list>li .detail .download .list{padding-left:0;border-top:1px solid #eee} +.repository.release #release-list>li .detail .download .list li{list-style:none;display:block;padding-top:8px;padding-bottom:8px;border-bottom:1px solid #eee} +.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #FFF} +.repository.new.release .target{min-width:500px} +.repository.new.release .target #tag-name{margin-top:-4px} +.repository.new.release .target .at{margin-left:-5px;margin-right:5px} +.repository.new.release .target .dropdown.icon{margin:0;padding-top:3px} +.repository.new.release .target .selection.dropdown{padding-top:10px;padding-bottom:10px} +.repository.new.release .prerelease.field{margin-bottom:0} +@media only screen and (max-width:438px){.repository.new.release .field button,.repository.new.release .field input{width:100%} +} +@media only screen and (max-width:768px){.repository.new.release .field button{margin-bottom:1em} +} +.repository.forks .list{margin-top:0} +.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #DDD} +.repository.forks .list .item .ui.avatar{float:left;margin-right:5px} +.repository.forks .list .item .link{padding-top:5px} +.repository.wiki.start .ui.segment{padding-top:70px;padding-bottom:100px} +.repository.wiki.start .ui.segment .mega-octicon{font-size:48px} +.repository.wiki.new .CodeMirror .CodeMirror-code{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment{background:inherit} +.repository.wiki.new .editor-preview{background-color:#fff} +.repository.wiki.view .choose.page{margin-top:-5px} +.repository.wiki.view .ui.sub.header{text-transform:none} +.repository.wiki.view>.markdown{padding:15px 30px} +.repository.wiki.view>.markdown h1:first-of-type,.repository.wiki.view>.markdown h2:first-of-type,.repository.wiki.view>.markdown h3:first-of-type,.repository.wiki.view>.markdown h4:first-of-type,.repository.wiki.view>.markdown h5:first-of-type,.repository.wiki.view>.markdown h6:first-of-type{margin-top:0} +@media only screen and (max-width:767px){.repository.wiki .dividing.header .stackable.grid .button{margin-top:2px;margin-bottom:2px} +} +.repository.settings.collaboration .collaborator.list{padding:0} +.repository.settings.collaboration .collaborator.list>.item{margin:0;line-height:2em} +.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #DDD} +.repository.settings.collaboration #repo-collab-form #search-user-box .results{left:7px} +.repository.settings.collaboration #repo-collab-form .ui.button{margin-left:5px;margin-top:-3px} +.repository.settings.branches .protected-branches .selection.dropdown{width:300px} +.repository.settings.branches .protected-branches .item{border:1px solid #eaeaea;padding:10px 15px} +.repository.settings.branches .protected-branches .item:not(:last-child){border-bottom:0} +.repository.settings.branches .branch-protection .help{margin-left:26px;padding-top:0} +.repository.settings.branches .branch-protection .fields{margin-left:20px;display:block} +.repository.settings.branches .branch-protection .whitelist{margin-left:26px} +.repository.settings.branches .branch-protection .whitelist .dropdown img{display:inline-block} +.repository.settings.webhook .events .column{padding-bottom:0} +.repository.settings.webhook .events .help{font-size:13px;margin-left:26px;padding-top:0} +.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #A3C293;border-right:1px solid #A3C293} +.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #A3C293} +.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #A3C293} +.repository .ui.segment.sub-menu{padding:7px;line-height:0} +.repository .ui.segment.sub-menu .list{width:100%;display:flex} +.repository .ui.segment.sub-menu .list .item{width:100%;border-radius:3px} +.repository .ui.segment.sub-menu .list .item a{color:#000} +.repository .ui.segment.sub-menu .list .item a:hover{color:#666} +.repository .ui.segment.sub-menu .list .item.active{background:rgba(0,0,0,.05)} +.repository .segment.reactions.dropdown .menu,.repository .select-reaction.dropdown .menu{right:0!important;left:auto!important} +.repository .segment.reactions.dropdown .menu>.header,.repository .select-reaction.dropdown .menu>.header{margin:.75rem 0 .5rem} +.repository .segment.reactions.dropdown .menu>.item,.repository .select-reaction.dropdown .menu>.item{float:left;padding:.5rem .5rem!important} +.repository .segment.reactions.dropdown .menu>.item img.emoji,.repository .select-reaction.dropdown .menu>.item img.emoji{margin-right:0} +.repository .segment.reactions{padding:.3em 1em} +.repository .segment.reactions .ui.label{padding:.4em} +.repository .segment.reactions .ui.label.disabled{cursor:default} +.repository .segment.reactions .ui.label>img{height:1.5em!important} +.repository .segment.reactions .select-reaction{float:none} +.repository .segment.reactions .select-reaction:not(.active) a{display:none} +.repository .segment.reactions:hover .select-reaction a{display:block} +.user-cards .list{padding:0} +.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left} +.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px} +.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400} +.user-cards .list .item .meta{margin-top:5px} +#search-repo-box .results .result .image,#search-user-box .results .result .image{float:left;margin-right:8px;width:2em;height:2em} +#search-repo-box .results .result .content,#search-user-box .results .result .content{margin:6px 0} +#issue-filters.hide{display:none} +#issue-actions{margin-top:-1rem!important} +#issue-actions.hide{display:none} +.ui.checkbox.issue-checkbox{vertical-align:middle} +.issue.list{list-style:none} +.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #AAA} +.issue.list>.item .title{color:#444;font-size:15px;font-weight:700;margin:0 6px} +.issue.list>.item .title:hover{color:#000} +.issue.list>.item .comment{padding-right:10px;color:#666} +.issue.list>.item .desc{padding-top:5px;color:#999} +.issue.list>.item .desc .checklist{padding-left:5px} +.issue.list>.item .desc .checklist .progress-bar{margin-left:2px;width:80px;height:6px;display:inline-block;background-color:#eee;overflow:hidden;border-radius:3px;vertical-align:2px!important} +.issue.list>.item .desc .checklist .progress-bar .progress{background-color:#ccc;display:block;height:100%} +.issue.list>.item .desc a.milestone{padding-left:5px;color:#999!important} +.issue.list>.item .desc a.milestone:hover{color:#000!important} +.issue.list>.item .desc .assignee{margin-top:-5px;margin-right:5px} +.issue.list>.item .desc .overdue{color:red} +.page.buttons{padding-top:15px} +.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087F7;box-shadow:none!important} +.ui.form .dropzone .dz-error-message{top:140px} +.settings .content{margin-top:2px} +.settings .content .segment,.settings .content>.header{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)} +.settings .list>.item .green{color:#21BA45} +.settings .list>.item:not(:first-child){border-top:1px solid #eaeaea;padding:1rem;margin:15px -1rem -1rem -1rem} +.settings .list>.item>.mega-octicon{display:table-cell} +.settings .list>.item>.mega-octicon+.content{display:table-cell;padding:0 0 0 .5em;vertical-align:top} +.settings .list>.item .info{margin-top:10px} +.settings .list>.item .info .tab.segment{border:none;padding:10px 0 0} +.settings .list.key .meta{padding-top:5px;color:#666} +.settings .list.email>.item:not(:first-child){min-height:60px} +.settings .list.collaborator>.item{padding:0} +.ui.vertical.menu .header.item{font-size:1.1em;background:#f0f0f0} +.edit-label.modal .form .column,.new-label.segment .form .column{padding-right:0} +.edit-label.modal .form .buttons,.new-label.segment .form .buttons{margin-left:auto;padding-top:15px} +.edit-label.modal .form .color.picker.column,.new-label.segment .form .color.picker.column{width:auto} +.edit-label.modal .form .color.picker.column .color-picker,.new-label.segment .form .color.picker.column .color-picker{height:35px;width:auto;padding-left:30px} +.edit-label.modal .form .minicolors-swatch.minicolors-sprite,.new-label.segment .form .minicolors-swatch.minicolors-sprite{top:10px;left:10px;width:15px;height:15px} +.edit-label.modal .form .precolors,.new-label.segment .form .precolors{padding-left:0;padding-right:0;margin:3px 10px auto 10px;width:120px} +.edit-label.modal .form .precolors .color,.new-label.segment .form .precolors .color{float:left;width:15px;height:15px} +#avatar-arrow:after,#avatar-arrow:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} +#avatar-arrow:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +#avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} +#delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important} +.tab-size-1{-moz-tab-size:1!important;-o-tab-size:1!important;tab-size:1!important} +.tab-size-2{-moz-tab-size:2!important;-o-tab-size:2!important;tab-size:2!important} +.tab-size-3{-moz-tab-size:3!important;-o-tab-size:3!important;tab-size:3!important} +.tab-size-4{-moz-tab-size:4!important;-o-tab-size:4!important;tab-size:4!important} +.tab-size-5{-moz-tab-size:5!important;-o-tab-size:5!important;tab-size:5!important} +.tab-size-6{-moz-tab-size:6!important;-o-tab-size:6!important;tab-size:6!important} +.tab-size-7{-moz-tab-size:7!important;-o-tab-size:7!important;tab-size:7!important} +.tab-size-8{-moz-tab-size:8!important;-o-tab-size:8!important;tab-size:8!important} +.tab-size-9{-moz-tab-size:9!important;-o-tab-size:9!important;tab-size:9!important} +.tab-size-10{-moz-tab-size:10!important;-o-tab-size:10!important;tab-size:10!important} +.tab-size-11{-moz-tab-size:11!important;-o-tab-size:11!important;tab-size:11!important} +.tab-size-12{-moz-tab-size:12!important;-o-tab-size:12!important;tab-size:12!important} +.tab-size-13{-moz-tab-size:13!important;-o-tab-size:13!important;tab-size:13!important} +.tab-size-14{-moz-tab-size:14!important;-o-tab-size:14!important;tab-size:14!important} +.tab-size-15{-moz-tab-size:15!important;-o-tab-size:15!important;tab-size:15!important} +.tab-size-16{-moz-tab-size:16!important;-o-tab-size:16!important;tab-size:16!important} +.stats-table{display:table;width:100%} +.stats-table .table-cell{display:table-cell} +.stats-table .table-cell.tiny{height:.5em} +tbody.commit-list{vertical-align:baseline} +.commit-body{white-space:pre-wrap} +@media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px} +.ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0} +} +#topic_edit{margin-top:5px} +#repo-topics{margin-top:5px} +.repo-topic{cursor:pointer} +#new-dependency-drop-list.ui.selection.dropdown{min-width:0;width:100%;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap} +#new-dependency-drop-list .text{width:100%;overflow:hidden} +#manage_topic{font-size:12px} +.label+#manage_topic{margin-left:5px} +.repo-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap} +.repo-header .repo-buttons{display:flex;align-items:center} +.repo-buttons .disabled-repo-button .label{opacity:.5} +.repo-buttons .disabled-repo-button a.button{opacity:.5;cursor:not-allowed} +.repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important} +.repo-buttons .ui.labeled.button>.label{border-left:none!important;margin:0!important} +.CodeMirror{font:14px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +.CodeMirror.cm-s-default{border-radius:3px;padding:0!important} +.CodeMirror .cm-comment{background:inherit!important} +.repository.file.editor .tab[data-tab=write]{padding:0!important} +.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:none!important} +.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:none;border-right:none;border-bottom:none} +.organization{padding-top:15px} +.organization .head .ui.header .text{vertical-align:middle;font-size:1.6rem;margin-left:15px} +.organization .head .ui.header .ui.right{margin-top:5px} +.organization.new.org form{margin:auto} +.organization.new.org form .ui.message{text-align:center} +@media only screen and (min-width:768px){.organization.new.org form{width:800px!important} +.organization.new.org form .header{padding-left:280px!important} +.organization.new.org form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word} +.organization.new.org form .help{margin-left:265px!important} +.organization.new.org form .optional .title{margin-left:250px!important} +.organization.new.org form input,.organization.new.org form textarea{width:50%!important} +} +@media only screen and (max-width:767px){.organization.new.org form .optional .title{margin-left:15px} +.organization.new.org form .inline.field>label{display:block} +} +.organization.new.org form .header{padding-left:0!important;text-align:center} +.organization.options input{min-width:300px} +.organization.profile #org-avatar{width:100px;height:100px;margin-right:15px} +.organization.profile #org-info .ui.header{font-size:36px;margin-bottom:0} +.organization.profile #org-info .desc{font-size:16px;margin-bottom:10px} +.organization.profile #org-info .meta .item{display:inline-block;margin-right:10px} +.organization.profile #org-info .meta .item .icon{margin-right:5px} +.organization.profile .ui.top.header .ui.right{margin-top:0} +.organization.profile .teams .item{padding:10px 15px} +.organization.profile .members .ui.avatar,.organization.teams .members .ui.avatar{width:48px;height:48px;margin-right:5px} +.organization.invite #invite-box{margin:50px auto auto;width:500px!important} +.organization.invite #invite-box #search-user-box input{margin-left:0;width:300px} +.organization.invite #invite-box .ui.button{margin-left:5px;margin-top:-3px} +.organization.members .list .item{margin-left:0;margin-right:0;border-bottom:1px solid #eee} +.organization.members .list .item .ui.avatar{width:48px;height:48px} +.organization.members .list .item .meta{line-height:24px} +.organization.teams .detail .item{padding:10px 15px} +.organization.teams .detail .item:not(:last-child){border-bottom:1px solid #eee} +.organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px} +.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #DDD} +.organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px} +.organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0} +.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px} +.user:not(.icon){padding-top:15px} +.user.profile .ui.card .username{display:block} +.user.profile .ui.card .extra.content{padding:0} +.user.profile .ui.card .extra.content ul{margin:0;padding:0} +.user.profile .ui.card .extra.content ul li{padding:10px;list-style:none} +.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #eaeaea} +.user.profile .ui.card .extra.content ul li .octicon{margin-left:1px;margin-right:5px} +.user.profile .ui.card .extra.content ul li.follow .ui.button{width:100%} +@media only screen and (max-width:768px){.user.profile .ui.card #profile-avatar{height:250px;overflow:hidden} +.user.profile .ui.card #profile-avatar img{max-height:768px;max-width:768px} +} +@media only screen and (max-width:768px){.user.profile .ui.card{width:100%} +} +.user.profile .ui.repository.list{margin-top:25px} +.user.profile #loading-heatmap{margin-bottom:1em} +.user.followers .header.name{font-size:20px;line-height:24px;vertical-align:middle} +.user.followers .follow .ui.button{padding:8px 15px} +.user.notification .octicon{float:left;font-size:2em} +.user.notification .content{float:left;margin-left:7px} +.user.notification table form{display:inline-block} +.user.notification table button{padding:3px 3px 3px 5px} +.user.notification table tr{cursor:pointer} +.user.notification .octicon.green{color:#21ba45} +.user.notification .octicon.red{color:#d01919} +.user.notification .octicon.purple{color:#a333c8} +.user.notification .octicon.blue{color:#2185d0} +.user.link-account:not(.icon){padding-top:15px;padding-bottom:5px} +.user.settings .iconFloat{float:left} +.dashboard{padding-top:15px} +.dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px} +.dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none} +.dashboard.feeds .filter.menu .item,.dashboard.issues .filter.menu .item{text-align:left} +.dashboard.feeds .filter.menu .item .text,.dashboard.issues .filter.menu .item .text{height:16px;vertical-align:middle} +.dashboard.feeds .filter.menu .item .text.truncate,.dashboard.issues .filter.menu .item .text.truncate{width:85%} +.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:7px;left:90%;width:15%} +@media only screen and (max-width:768px){.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:10px;left:auto;width:auto;right:13px} +} +.dashboard.feeds .filter.menu .jump.item,.dashboard.issues .filter.menu .jump.item{margin:1px;padding-right:0} +.dashboard.feeds .filter.menu .menu,.dashboard.issues .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important} +@media only screen and (max-width:768px){.dashboard.feeds .filter.menu,.dashboard.issues .filter.menu{width:100%} +} +.dashboard.feeds .right.stackable.menu>.item.active,.dashboard.issues .right.stackable.menu>.item.active{color:#d9453d} +.dashboard .dashboard-repos{margin:0 1px} +.dashboard .dashboard-navbar{width:100vw;padding:0 .5rem} +.feeds .news>.ui.grid{margin-left:auto;margin-right:auto} +.feeds .news .ui.avatar{margin-top:13px} +.feeds .news .time-since{font-size:13px} +.feeds .news .issue.title{width:80%} +.feeds .news .push.news .content ul{font-size:13px;list-style:none;padding-left:10px} +.feeds .news .push.news .content ul img{margin-bottom:-2px} +.feeds .news .push.news .content ul .text.truncate{width:80%;margin-bottom:-5px} +.feeds .news .commit-id{font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +.feeds .news code{padding:1px;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px;word-break:break-all} +.feeds .list .header .ui.label{margin-top:-4px;padding:4px 5px;font-weight:400} +.feeds .list .header .plus.icon{margin-top:5px} +.feeds .list ul{list-style:none;margin:0;padding-left:0} +.feeds .list ul li:not(:last-child){border-bottom:1px solid #EAEAEA} +.feeds .list ul li.private{background-color:#fcf8e9} +.feeds .list ul li a{padding:6px 1.2em;display:block} +.feeds .list ul li a .octicon{color:#888} +.feeds .list ul li a .octicon.rear{font-size:15px} +.feeds .list ul li a .star-num{font-size:12px} +.feeds .list .repo-owner-name-list .item-name{max-width:70%;margin-bottom:-4px} +.feeds .list #collaborative-repo-list .owner-and-repo{max-width:80%;margin-bottom:-5px} +.feeds .list #collaborative-repo-list .owner-name{max-width:120px;margin-bottom:-5px} +.admin{padding-top:15px} +.admin .table.segment{padding:0;font-size:13px} +.admin .table.segment:not(.striped){padding-top:5px} +.admin .table.segment:not(.striped) thead th:last-child{padding-right:5px!important} +.admin .table.segment th{padding-top:5px;padding-bottom:5px} +.admin .table.segment:not(.select) td:first-of-type,.admin .table.segment:not(.select) th:first-of-type{padding-left:15px!important} +.admin .ui.header,.admin .ui.segment{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)} +.admin.user .email{max-width:200px} +.admin dl.admin-dl-horizontal{padding:20px;margin:0} +.admin dl.admin-dl-horizontal dd{margin-left:275px} +.admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.admin.config #test-mail-btn{margin-left:5px} +.explore{padding-top:15px} +.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important} +.explore .navbar .octicon{width:16px;text-align:center;margin-right:5px} +.ui.repository.list .item{padding-bottom:25px} +.ui.repository.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px} +.ui.repository.list .item .ui.header{font-size:1.5rem;padding-bottom:10px} +.ui.repository.list .item .ui.header .name{word-break:break-all} +.ui.repository.list .item .ui.header .metas{color:#888;font-size:14px;font-weight:400} +.ui.repository.list .item .ui.header .metas span:not(:last-child){margin-right:5px} +.ui.repository.list .item .time{font-size:12px;color:grey} +.ui.repository.list .item .ui.tags{margin-bottom:1em} +.ui.repository.branches .time{font-size:12px;color:grey} +.ui.user.list .item{padding-bottom:25px} +.ui.user.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px} +.ui.user.list .item .ui.avatar.image{width:40px;height:40px} +.ui.user.list .item .description{margin-top:5px} +.ui.user.list .item .description .octicon:not(:first-child){margin-left:5px} +.ui.user.list .item .description a{color:#333} +.ui.user.list .item .description a:hover{text-decoration:underline} +.ui.button.add-code-comment{font-size:14px;height:16px;padding:2px 0 0;position:relative;width:16px;z-index:5;float:left;margin:-2px -10px -2px -20px;opacity:0;transition:transform .1s ease-in-out;transform:scale(1,1)} +.ui.button.add-code-comment:hover{transform:scale(1.2,1.2)} +.focus-lines-new .ui.button.add-code-comment.add-code-comment-right,.focus-lines-old .ui.button.add-code-comment.add-code-comment-left{opacity:1} +.comment-code-cloud{padding:4px;position:relative;border:1px solid #f1f1f1;margin:13px 10px 5px auto} +.comment-code-cloud:before{content:" ";width:0;height:0;border-left:13px solid transparent;border-right:13px solid transparent;border-bottom:13px solid #f1f1f1;left:20px;position:absolute;top:-13px} +.comment-code-cloud .attached.tab{border:none;padding:0;margin:0} +.comment-code-cloud .attached.tab.markdown{padding:1em;min-height:168px} +.comment-code-cloud .attached.header{padding:.1rem 1rem} +.comment-code-cloud .right.menu.options .item{padding:.85714286em .442857em;cursor:pointer} +.comment-code-cloud .ui.form textarea{border:0} +.comment-code-cloud .ui.attached.tabular.menu{background:#f7f7f7;border:1px solid #d4d4d5;padding-top:5px;padding-left:5px;margin-top:0} +.comment-code-cloud .footer{border-top:1px solid #f1f1f1;margin-top:10px} +.comment-code-cloud .footer .markdown-info{display:inline-block;margin:5px 0;font-size:12px;color:rgba(0,0,0,.6)} +.comment-code-cloud .footer .ui.right.floated{padding-top:6px} +.comment-code-cloud .footer:after{clear:both;content:"";display:block} +.comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em} +.comment-code-cloud form.comment-form-reply{margin:0 0 0 4em} +.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} \ No newline at end of file diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index d17a06aebf..b78ffad05c 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -1 +1,240 @@ -.hljs{display:block;overflow-x:auto;padding:.5em;color:#bababa}.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-num{background-color:#2b2b2b!important}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#6896ba}.hljs-code,.hljs-selector-class{color:#a6e22e}.hljs-emphasis{font-style:italic}.hljs-attribute,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-variable{color:#cb7832}.hljs-params{color:#b9b9b9}.hljs-string{color:#6a8759}.hljs-addition,.hljs-built_in,.hljs-builtin-name,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-subst,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-type{color:#e0c46c}.hljs-comment,.hljs-deletion,.hljs-meta{color:#7f7f7f}.repository .ui.segment.sub-menu .list .item a{color:#dbdbdb}.ui.horizontal.segments>.segment{background-color:#383c4a}body{background:#383c4a;color:#9e9e9e}a{color:#87ab63}a:hover{color:#a0cc75}.ui.card>.extra a:not(.ui):hover,.ui.cards>.card>.extra a:not(.ui):hover{color:#a0cc75}.ui.breadcrumb a:hover{color:#a0cc75}.ui.breadcrumb a{color:#87ab63}.repository .metas .ui.list a .text{color:#87ab63}.repository .metas .ui.list a .text:hover{color:#a0cc75}.repository .label.list .item a{color:#87ab63}.repository .label.list .item a:hover{color:#a0cc75}.repository .milestone.list>.item>a{color:#87ab63}.repository .milestone.list>.item>a:hover{color:#a0cc75}.repository.release #release-list{border-top:1px solid #4c505c}.repository .milestone.list>.item .operate>a{color:#87ab63}.repository .milestone.list>.item .operate>a:hover{color:#a0cc75}.ui.green.progress .bar{background-color:#684}.ui.progress.success .bar{background-color:#7b9e57!important}.following.bar.light{background:#2e323e}.ui.secondary.menu .active.item{color:#dbdbdb}.ui.secondary.menu .item{color:#9e9e9e}.following.bar .top.menu a.item:hover{color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a{border:solid 1px #353945;background-color:#353945}.following.bar.light{border-bottom:1px solid #313131}.ui.attached.header{background:#404552;border:1px solid #404552;color:#dbdbdb}.ui.attached.table{border:1px solid #304251;background:#304251}.feeds .list ul li:not(:last-child){border-bottom:1px solid #333640}.feeds .list ul li.private{background:#353945;border:1px solid #333640}.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff}.ui.menu .ui.dropdown .menu>.item{background:#2c303a!important;color:#9e9e9e!important}.ui.secondary.menu .dropdown.item>.menu,.ui.text.menu .dropdown.item>.menu{border:1px solid #434444}footer{background:#2e323e;border-top:1px solid #313131}.ui.menu .dropdown.item .menu{background:#2c303a}.ui.menu .ui.dropdown .menu>.item:hover,.ui.menu .ui.dropdown .menu>.selected.item{color:#fff!important}.ui.dropdown .menu>.header{color:#dbdbdb}.ui.red.label,.ui.red.labels .label{background-color:#7d3434!important;border-color:#8a2121!important}.ui.menu{background:#404552;border:1px solid #353945}.ui.menu .active.item:hover,.ui.vertical.menu .active.item:hover{color:#dbdbdb;background:#4B5162}.ui.link.menu .item:hover,.ui.menu .dropdown.item:hover,.ui.menu .link.item:hover,.ui.menu a.item:hover{color:#dbdbdb;background:#454b5a}.ui.menu .active.item{background:#4B5162;color:#dbdbdb}.ui.input input{background:#404552;border:2px solid #353945;color:#dbdbdb}.ui.input input:focus,.ui.input.focus input{background:#404552;border:2px solid #353945;color:#dbdbdb}.ui.accordion .title:not(.ui){color:#dbdbdb}.ui.label{color:#dbdbdb;background-color:#404552}.issue.list>.item .title{color:#87ab63}.issue.list>.item .title:hover{color:#a0cc75}.issue.list>.item{border-bottom:1px dashed #475767}.ui.basic.green.label,.ui.green.label,.ui.green.labels .label{background-color:#2d693b!important;border-color:#2d693b!important}.ui.basic.green.labels a.label:hover,a.ui.basic.green.label:hover{background-color:#16ab39!important;border-color:#16ab39!important;color:#fff!important}.issue.list>.item .comment{color:#129c92}.ui.basic.button,.ui.basic.buttons .button{color:#797979!important}.ui.basic.red.active.button,.ui.basic.red.buttons .active.button{box-shadow:0 0 0 1px #c75252 inset!important;color:#c75252!important}.ui.basic.button:focus,.ui.basic.button:hover,.ui.basic.buttons .button:focus,.ui.basic.buttons .button:hover{background:0 0!important;color:#dbdbdb!important}.ui.menu .item{background:#404552;color:#9e9e9e}.ui.menu .item.disabled,.ui.menu .item.disabled:hover{color:#626773}.ui.pagination.menu .active.item{color:#dbdbdb;background-color:#87ab63}.repository .header-wrapper{background-color:#2a2e3a}.ui.tabular.menu .active.item{background:#383c4a;color:#dbdbdb;border-left:1px solid transparent;border-right:1px solid transparent;border-top:none}.ui.tabular.menu .item{color:#9e9e9e}.ui.tabular.menu .item:hover{color:#dbdbdb}.ui.breadcrumb .divider,.ui.header{color:#9e9e9e}.ui.blue.label,.ui.blue.labels .label{background-color:#26577b!important;border-color:#26577b!important}.ui.menu .item>.label{background:#565454}.ui.blue.button,.ui.blue.buttons .button{background-color:#87ab63}.ui.blue.button:hover,.ui.blue.buttons .button:hover{background-color:#a0cc75}.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{background:#404552;border:2px solid #353945}.ui.form input:not([type]):focus,.ui.form input[type=date]:focus,.ui.form input[type=datetime-local]:focus,.ui.form input[type=email]:focus,.ui.form input[type=number]:focus,.ui.form input[type=password]:focus,.ui.form input[type=search]:focus,.ui.form input[type=tel]:focus,.ui.form input[type=text]:focus,.ui.form input[type=time]:focus,.ui.form input[type=url]:focus{background:#404552;border:2px solid #4b505f;color:#dbdbdb}.ui.action.input:not([class*="left action"]) input:focus{border-right-color:#4b505f!important}.ui.green.button,.ui.green.buttons .button{background-color:#87ab63}.ui.green.button:hover,.ui.green.buttons .button:hover{background-color:#a0cc75}.ui.button{background:#383c4a;border:1px solid #4c505c;color:#dbdbdb}.ui.labeled.button:not([class*="left labeled"])>.label,.ui[class*="left labeled"].button>.button{background:#404552;border:1px solid #4c505c;color:#87ab63}.ui.button:hover{background-color:#404552;color:#dbdbdb}.ui.table thead th{background:#404552;color:#dbdbdb}.repository.file.list #repo-files-table tr:hover{background-color:#393d4a}.ui.table{color:#a5a5a5!important;border:1px solid #4c505c;background:#353945}.ui.table tbody tr{border-bottom:1px solid #333640;background:#2a2e3a}.ui .text.grey{color:#808084!important}.ui.attached.table.segment{background:#353945;color:#dbdbdb!important}.markdown:not(code) h2{border-bottom:1px solid #304251}.hljs,.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#9daccc}.markdown:not(code) .highlight pre,.markdown:not(code) pre{background-color:#2a2e3a;border:1px solid #404552}.markdown:not(code) table tr:nth-child(2n){background-color:#474d61}.ui.dropdown .menu{background:#2c303a}.ui.dropdown .menu>.message:not(.ui){color:#636363}.ui.input{color:#dbdbdb}.overflow.menu .items .item{color:#9d9d9d}.overflow.menu .items .item:hover{color:#dbdbdb}.ui.segment{background:#353945;color:#9e9e9e!important;border:1px solid #404552}.ui.active.button:active,.ui.button:active,.ui.button:focus{background-color:#2e3e4e;color:#dbdbdb}.ui.dropdown .menu .selected.item,.ui.dropdown.selected{color:#dbdbdb}.ui.dropdown .menu>.item:hover{color:#dbdbdb}.ui.dropdown .menu>.item{color:#9e9e9e}.ui.attached.segment{border:1px solid #404552}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#353945}.repository.view.issue .comment-list .comment .content .header{color:#dbdbdb;background-color:#404552;border-bottom:1px solid #353944}.ui .text.grey a{color:#b3b3b3!important}.ui.comments .comment .actions a{color:#dbdbdb}.repository.view.issue .comment-list .comment .content .header:after{border-right-color:#404552}.repository.new.issue .comment.form .content:after{border-right-color:#353945}.repository.view.issue .comment-list .comment .content .header:before{border-right-color:#404552}.repository.new.issue .comment.form .content:before{border-right-color:#353945}.repository.view.issue .comment-list:before{background-color:#313c47}.repository .comment.form .content .form:after{border-right-color:#313c47}.repository .comment.form .content .form:before{border-right-color:#313c47}.ui .text.grey a{color:#dbdbdb!important}.ui .text.grey a:hover{color:#dbdbdb!important}.ui.basic.green.active.button,.ui.basic.green.buttons .active.button{color:#13ae38!important}.ui.form textarea,.ui.form textarea:focus{background:#1a2632;border:1px solid #313c47;color:#dbdbdb}.ui.form textarea:focus{border:1px solid #456580}.ui .info.segment.top{background-color:#404552!important}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#3c2626!important;border-color:#634343!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#283e2d!important;border-color:#314a37!important}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#3a523a}.repository .diff-file-box .code-diff .lines-num{border-right:1px solid #2d2d2d}.repository .diff-file-box .file-body.file-code .lines-num{color:#9e9e9e;background:#2e323e}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{border-color:#2d2d2d!important}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #2d2d2d}.hljs-section,.hljs-selector-id,.hljs-title{color:#986c88}.hljs-doctag,.hljs-string{color:#949494}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#5f3737}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#292727!important}.ui.vertical.menu .active.item{background:#4B5162}.ui.vertical.menu .item{background:#353945}.ui.vertical.menu .header.item{background:#404552}.ui.vertical.menu{background:#353945;border:1px solid #333640}.ui.repository.list .item:not(:first-child){border-top:1px solid #4c505c}.ui .text.blue{color:#87ab63!important}.ui.selection.active.dropdown,.ui.selection.active.dropdown .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)}.ui.selection.active.dropdown:hover,.ui.selection.active.dropdown:hover .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)}.ui.selection.dropdown{background:#404552;border:1px solid #404552;color:#9e9e9e}.ui.menu .ui.dropdown .menu>.active.item{color:#dbdbdb!important}.ui.tabular.menu{border-bottom:1px solid #313c47}.ui.card,.ui.cards>.card{background:#353945;box-shadow:0 1px 3px 0 #4c505c,0 0 0 1px #4c505c}.ui.card>.content>.header,.ui.cards>.card>.content>.header{color:#dbdbdb}.ui.card>.extra a:not(.ui),.ui.cards>.card>.extra a:not(.ui){color:#87ab63}.ui .text.black{color:#9e9e9e}.ui .text.black:hover{color:#dbdbdb}.ui.secondary.segment{background:#353945}.ui.secondary.pointing.menu .active.item{border-color:#87ab63;color:#dbdbdb;background:#404552}.ui.user.list .item:not(:first-child){border-top:1px solid #4c505c}.ui.secondary.pointing.menu .active.item:hover{border-color:#af8b4c;color:#dbdbdb;background:#4b5162}.ui.secondary.pointing.menu .dropdown.item:hover,.ui.secondary.pointing.menu .link.item:hover,.ui.secondary.pointing.menu a.item:hover{color:#dbdbdb}.ui.checkbox label,.ui.checkbox+label,.ui.form .field>label{color:#9e9e9e}.ui.form .inline.field>label,.ui.form .inline.field>p,.ui.form .inline.fields .field>label,.ui.form .inline.fields .field>p,.ui.form .inline.fields>label{color:#9e9e9e}.user.settings .email.list .item:not(:first-child){border-top:1px solid #3f4451}.explore .navbar{background-color:#2a2e3a!important}.ui.menu.new-menu{background-color:#2a2e3a!important}@media only screen and (max-width:1200px){.ui.menu.new-menu:after{background-image:linear-gradient(to right,rgba(42,46,42,0),#2a2e2a 100%)}}input{background:#2e323e}.ui.secondary.pointing.menu .active.item{border:none;background:#383c4a}.settings .key.list .item:not(:first-child){border-top:1px solid #404552}.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{color:#9e9e9e}.ui.attached.info.message,.ui.info.message{box-shadow:0 0 0 1px #4b5e71 inset,0 0 0 0 transparent}.ui.bottom.attached.message{background-color:#2c662d;color:#87ab63}.ui.bottom.attached.message .pull-right{color:#87ab63}.ui.info.message{background-color:#2c3b4a;color:#9ebcc5}.CodeMirror div.CodeMirror-cursor{border-left:1px solid #9e9e9e}.ui .warning.header{background-color:#5d3a22!important;border-color:#794f31}.ui.red.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent}.ui.red.button,.ui.red.buttons .button{background-color:#7d3434}.ui.red.button:hover,.ui.red.buttons .button:hover{background-color:#984646}.ui.checkbox label:hover,.ui.checkbox+label:hover{color:#dbdbdb!important}.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{color:#7f98ad}.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{background:#304251}.ui.checkbox .box:hover::before,.ui.checkbox label:hover::before{background:#304251}.ui.checkbox .box:before,.ui.checkbox label:before{background:#304251;border:1px solid #304251}.ui.checkbox .box:active::before,.ui.checkbox label:active::before{background:#304251;border-color:rgba(34,36,38,.35)}.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{border-color:#304251;background:#304251}.ui.checkbox input:focus~.box:before,.ui.checkbox input:focus~label:before{border-color:#304251;background:#304251}.ui.checkbox input:checked:focus~.box:before,.ui.checkbox input:checked:focus~label:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:before{border-color:#304251;background:#304251}.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{opacity:1;color:#7f98ad}.ui.checkbox input:checked:focus~.box:after,.ui.checkbox input:checked:focus~label:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:after{color:#7f98ad}.ui.checkbox input:focus~.box:after,.ui.checkbox input:focus~label,.ui.checkbox input:focus~label:after{color:#9a9a9a}.ui.selection.dropdown:hover{border:1px solid #456580}.ui.selection.dropdown .menu>.item{border-top:1px solid #313c47}.ui.selection.visible.dropdown>.text:not(.default){color:#9e9e9e}.ui.negative.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent}.hljs-attribute,.hljs-name,.hljs-tag{color:#ef5e77}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #4c505c}.ui.form textarea,.ui.form textarea:focus{background:#404552;border:2px solid #353945}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:#bd84bf}.hljs-doctag,.hljs-string{color:#8ab398}.ui.form .dropzone{border:2px dashed #4c505c}.ui.basic.red.button,.ui.basic.red.buttons .button{box-shadow:0 0 0 1px #a04141 inset!important;color:#a04141!important}.ui.list .list>.item .header,.ui.list>.item .header{color:#dedede}.ui.list .list>.item .description,.ui.list>.item .description{color:#9e9e9e}.ui.user.list .item .description a{color:#668cb1}.repository.file.list #file-content .code-view .lines-num{background:#2e323e}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e}.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#87ab63}.ui.basic.blue.button:hover,.ui.basic.blue.buttons .button:hover{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.ui.basic.blue.button:focus,.ui.basic.blue.buttons .button:focus{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb}.repository .label.list .item{border-bottom:1px dashed #4c505c}.repository.file.list #file-content .code-view .lines-num{background:#2e323e}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e}.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #a27558 inset!important;color:#a27558!important}.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#2a2e3a}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#283e2d!important;border-color:#314a37!important}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#3c2626!important;border-color:#634343!important}.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#a27558}.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}#git-graph-container li a{color:#c79575}#git-graph-container li .author{color:#c79575}.ui.header .sub.header{color:#9e9e9e}.ui.dividing.header{border-bottom:1px solid #4c505c}.ui.modal>.header{background:#404552;color:#dbdbdb}.ui.modal>.actions{background:#404552;border-top:1px solid #404552}.ui.modal>.content{background:#383c4a}.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}.editor-toolbar{background-color:#404552}.editor-toolbar a{color:#87ab63!important}.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:none}.CodeMirror-gutters{background-color:#2b2b2b}.repository .diff-detail-box{background-color:#383c4a}.repository .diff-detail-box .detail-files{background-color:inherit}.comment-code-cloud .ui.attached.tabular.menu{background:none transparent;border:none}.comment-code-cloud .footer .markdown-info{color:inherit}.file-comment{color:#888}.ui.comments .comment .author{color:#dbdbdb}.ui.comments .comment .metadata{color:#808084}.ui.comments .comment .text{color:#9e9e9e}.heatmap-color-0{background-color:#2d303b} \ No newline at end of file +.hljs{display:block;overflow-x:auto;padding:.5em;color:#bababa} +.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-num{background-color:#2b2b2b!important} +.hljs-emphasis,.hljs-strong{color:#a8a8a2} +.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#6896ba} +.hljs-code,.hljs-selector-class{color:#a6e22e} +.hljs-emphasis{font-style:italic} +.hljs-attribute,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-variable{color:#cb7832} +.hljs-params{color:#b9b9b9} +.hljs-string{color:#6a8759} +.hljs-addition,.hljs-built_in,.hljs-builtin-name,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-subst,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-type{color:#e0c46c} +.hljs-comment,.hljs-deletion,.hljs-meta{color:#7f7f7f} +.repository .ui.segment.sub-menu .list .item a{color:#dbdbdb} +.ui.horizontal.segments>.segment{background-color:#383c4a} +body{background:#383c4a;color:#9e9e9e} +a{color:#87ab63} +a:hover{color:#a0cc75} +.ui.card>.extra a:not(.ui):hover,.ui.cards>.card>.extra a:not(.ui):hover{color:#a0cc75} +.ui.breadcrumb a:hover{color:#a0cc75} +.ui.breadcrumb a{color:#87ab63} +.repository .metas .ui.list a .text{color:#87ab63} +.repository .metas .ui.list a .text:hover{color:#a0cc75} +.repository .label.list .item a{color:#87ab63} +.repository .label.list .item a:hover{color:#a0cc75} +.repository .milestone.list>.item>a{color:#87ab63} +.repository .milestone.list>.item>a:hover{color:#a0cc75} +.repository.release #release-list{border-top:1px solid #4c505c} +.repository .milestone.list>.item .operate>a{color:#87ab63} +.repository .milestone.list>.item .operate>a:hover{color:#a0cc75} +.ui.green.progress .bar{background-color:#684} +.ui.progress.success .bar{background-color:#7b9e57!important} +.following.bar.light{background:#2e323e} +.ui.secondary.menu .active.item{color:#dbdbdb} +.ui.secondary.menu .item{color:#9e9e9e} +.following.bar .top.menu a.item:hover{color:#fff} +.repository.view.issue .comment-list .comment .content>.bottom.segment a{border:solid 1px #353945;background-color:#353945} +.following.bar.light{border-bottom:1px solid #313131} +.ui.attached.header{background:#404552;border:1px solid #404552;color:#dbdbdb} +.ui.attached.table{border:1px solid #304251;background:#304251} +.feeds .list ul li:not(:last-child){border-bottom:1px solid #333640} +.feeds .list ul li.private{background:#353945;border:1px solid #333640} +.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff} +.ui.menu .ui.dropdown .menu>.item{background:#2c303a!important;color:#9e9e9e!important} +.ui.secondary.menu .dropdown.item>.menu,.ui.text.menu .dropdown.item>.menu{border:1px solid #434444} +footer{background:#2e323e;border-top:1px solid #313131} +.ui.menu .dropdown.item .menu{background:#2c303a} +.ui.menu .ui.dropdown .menu>.item:hover,.ui.menu .ui.dropdown .menu>.selected.item{color:#fff!important} +.ui.dropdown .menu>.header{color:#dbdbdb} +.ui.red.label,.ui.red.labels .label{background-color:#7d3434!important;border-color:#8a2121!important} +.ui.menu{background:#404552;border:1px solid #353945} +.ui.menu .active.item:hover,.ui.vertical.menu .active.item:hover{color:#dbdbdb;background:#4B5162} +.ui.link.menu .item:hover,.ui.menu .dropdown.item:hover,.ui.menu .link.item:hover,.ui.menu a.item:hover{color:#dbdbdb;background:#454b5a} +.ui.menu .active.item{background:#4B5162;color:#dbdbdb} +.ui.input input{background:#404552;border:2px solid #353945;color:#dbdbdb} +.ui.input input:focus,.ui.input.focus input{background:#404552;border:2px solid #353945;color:#dbdbdb} +.ui.accordion .title:not(.ui){color:#dbdbdb} +.ui.label{color:#dbdbdb;background-color:#404552} +.issue.list>.item .title{color:#87ab63} +.issue.list>.item .title:hover{color:#a0cc75} +.issue.list>.item{border-bottom:1px dashed #475767} +.ui.basic.green.label,.ui.green.label,.ui.green.labels .label{background-color:#2d693b!important;border-color:#2d693b!important} +.ui.basic.green.labels a.label:hover,a.ui.basic.green.label:hover{background-color:#16ab39!important;border-color:#16ab39!important;color:#fff!important} +.issue.list>.item .comment{color:#129c92} +.ui.basic.button,.ui.basic.buttons .button{color:#797979!important} +.ui.basic.red.active.button,.ui.basic.red.buttons .active.button{box-shadow:0 0 0 1px #c75252 inset!important;color:#c75252!important} +.ui.basic.button:focus,.ui.basic.button:hover,.ui.basic.buttons .button:focus,.ui.basic.buttons .button:hover{background:0 0!important;color:#dbdbdb!important} +.ui.menu .item{background:#404552;color:#9e9e9e} +.ui.menu .item.disabled,.ui.menu .item.disabled:hover{color:#626773} +.ui.pagination.menu .active.item{color:#dbdbdb;background-color:#87ab63} +.repository .header-wrapper{background-color:#2a2e3a} +.ui.tabular.menu .active.item{background:#383c4a;color:#dbdbdb;border-left:1px solid transparent;border-right:1px solid transparent;border-top:none} +.ui.tabular.menu .item{color:#9e9e9e} +.ui.tabular.menu .item:hover{color:#dbdbdb} +.ui.breadcrumb .divider,.ui.header{color:#9e9e9e} +.ui.blue.label,.ui.blue.labels .label{background-color:#26577b!important;border-color:#26577b!important} +.ui.menu .item>.label{background:#565454} +.ui.blue.button,.ui.blue.buttons .button{background-color:#87ab63} +.ui.blue.button:hover,.ui.blue.buttons .button:hover{background-color:#a0cc75} +.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{background:#404552;border:2px solid #353945} +.ui.form input:not([type]):focus,.ui.form input[type=date]:focus,.ui.form input[type=datetime-local]:focus,.ui.form input[type=email]:focus,.ui.form input[type=number]:focus,.ui.form input[type=password]:focus,.ui.form input[type=search]:focus,.ui.form input[type=tel]:focus,.ui.form input[type=text]:focus,.ui.form input[type=time]:focus,.ui.form input[type=url]:focus{background:#404552;border:2px solid #4b505f;color:#dbdbdb} +.ui.action.input:not([class*="left action"]) input:focus{border-right-color:#4b505f!important} +.ui.green.button,.ui.green.buttons .button{background-color:#87ab63} +.ui.green.button:hover,.ui.green.buttons .button:hover{background-color:#a0cc75} +.ui.button{background:#383c4a;border:1px solid #4c505c;color:#dbdbdb} +.ui.labeled.button:not([class*="left labeled"])>.label,.ui[class*="left labeled"].button>.button{background:#404552;border:1px solid #4c505c;color:#87ab63} +.ui.button:hover{background-color:#404552;color:#dbdbdb} +.ui.table thead th{background:#404552;color:#dbdbdb} +.repository.file.list #repo-files-table tr:hover{background-color:#393d4a} +.ui.table{color:#a5a5a5!important;border:1px solid #4c505c;background:#353945} +.ui.table tbody tr{border-bottom:1px solid #333640;background:#2a2e3a} +.ui .text.grey{color:#808084!important} +.ui.attached.table.segment{background:#353945;color:#dbdbdb!important} +.markdown:not(code) h2{border-bottom:1px solid #304251} +.hljs,.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#9daccc} +.markdown:not(code) .highlight pre,.markdown:not(code) pre{background-color:#2a2e3a;border:1px solid #404552} +.markdown:not(code) table tr:nth-child(2n){background-color:#474d61} +.ui.dropdown .menu{background:#2c303a} +.ui.dropdown .menu>.message:not(.ui){color:#636363} +.ui.input{color:#dbdbdb} +.overflow.menu .items .item{color:#9d9d9d} +.overflow.menu .items .item:hover{color:#dbdbdb} +.ui.segment{background:#353945;color:#9e9e9e!important;border:1px solid #404552} +.ui.active.button:active,.ui.button:active,.ui.button:focus{background-color:#2e3e4e;color:#dbdbdb} +.ui.dropdown .menu .selected.item,.ui.dropdown.selected{color:#dbdbdb} +.ui.dropdown .menu>.item:hover{color:#dbdbdb} +.ui.dropdown .menu>.item{color:#9e9e9e} +.ui.attached.segment{border:1px solid #404552} +.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#353945} +.repository.view.issue .comment-list .comment .content .header{color:#dbdbdb;background-color:#404552;border-bottom:1px solid #353944} +.ui .text.grey a{color:#b3b3b3!important} +.ui.comments .comment .actions a{color:#dbdbdb} +.repository.view.issue .comment-list .comment .content .header:after{border-right-color:#404552} +.repository.new.issue .comment.form .content:after{border-right-color:#353945} +.repository.view.issue .comment-list .comment .content .header:before{border-right-color:#404552} +.repository.new.issue .comment.form .content:before{border-right-color:#353945} +.repository.view.issue .comment-list:before{background-color:#313c47} +.repository .comment.form .content .form:after{border-right-color:#313c47} +.repository .comment.form .content .form:before{border-right-color:#313c47} +.ui .text.grey a{color:#dbdbdb!important} +.ui .text.grey a:hover{color:#dbdbdb!important} +.ui.basic.green.active.button,.ui.basic.green.buttons .active.button{color:#13ae38!important} +.ui.form textarea,.ui.form textarea:focus{background:#1a2632;border:1px solid #313c47;color:#dbdbdb} +.ui.form textarea:focus{border:1px solid #456580} +.ui .info.segment.top{background-color:#404552!important} +.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#3c2626!important;border-color:#634343!important} +.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#283e2d!important;border-color:#314a37!important} +.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#3a523a} +.repository .diff-file-box .code-diff .lines-num{border-right:1px solid #2d2d2d} +.repository .diff-file-box .file-body.file-code .lines-num{color:#9e9e9e;background:#2e323e} +.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{border-color:#2d2d2d!important} +.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #2d2d2d} +.hljs-section,.hljs-selector-id,.hljs-title{color:#986c88} +.hljs-doctag,.hljs-string{color:#949494} +.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#5f3737} +.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#292727!important} +.ui.vertical.menu .active.item{background:#4B5162} +.ui.vertical.menu .item{background:#353945} +.ui.vertical.menu .header.item{background:#404552} +.ui.vertical.menu{background:#353945;border:1px solid #333640} +.ui.repository.list .item:not(:first-child){border-top:1px solid #4c505c} +.ui .text.blue{color:#87ab63!important} +.ui.selection.active.dropdown,.ui.selection.active.dropdown .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)} +.ui.selection.active.dropdown:hover,.ui.selection.active.dropdown:hover .menu{border-color:#4e5361;box-shadow:0 2px 3px 0 rgba(34,36,38,.15)} +.ui.selection.dropdown{background:#404552;border:1px solid #404552;color:#9e9e9e} +.ui.menu .ui.dropdown .menu>.active.item{color:#dbdbdb!important} +.ui.tabular.menu{border-bottom:1px solid #313c47} +.ui.card,.ui.cards>.card{background:#353945;box-shadow:0 1px 3px 0 #4c505c,0 0 0 1px #4c505c} +.ui.card>.content>.header,.ui.cards>.card>.content>.header{color:#dbdbdb} +.ui.card>.extra a:not(.ui),.ui.cards>.card>.extra a:not(.ui){color:#87ab63} +.ui .text.black{color:#9e9e9e} +.ui .text.black:hover{color:#dbdbdb} +.ui.secondary.segment{background:#353945} +.ui.secondary.pointing.menu .active.item{border-color:#87ab63;color:#dbdbdb;background:#404552} +.ui.user.list .item:not(:first-child){border-top:1px solid #4c505c} +.ui.secondary.pointing.menu .active.item:hover{border-color:#af8b4c;color:#dbdbdb;background:#4b5162} +.ui.secondary.pointing.menu .dropdown.item:hover,.ui.secondary.pointing.menu .link.item:hover,.ui.secondary.pointing.menu a.item:hover{color:#dbdbdb} +.ui.checkbox label,.ui.checkbox+label,.ui.form .field>label{color:#9e9e9e} +.ui.form .inline.field>label,.ui.form .inline.field>p,.ui.form .inline.fields .field>label,.ui.form .inline.fields .field>p,.ui.form .inline.fields>label{color:#9e9e9e} +.user.settings .email.list .item:not(:first-child){border-top:1px solid #3f4451} +.explore .navbar{background-color:#2a2e3a!important} +.ui.menu.new-menu{background-color:#2a2e3a!important} +@media only screen and (max-width:1200px){.ui.menu.new-menu:after{background-image:linear-gradient(to right,rgba(42,46,42,0),#2a2e2a 100%)} +} +input{background:#2e323e} +.ui.secondary.pointing.menu .active.item{border:none;background:#383c4a} +.settings .key.list .item:not(:first-child){border-top:1px solid #404552} +.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{color:#9e9e9e} +.ui.attached.info.message,.ui.info.message{box-shadow:0 0 0 1px #4b5e71 inset,0 0 0 0 transparent} +.ui.bottom.attached.message{background-color:#2c662d;color:#87ab63} +.ui.bottom.attached.message .pull-right{color:#87ab63} +.ui.info.message{background-color:#2c3b4a;color:#9ebcc5} +.CodeMirror div.CodeMirror-cursor{border-left:1px solid #9e9e9e} +.ui .warning.header{background-color:#5d3a22!important;border-color:#794f31} +.ui.red.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent} +.ui.red.button,.ui.red.buttons .button{background-color:#7d3434} +.ui.red.button:hover,.ui.red.buttons .button:hover{background-color:#984646} +.ui.checkbox label:hover,.ui.checkbox+label:hover{color:#dbdbdb!important} +.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{color:#7f98ad} +.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{background:#304251} +.ui.checkbox .box:hover::before,.ui.checkbox label:hover::before{background:#304251} +.ui.checkbox .box:before,.ui.checkbox label:before{background:#304251;border:1px solid #304251} +.ui.checkbox .box:active::before,.ui.checkbox label:active::before{background:#304251;border-color:rgba(34,36,38,.35)} +.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{border-color:#304251;background:#304251} +.ui.checkbox input:focus~.box:before,.ui.checkbox input:focus~label:before{border-color:#304251;background:#304251} +.ui.checkbox input:checked:focus~.box:before,.ui.checkbox input:checked:focus~label:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:before{border-color:#304251;background:#304251} +.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{opacity:1;color:#7f98ad} +.ui.checkbox input:checked:focus~.box:after,.ui.checkbox input:checked:focus~label:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:after{color:#7f98ad} +.ui.checkbox input:focus~.box:after,.ui.checkbox input:focus~label,.ui.checkbox input:focus~label:after{color:#9a9a9a} +.ui.selection.dropdown:hover{border:1px solid #456580} +.ui.selection.dropdown .menu>.item{border-top:1px solid #313c47} +.ui.selection.visible.dropdown>.text:not(.default){color:#9e9e9e} +.ui.negative.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent} +.hljs-attribute,.hljs-name,.hljs-tag{color:#ef5e77} +.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #4c505c} +.ui.form textarea,.ui.form textarea:focus{background:#404552;border:2px solid #353945} +.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:#bd84bf} +.hljs-doctag,.hljs-string{color:#8ab398} +.ui.form .dropzone{border:2px dashed #4c505c} +.ui.basic.red.button,.ui.basic.red.buttons .button{box-shadow:0 0 0 1px #a04141 inset!important;color:#a04141!important} +.ui.list .list>.item .header,.ui.list>.item .header{color:#dedede} +.ui.list .list>.item .description,.ui.list>.item .description{color:#9e9e9e} +.ui.user.list .item .description a{color:#668cb1} +.repository.file.list #file-content .code-view .lines-num{background:#2e323e} +.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e} +.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#87ab63} +.ui.basic.blue.button:hover,.ui.basic.blue.buttons .button:hover{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} +.ui.basic.blue.button:focus,.ui.basic.blue.buttons .button:focus{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} +.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} +a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb} +.repository .label.list .item{border-bottom:1px dashed #4c505c} +.repository.file.list #file-content .code-view .lines-num{background:#2e323e} +.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e} +.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #a27558 inset!important;color:#a27558!important} +.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} +a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb} +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#2a2e3a} +.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#283e2d!important;border-color:#314a37!important} +.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#3c2626!important;border-color:#634343!important} +.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#a27558} +.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558} +#git-graph-container li a{color:#c79575} +#git-graph-container li .author{color:#c79575} +.ui.header .sub.header{color:#9e9e9e} +.ui.dividing.header{border-bottom:1px solid #4c505c} +.ui.modal>.header{background:#404552;color:#dbdbdb} +.ui.modal>.actions{background:#404552;border-top:1px solid #404552} +.ui.modal>.content{background:#383c4a} +.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} +.editor-toolbar{background-color:#404552} +.editor-toolbar a{color:#87ab63!important} +.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:none} +.CodeMirror-gutters{background-color:#2b2b2b} +.repository .diff-detail-box{background-color:#383c4a} +.repository .diff-detail-box .detail-files{background-color:inherit} +.comment-code-cloud .ui.attached.tabular.menu{background:none transparent;border:none} +.comment-code-cloud .footer .markdown-info{color:inherit} +.file-comment{color:#888} +.ui.comments .comment .author{color:#dbdbdb} +.ui.comments .comment .metadata{color:#808084} +.ui.comments .comment .text{color:#9e9e9e} +.heatmap-color-0{background-color:#2d303b} \ No newline at end of file From 597ac064c3cb5931bc98b3dea6d742e08cb9fc11 Mon Sep 17 00:00:00 2001 From: Xaver Maierhofer Date: Mon, 13 May 2019 22:52:59 +0200 Subject: [PATCH 007/220] Style orgs list in user profile (#6911) --- public/css/index.css | 2 ++ public/less/_user.less | 15 +++++++++++++++ templates/user/profile.tmpl | 6 +++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/public/css/index.css b/public/css/index.css index a50fe43c8f..8e3e4293e5 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -890,6 +890,8 @@ tbody.commit-list{vertical-align:baseline} .user.notification .octicon.blue{color:#2185d0} .user.link-account:not(.icon){padding-top:15px;padding-bottom:5px} .user.settings .iconFloat{float:left} +.user-orgs{display:flex;flex-flow:row wrap;padding:0;margin:-3px!important} +.user-orgs li{display:flex;border-bottom:0!important;padding:3px!important;width:20%;max-width:60px} .dashboard{padding-top:15px} .dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px} .dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none} diff --git a/public/less/_user.less b/public/less/_user.less index 4b9be47269..635db83b49 100644 --- a/public/less/_user.less +++ b/public/less/_user.less @@ -133,3 +133,18 @@ } } } + +.user-orgs { + display: flex; + flex-flow: row wrap; + padding: 0; + margin: -3px !important; + + li { + display: flex; + border-bottom: 0 !important; + padding: 3px !important; + width: 20%; + max-width: 60px; + } +} diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 6170c6d130..833de90b8c 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -69,11 +69,15 @@ */}} {{if and .Orgs .HasOrgsVisible}}
  • +
      {{range .Orgs}} {{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} - +
    • + +
    • {{end}} {{end}} +
  • {{end}} {{if and .IsSigned (ne .SignedUserName .Owner.Name)}} From 36b68fdb0187a1db8711f093cdfa6b6b620082b4 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Tue, 14 May 2019 00:19:38 +0200 Subject: [PATCH 008/220] [docker] support for custom GITEA_CUSTOM env var (#6608) --- docker/root/etc/profile.d/gitea.sh | 2 -- docker/root/etc/s6/gitea/setup | 14 ++++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) delete mode 100755 docker/root/etc/profile.d/gitea.sh diff --git a/docker/root/etc/profile.d/gitea.sh b/docker/root/etc/profile.d/gitea.sh deleted file mode 100755 index 41afd4cfb8..0000000000 --- a/docker/root/etc/profile.d/gitea.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -export GITEA_CUSTOM=/data/gitea diff --git a/docker/root/etc/s6/gitea/setup b/docker/root/etc/s6/gitea/setup index 2b0fb6c37b..dec0ee2b55 100755 --- a/docker/root/etc/s6/gitea/setup +++ b/docker/root/etc/s6/gitea/setup @@ -6,12 +6,16 @@ if [ ! -d /data/git/.ssh ]; then fi if [ ! -f /data/git/.ssh/environment ]; then - echo "GITEA_CUSTOM=/data/gitea" >| /data/git/.ssh/environment + echo "GITEA_CUSTOM=$GITEA_CUSTOM" >| /data/git/.ssh/environment chmod 600 /data/git/.ssh/environment + +elif ! grep -q "^GITEA_CUSTOM=$GITEA_CUSTOM$" /data/git/.ssh/environment; then + sed -i /^GITEA_CUSTOM=/d /data/git/.ssh/environment + echo "GITEA_CUSTOM=$GITEA_CUSTOM" >> /data/git/.ssh/environment fi -if [ ! -f /data/gitea/conf/app.ini ]; then - mkdir -p /data/gitea/conf +if [ ! -f ${GITEA_CUSTOM}/conf/app.ini ]; then + mkdir -p ${GITEA_CUSTOM}/conf # Set INSTALL_LOCK to true only if SECRET_KEY is not empty and # INSTALL_LOCK is empty @@ -36,7 +40,9 @@ if [ ! -f /data/gitea/conf/app.ini ]; then DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-"false"} \ REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN_VIEW:-"false"} \ SECRET_KEY=${SECRET_KEY:-""} \ - envsubst < /etc/templates/app.ini > /data/gitea/conf/app.ini + envsubst < /etc/templates/app.ini > ${GITEA_CUSTOM}/conf/app.ini + + chown ${USER}:git ${GITEA_CUSTOM}/conf/app.ini fi # only chown if current owner is not already the gitea ${USER}. No recursive check to save time From e63274ee09596de5446f92150b2afbad9664c5de Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 May 2019 06:53:54 +0800 Subject: [PATCH 009/220] remove macaron dependent on models/mail.go (#6931) --- models/mail.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/models/mail.go b/models/mail.go index c8f67bd345..b3e1e0d833 100644 --- a/models/mail.go +++ b/models/mail.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "gopkg.in/gomail.v2" - "gopkg.in/macaron.v1" ) const ( @@ -45,11 +44,11 @@ func SendTestMail(email string) error { } // SendUserMail sends a mail to the user -func SendUserMail(c *macaron.Context, u *User, tpl base.TplName, code, subject, info string) { +func SendUserMail(language string, u *User, tpl base.TplName, code, subject, info string) { data := map[string]interface{}{ "DisplayName": u.DisplayName(), - "ActiveCodeLives": base.MinutesToFriendly(setting.Service.ActiveCodeLives, c.Locale.Language()), - "ResetPwdCodeLives": base.MinutesToFriendly(setting.Service.ResetPwdCodeLives, c.Locale.Language()), + "ActiveCodeLives": base.MinutesToFriendly(setting.Service.ActiveCodeLives, language), + "ResetPwdCodeLives": base.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language), "Code": code, } @@ -66,21 +65,27 @@ func SendUserMail(c *macaron.Context, u *User, tpl base.TplName, code, subject, mailer.SendAsync(msg) } +// Locale represents an interface to translation +type Locale interface { + Language() string + Tr(string, ...interface{}) string +} + // SendActivateAccountMail sends an activation mail to the user (new user registration) -func SendActivateAccountMail(c *macaron.Context, u *User) { - SendUserMail(c, u, mailAuthActivate, u.GenerateActivateCode(), c.Tr("mail.activate_account"), "activate account") +func SendActivateAccountMail(locale Locale, u *User) { + SendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateActivateCode(), locale.Tr("mail.activate_account"), "activate account") } // SendResetPasswordMail sends a password reset mail to the user -func SendResetPasswordMail(c *macaron.Context, u *User) { - SendUserMail(c, u, mailAuthResetPassword, u.GenerateActivateCode(), c.Tr("mail.reset_password"), "recover account") +func SendResetPasswordMail(locale Locale, u *User) { + SendUserMail(locale.Language(), u, mailAuthResetPassword, u.GenerateActivateCode(), locale.Tr("mail.reset_password"), "recover account") } // SendActivateEmailMail sends confirmation email to confirm new email address -func SendActivateEmailMail(c *macaron.Context, u *User, email *EmailAddress) { +func SendActivateEmailMail(locale Locale, u *User, email *EmailAddress) { data := map[string]interface{}{ "DisplayName": u.DisplayName(), - "ActiveCodeLives": base.MinutesToFriendly(setting.Service.ActiveCodeLives, c.Locale.Language()), + "ActiveCodeLives": base.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()), "Code": u.GenerateEmailActivateCode(email.Email), "Email": email.Email, } @@ -92,14 +97,14 @@ func SendActivateEmailMail(c *macaron.Context, u *User, email *EmailAddress) { return } - msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), content.String()) + msg := mailer.NewMessage([]string{email.Email}, locale.Tr("mail.activate_email"), content.String()) msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID) mailer.SendAsync(msg) } // SendRegisterNotifyMail triggers a notify e-mail by admin created a account. -func SendRegisterNotifyMail(c *macaron.Context, u *User) { +func SendRegisterNotifyMail(locale Locale, u *User) { data := map[string]interface{}{ "DisplayName": u.DisplayName(), "Username": u.Name, @@ -112,7 +117,7 @@ func SendRegisterNotifyMail(c *macaron.Context, u *User) { return } - msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), content.String()) + msg := mailer.NewMessage([]string{u.Email}, locale.Tr("mail.register_notify"), content.String()) msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID) mailer.SendAsync(msg) From c0fc6cd9a8ae438f5759f2ee88d395bf7e1dbe1d Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 14 May 2019 01:08:34 +0100 Subject: [PATCH 010/220] rotate unusual logs and stop stacktracing (#6935) --- modules/log/log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/log/log.go b/modules/log/log.go index c0fd117967..d18996d48d 100644 --- a/modules/log/log.go +++ b/modules/log/log.go @@ -82,7 +82,7 @@ func NewGitLogger(logPath string) { } GitLogger = newLogger("git", 0) - GitLogger.SetLogger("file", "file", fmt.Sprintf(`{"level":"TRACE","filename":"%s","rotate":false}`, logPath)) + GitLogger.SetLogger("file", "file", fmt.Sprintf(`{"level":"TRACE","filename":"%s","rotate":true,"maxsize":%d,"daily":true,"maxdays":7,"compress":true,"compressionLevel":-1, "stacktraceLevel":"NONE"}`, logPath, 1<<28)) } // GetLevel returns the minimum logger level From 3957b40021a7e017fc118a72fb5de38034427f00 Mon Sep 17 00:00:00 2001 From: Xaver Maierhofer Date: Tue, 14 May 2019 02:54:23 +0200 Subject: [PATCH 011/220] Add less linter via npx (#6936) --- .lesshintrc.json | 12 + Makefile | 1 + package-lock.json | 1657 +++++++++++++++++++++++++++-- package.json | 3 +- public/css/index.css | 108 +- public/css/theme-arc-green.css | 22 +- public/less/_admin.less | 5 +- public/less/_base.less | 110 +- public/less/_dashboard.less | 6 +- public/less/_editor.less | 8 +- public/less/_explore.less | 10 +- public/less/_form.less | 22 +- public/less/_home.less | 6 +- public/less/_markdown.less | 41 +- public/less/_organization.less | 6 +- public/less/_repository.less | 184 ++-- public/less/_review.less | 8 +- public/less/_tribute.less | 5 +- public/less/themes/_base.less | 2 +- public/less/themes/arc-green.less | 386 +++++-- 20 files changed, 2165 insertions(+), 437 deletions(-) create mode 100644 .lesshintrc.json diff --git a/.lesshintrc.json b/.lesshintrc.json new file mode 100644 index 0000000000..55ea979673 --- /dev/null +++ b/.lesshintrc.json @@ -0,0 +1,12 @@ +{ + "idSelector": false, + "importPath": false, + "importantRule": false, + "maxCharPerLine": false, + "propertyOrdering": false, + "qualifyingElement": false, + "spaceAroundComma": false, + "stringQuotes": "double", + "universalSelector": false, + "zeroUnit": "no_unit" +} diff --git a/Makefile b/Makefile index 424ea9dedb..2b77ce5dca 100644 --- a/Makefile +++ b/Makefile @@ -388,6 +388,7 @@ generate-stylesheets: exit 1; \ fi; $(eval BROWSERS := "> 1%, last 2 firefox versions, last 2 safari versions, ie 11") + npx lesshint public/less/ npx lessc --clean-css="--s0 -b" public/less/index.less public/css/index.css $(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css="--s0 -b" public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;) $(foreach file, $(wildcard public/css/*),npx postcss --use autoprefixer --autoprefixer.browsers $(BROWSERS) -o $(file) $(file);) diff --git a/package-lock.json b/package-lock.json index 561c4c5bee..57a39821e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,6 +2,22 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, "ajv": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", @@ -73,6 +89,60 @@ } } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -83,6 +153,12 @@ "safer-buffer": "~2.1.0" } }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -90,75 +166,24 @@ "dev": true, "optional": true }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, "autoprefixer": { - "version": "9.4.7", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.7.tgz", - "integrity": "sha512-qS5wW6aXHkm53Y4z73tFGsUhmZu4aMPV9iHXYlF0c/wxjknXNHuj/1cIQb+6YH692DbJGGWcckAXX+VxKvahMA==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.5.1.tgz", + "integrity": "sha512-KJSzkStUl3wP0D5sdMlP82Q52JLy5+atf2MHAre48+ckWkXgixmfHyWmA77wFDy6jTHU6mIgXv6hAQ2mf1PjJQ==", "dev": true, "requires": { - "browserslist": "^4.4.1", - "caniuse-lite": "^1.0.30000932", + "browserslist": "^4.5.4", + "caniuse-lite": "^1.0.30000957", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", "postcss": "^7.0.14", "postcss-value-parser": "^3.3.1" - }, - "dependencies": { - "browserslist": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.1.tgz", - "integrity": "sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000929", - "electron-to-chromium": "^1.3.103", - "node-releases": "^1.1.3" - } - }, - "caniuse-lite": { - "version": "1.0.30000935", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000935.tgz", - "integrity": "sha512-1Y2uJ5y56qDt3jsDTdBHL1OqiImzjoQcBG6Yl3Qizq8mcc2SgCFpi+ZwLLqkztYnk9l87IYqRlNBnPSOTbFkXQ==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.113", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz", - "integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==", - "dev": true - }, - "node-releases": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.7.tgz", - "integrity": "sha512-bKdrwaqJUPHqlCzDD7so/R+Nk0jGv9a11ZhLrD9f6i947qGLrGAhU3OxRENa19QQmwzGy/g6zCDEuLGDO8HPvA==", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "postcss": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", - "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "aws-sign2": { @@ -168,12 +193,176 @@ "dev": true, "optional": true }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browserslist": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.6.tgz", + "integrity": "sha512-o/hPOtbU9oX507lIqon+UvPYqpx3mHc8cV3QemSBTXwkG8gSQSK6UKvXcE/DcleU3+A59XTUHyCvZ5qGy8xVAg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000963", + "electron-to-chromium": "^1.3.127", + "node-releases": "^1.1.17" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, "camelcase": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", "dev": true }, + "caniuse-lite": { + "version": "1.0.30000967", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000967.tgz", + "integrity": "sha512-rUBIbap+VJfxTzrM4akJ00lkvVb5/n5v3EGXfWzSH5zT8aJmGzjA8HWhJ4U6kCpzxozUSnB+yvAYDRPY6mRpgQ==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -196,6 +385,39 @@ } } }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -215,18 +437,268 @@ } } }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz", + "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.0", + "parse-json": "^4.0.0" + } + }, + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.133", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.133.tgz", + "integrity": "sha512-lyoC8aoqbbDqsprb6aPdt9n3DpOZZzdz/T4IZKsR0/dkZIxnJVUjjcpOSwA66jPRIOyDAamCTAUqweU05kKNSg==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -234,6 +706,55 @@ "dev": true, "optional": true }, + "fast-glob": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", + "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -272,6 +793,83 @@ } } }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -303,6 +901,44 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, "image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -310,6 +946,205 @@ "dev": true, "optional": true }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, "less": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", @@ -692,18 +1527,160 @@ } } }, + "lesshint": { + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/lesshint/-/lesshint-6.3.6.tgz", + "integrity": "sha512-yFUAwNAMkUzKRO0qa6d0N1xXW66RFuipFB3VVICwQB6aIyh9y11wUpcMp6e3adL46+0aGJIkDW6z12c+bWaLgA==", + "dev": true, + "requires": { + "commander": "^2.8.0", + "cosmiconfig": "^5.0.1", + "globby": "^8.0.0", + "lodash.merge": "^4.0.1", + "lodash.orderby": "^4.6.0", + "postcss": "^7.0.14", + "postcss-less": "^3.1.1", + "postcss-selector-parser": "^5.0.0", + "postcss-values-parser": "^2.0.0", + "strip-json-comments": "^2.0.0" + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "dev": true + }, + "lodash.orderby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.orderby/-/lodash.orderby-4.6.0.tgz", + "integrity": "sha1-5pfwTOXXhSL1TZM4syuBozk+TrM=", + "dev": true + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "merge2": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "node-releases": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.19.tgz", + "integrity": "sha512-SH/B4WwovHbulIALsQllAVwqZZD1kPmKCqrhGfR29dXjLAVZMHvBjD3S6nL9D/J9QkmZ1R92/0wCMDKXUUvyyA==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, "normalize-range": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -711,6 +1688,132 @@ "dev": true, "optional": true }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.16.tgz", + "integrity": "sha512-MOo8zNSlIqh22Uaa3drkdIAgUGEL+AD1ESiSdmElLUmE2uVDo1QloiT/IfW9qRw8Gw+Y/w69UVMGwbufMSftxA==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "postcss-cli-simple": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-cli-simple/-/postcss-cli-simple-3.0.0.tgz", @@ -760,12 +1863,43 @@ } } }, + "postcss-less": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz", + "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, "postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, + "postcss-values-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", + "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", + "dev": true, + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -773,6 +1907,46 @@ "dev": true, "optional": true }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -780,6 +1954,15 @@ "dev": true, "optional": true }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -788,9 +1971,212 @@ "optional": true }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "supports-color": { @@ -802,6 +2188,48 @@ "has-flag": "^3.0.0" } }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -838,6 +2266,105 @@ "requires": { "safe-buffer": "^5.0.1" } + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } diff --git a/package.json b/package.json index 5605da52d3..094941980f 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "license": "MIT", "devDependencies": { - "autoprefixer": "9.4.7", + "autoprefixer": "9.5.1", "less": "3.9.0", "less-plugin-clean-css": "1.5.1", + "lesshint": "^6.3.6", "postcss-cli-simple": "3.0.0" } } diff --git a/public/css/index.css b/public/css/index.css index 8e3e4293e5..d53d4fb157 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -3,7 +3,7 @@ .tribute-container li{padding:8px 12px;border-bottom:1px solid #dcdcdc} .tribute-container li img{display:inline-block;vertical-align:middle;width:28px;height:28px;margin-right:5px} .tribute-container li span.fullname{font-weight:400;font-size:.8rem;margin-left:3px} -.tribute-container li.highlight,.tribute-container li:hover{background:#2185D0;color:#fff} +.tribute-container li.highlight,.tribute-container li:hover{background:#2185d0;color:#fff} .emoji{width:1.5em;height:1.5em;display:inline-block;background-size:contain} .ui.label .emoji{height:1.2em!important} @font-face{font-family:Lato;src:url(../vendor/assets/lato-fonts/lato-regular.eot);src:url(../vendor/assets/lato-fonts/lato-regular.eot?#iefix) format('embedded-opentype'),url(../vendor/assets/lato-fonts/lato-regular.woff2) format('woff2'),url(../vendor/assets/lato-fonts/lato-regular.woff) format('woff'),url(../vendor/assets/lato-fonts/lato-regular.ttf) format('truetype');font-weight:400;font-style:normal} @@ -53,7 +53,7 @@ code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break .dont-break-out{overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto} .full.height{flex-grow:1;padding-bottom:80px} .following.bar{z-index:900;left:0;margin:0!important} -.following.bar.light{background-color:#fff;border-bottom:1px solid #DDD;box-shadow:0 2px 3px rgba(0,0,0,.04)} +.following.bar.light{background-color:#fff;border-bottom:1px solid #ddd;box-shadow:0 2px 3px rgba(0,0,0,.04)} .following.bar .column .menu{margin-top:0} .following.bar .top.menu a.item.brand{padding-left:0} .following.bar .brand .ui.mini.image{width:30px} @@ -85,7 +85,7 @@ code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break .ui.dropdown .menu .menu>.item>.floating.label{z-index:21} .ui .text.red{color:#d95c5c!important} .ui .text.red a{color:#d95c5c!important} -.ui .text.red a:hover{color:#E67777!important} +.ui .text.red a:hover{color:#e67777!important} .ui .text.blue{color:#428bca!important} .ui .text.blue a{color:#15c!important} .ui .text.blue a:hover{color:#428bca!important} @@ -97,7 +97,7 @@ code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break .ui .text.light.grey{color:#888!important} .ui .text.green{color:#6cc644!important} .ui .text.purple{color:#6e5494!important} -.ui .text.yellow{color:#FBBD08!important} +.ui .text.yellow{color:#fbbd08!important} .ui .text.gold{color:#a1882b!important} .ui .text.left{text-align:left!important} .ui .text.right{text-align:right!important} @@ -113,8 +113,8 @@ code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break .ui.bottom.attached.message .pull-right{color:#000} .ui.bottom.attached.message .pull-right>span,.ui.bottom.attached.message>span{color:#21ba45} .ui .header>i+.content{padding-left:.75rem;vertical-align:middle} -.ui .warning.header{background-color:#F9EDBE!important;border-color:#F0C36D} -.ui .warning.segment{border-color:#F0C36D} +.ui .warning.header{background-color:#f9edbe!important;border-color:#efc16b} +.ui .warning.segment{border-color:#efc16b} .ui .info.segment{border:1px solid #c5d5dd} .ui .info.segment.top{background-color:#e6f1f6!important} .ui .info.segment.top h3,.ui .info.segment.top h4{margin-top:0} @@ -134,7 +134,7 @@ code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break .ui .background.light.grey{background-color:#888!important} .ui .background.green{background-color:#6cc644!important} .ui .background.purple{background-color:#6e5494!important} -.ui .background.yellow{background-color:#FBBD08!important} +.ui .background.yellow{background-color:#fbbf09!important} .ui .background.gold{background-color:#a1882b!important} .ui .branch-tag-choice{line-height:20px} @media only screen and (max-width:767px){.ui.pagination.menu .item.navigation span.navigation_label,.ui.pagination.menu .item:not(.active):not(.navigation){display:none} @@ -147,7 +147,7 @@ footer{background-color:#fff;border-top:1px solid #d6d6d6;width:100%;flex-basis: footer .container{width:100vw!important;padding:0 .5rem} footer .container .fa{width:16px;text-align:center;color:#428bca} footer .container .links>*{border-left:1px solid #d6d6d6;padding-left:8px;margin-left:5px} -footer .container .links>:first-child{border-left:none} +footer .container .links>:first-child{border-left:0} footer .ui.language .menu{max-height:500px;overflow-y:auto;margin-bottom:7px} footer .ui.left,footer .ui.right{line-height:40px} .hide{display:none} @@ -180,7 +180,7 @@ footer .ui.left,footer .ui.right{line-height:40px} @media only screen and (max-width:991px) and (min-width:768px){.ui.container{width:95%} } .hljs{background:inherit!important;padding:0!important} -.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important} +.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#fafafa!important;border-width:1px!important} @media only screen and (max-width:1200px){.ui.menu.new-menu{overflow-x:auto!important;justify-content:left!important;padding-bottom:5px} .ui.menu.new-menu::-webkit-scrollbar{height:8px;display:none} .ui.menu.new-menu:hover::-webkit-scrollbar{display:block} @@ -236,7 +236,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .markdown:not(code) h6 .anchor{line-height:1.1} .markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px} .markdown:not(code) blockquote{margin-left:0} -.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none} +.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0} .markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em} .markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none} .markdown:not(code) ol ol,.markdown:not(code) ol ul,.markdown:not(code) ul ol,.markdown:not(code) ul ul{margin-top:0;margin-bottom:0} @@ -248,7 +248,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd} .markdown:not(code) blockquote>:first-child{margin-top:0} .markdown:not(code) blockquote>:last-child{margin-bottom:0} -.markdown:not(code) table{width:auto;overflow:auto;word-break:normal;word-break:keep-all;display:block} +.markdown:not(code) table{width:auto;overflow:auto;word-break:keep-all;display:block} .markdown:not(code) table th{font-weight:700} .markdown:not(code) table td,.markdown:not(code) table th{padding:6px 13px!important;border:1px solid #ddd!important} .markdown:not(code) table tr{background-color:#fff;border-top:1px solid #ccc} @@ -405,8 +405,8 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .metas .ui.list a .text{color:#444} .repository .metas .ui.list a .text:hover{color:#000} .repository .metas #deadlineForm input{width:12.8rem;border-radius:4px 0 0 4px;border-right:0;white-space:nowrap} -.repository .header-wrapper{background-color:#FAFAFA;margin-top:-15px;padding-top:15px} -.repository .header-wrapper .ui.tabs.divider{border-bottom:none} +.repository .header-wrapper{background-color:#fafafa;margin-top:-15px;padding-top:15px} +.repository .header-wrapper .ui.tabs.divider{border-bottom:0} .repository .header-wrapper .ui.tabular .octicon{margin-right:5px} .repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px} .repository .filter.menu .octicon{float:left;margin:5px -7px 0 -5px;width:16px} @@ -417,7 +417,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .select-label .item{max-width:250px;overflow:hidden;text-overflow:ellipsis} .repository .select-label .desc{padding-left:16px} .repository .ui.tabs.container{margin-top:14px;margin-bottom:0} -.repository .ui.tabs.container .ui.menu{border-bottom:none} +.repository .ui.tabs.container .ui.menu{border-bottom:0} .repository .ui.tabs.divider{margin-top:0;margin-bottom:20px} .repository #clone-panel{width:350px} @media only screen and (max-width:768px){.repository #clone-panel{width:100%} @@ -446,7 +446,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.file.list #repo-files-table td.age{width:120px} .repository.file.list #repo-files-table td .truncate{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap} .repository.file.list #repo-files-table td.message .isSigned{cursor:default} -.repository.file.list #repo-files-table tr:hover{background-color:#ffE} +.repository.file.list #repo-files-table tr:hover{background-color:#ffe} .repository.file.list #repo-files-table .jumpable-path{color:#888} .repository.file.list .non-diff-file-content .header .icon{font-size:1em} .repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px} @@ -486,7 +486,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.file.editor .commit-form-wrapper .commit-avatar{float:left;margin-left:-64px;width:3em;height:auto} .repository.file.editor .commit-form-wrapper .commit-form{position:relative;padding:15px;margin-bottom:10px;border:1px solid #ddd;border-radius:3px} .repository.file.editor .commit-form-wrapper .commit-form:after,.repository.file.editor .commit-form-wrapper .commit-form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} -.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} .repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#fff} .repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name{display:inline-block;padding:3px 6px;font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.65);background-color:rgba(209,227,237,.45);border-radius:3px} @@ -499,7 +499,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.new.issue .comment.form .comment .avatar{width:3em} .repository.new.issue .comment.form .content{margin-left:4em} .repository.new.issue .comment.form .content:after,.repository.new.issue .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} -.repository.new.issue .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.new.issue .comment.form .content:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository.new.issue .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} .repository.new.issue .comment.form .content:after{border-right-color:#fff} .repository.new.issue .comment.form .content .markdown{font-size:14px} @@ -512,10 +512,10 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .title .index{font-weight:300;color:#aaa;letter-spacing:-1px} .repository.view.issue .title .label{margin-right:10px} .repository.view.issue .title .edit-zone{margin-top:10px} -.repository.view.issue .pull-desc code{color:#0166E6} +.repository.view.issue .pull-desc code{color:#0166e6} .repository.view.issue .pull.tabular.menu{margin-bottom:10px} .repository.view.issue .pull.tabular.menu .octicon{margin-right:5px} -.repository.view.issue .pull.tab.segment{border:none;padding:10px 0 0;box-shadow:none;background-color:inherit} +.repository.view.issue .pull.tab.segment{border:0;padding:10px 0 0;box-shadow:none;background-color:inherit} .repository.view.issue .pull .merge.box .avatar{margin-left:10px;margin-top:10px} .repository.view.issue .pull .review-item .avatar,.repository.view.issue .pull .review-item .type-icon{float:none;display:inline-block;text-align:center;vertical-align:middle} .repository.view.issue .pull .review-item .avatar .octicon,.repository.view.issue .pull .review-item .type-icon .octicon{width:23px;font-size:23px;margin-top:.45em} @@ -532,7 +532,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .comment-list .comment .content{margin-left:4em} .repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px} .repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} -.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} .repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px} .repository.view.issue .comment-list .comment .content .markdown{font-size:14px} @@ -545,7 +545,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image{font-size:128px;color:#000} .repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image:hover{color:#000} .repository.view.issue .comment-list .comment .ui.form .field:first-child{clear:none} -.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:none;padding:10px 0 0} +.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:0;padding:10px 0 0} .repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} .repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px} .repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px} @@ -564,19 +564,19 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .comment.form .ui.comments{margin-top:-12px;max-width:100%} .repository .comment.form .content .field:first-child{clear:none} .repository .comment.form .content .form:after,.repository .comment.form .content .form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} -.repository .comment.form .content .form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository .comment.form .content .form:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository .comment.form .content .form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} .repository .comment.form .content .form:after{border-right-color:#fff} -.repository .comment.form .content .tab.segment{border:none;padding:10px 0 0} +.repository .comment.form .content .tab.segment{border:0;padding:10px 0 0} .repository .comment.form .content textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} .repository .label.list{list-style:none;padding-top:15px} -.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA} +.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #aaa} .repository .label.list .item a{font-size:15px;padding-top:5px;padding-right:10px;color:#666} .repository .label.list .item a:hover{color:#000} .repository .label.list .item a.open-issues{margin-right:30px} .repository .label.list .item .ui.label{font-size:1em} .repository .milestone.list{list-style:none;padding-top:15px} -.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA} +.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #aaa} .repository .milestone.list>.item>a{padding-top:5px;padding-right:10px;color:#000} .repository .milestone.list>.item>a:hover{color:#4078c0} .repository .milestone.list>.item .ui.progress{width:40%;padding:0;border:0;margin:0} @@ -592,7 +592,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.new.milestone #deadline{width:150px} .repository.compare.pull .choose.branch .octicon{padding-right:10px} .repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} -.repository.compare.pull .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +.repository.compare.pull .comment.form .content:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository.compare.pull .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} .repository.compare.pull .comment.form .content:after{border-right-color:#fff} .repository .filter.dropdown .menu{margin-top:1px!important} @@ -610,14 +610,14 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository #commits-table thead .shatd{text-align:center} .repository #commits-table td.sha .sha.label{margin:0} .repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important} -.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #BBB} -.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#FAFAFA;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #BBB;border-top-left-radius:0;border-bottom-left-radius:0} -.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21BA45;background:rgba(33,186,69,.1)} +.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #bbb} +.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#fafafa;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #bbb;border-top-left-radius:0;border-bottom-left-radius:0} +.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21ba45;background:rgba(33,186,69,.1)} .repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon{border-left:1px solid rgba(33,186,69,.5)} .repository .diff-detail-box{padding:7px 0;background:#fff;line-height:30px} .repository .diff-detail-box>div:after{clear:both;content:"";display:block} .repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px} -.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #DDD;padding-left:6px} +.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #ddd;padding-left:6px} .repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle} .repository .diff-detail-box span.status.modify{background-color:#f0db88} .repository .diff-detail-box span.status.add{background-color:#b4e2b4} @@ -631,15 +631,15 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .diff-box .header .file{flex:1;color:#888;word-break:break-all} .repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto} .repository .diff-file-box .header{background-color:#f7f7f7} -.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#A7A7A7;background:#fafafa;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top} +.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#a6a6a6;background:#fafafa;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top} .repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center} -.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #DDD} +.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #ddd} .repository .diff-file-box .code-diff{font-size:12px} -.repository .diff-file-box .code-diff td{padding:0 0 0 10px;border-top:none} +.repository .diff-file-box .code-diff td{padding:0 0 0 10px;border-top:0} .repository .diff-file-box .code-diff pre{margin:0} .repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px} .repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%} -.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#F0F0F0!important;border-color:#D2CECE!important;padding-top:8px;padding-bottom:8px} +.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} .repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99} .repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9} .repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important} @@ -659,19 +659,19 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.quickstart .guide .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem} .repository.quickstart .guide .ui.action.small.input{width:100%} .repository.quickstart .guide #repo-clone-url{border-radius:0;padding:5px 10px;font-size:1.2em} -.repository.release #release-list{border-top:1px solid #DDD;margin-top:20px;padding-top:15px} +.repository.release #release-list{border-top:1px solid #ddd;margin-top:20px;padding-top:15px} .repository.release #release-list>li{list-style:none} .repository.release #release-list>li .detail,.repository.release #release-list>li .meta{padding-top:30px;padding-bottom:40px} .repository.release #release-list>li .meta{text-align:right;position:relative} .repository.release #release-list>li .meta .tag:not(.icon){display:block;margin-top:15px} .repository.release #release-list>li .meta .commit{display:block;margin-top:10px} -.repository.release #release-list>li .detail{border-left:1px solid #DDD} +.repository.release #release-list>li .detail{border-left:1px solid #ddd} .repository.release #release-list>li .detail .author img{margin-bottom:-3px} .repository.release #release-list>li .detail .download{margin-top:20px} .repository.release #release-list>li .detail .download>a .octicon{margin-left:5px;margin-right:5px} .repository.release #release-list>li .detail .download .list{padding-left:0;border-top:1px solid #eee} .repository.release #release-list>li .detail .download .list li{list-style:none;display:block;padding-top:8px;padding-bottom:8px;border-bottom:1px solid #eee} -.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #FFF} +.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #fff} .repository.new.release .target{min-width:500px} .repository.new.release .target #tag-name{margin-top:-4px} .repository.new.release .target .at{margin-left:-5px;margin-right:5px} @@ -683,7 +683,7 @@ footer .ui.left,footer .ui.right{line-height:40px} @media only screen and (max-width:768px){.repository.new.release .field button{margin-bottom:1em} } .repository.forks .list{margin-top:0} -.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #DDD} +.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #ddd} .repository.forks .list .item .ui.avatar{float:left;margin-right:5px} .repository.forks .list .item .link{padding-top:5px} .repository.wiki.start .ui.segment{padding-top:70px;padding-bottom:100px} @@ -699,7 +699,7 @@ footer .ui.left,footer .ui.right{line-height:40px} } .repository.settings.collaboration .collaborator.list{padding:0} .repository.settings.collaboration .collaborator.list>.item{margin:0;line-height:2em} -.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #DDD} +.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #ddd} .repository.settings.collaboration #repo-collab-form #search-user-box .results{left:7px} .repository.settings.collaboration #repo-collab-form .ui.button{margin-left:5px;margin-top:-3px} .repository.settings.branches .protected-branches .selection.dropdown{width:300px} @@ -711,9 +711,9 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.settings.branches .branch-protection .whitelist .dropdown img{display:inline-block} .repository.settings.webhook .events .column{padding-bottom:0} .repository.settings.webhook .events .help{font-size:13px;margin-left:26px;padding-top:0} -.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #A3C293;border-right:1px solid #A3C293} -.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #A3C293} -.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #A3C293} +.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #a3c293;border-right:1px solid #a3c293} +.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #a3c293} +.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #a3c293} .repository .ui.segment.sub-menu{padding:7px;line-height:0} .repository .ui.segment.sub-menu .list{width:100%;display:flex} .repository .ui.segment.sub-menu .list .item{width:100%;border-radius:3px} @@ -743,7 +743,7 @@ footer .ui.left,footer .ui.right{line-height:40px} #issue-actions.hide{display:none} .ui.checkbox.issue-checkbox{vertical-align:middle} .issue.list{list-style:none} -.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #AAA} +.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #aaa} .issue.list>.item .title{color:#444;font-size:15px;font-weight:700;margin:0 6px} .issue.list>.item .title:hover{color:#000} .issue.list>.item .comment{padding-right:10px;color:#666} @@ -756,16 +756,16 @@ footer .ui.left,footer .ui.right{line-height:40px} .issue.list>.item .desc .assignee{margin-top:-5px;margin-right:5px} .issue.list>.item .desc .overdue{color:red} .page.buttons{padding-top:15px} -.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087F7;box-shadow:none!important} +.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087f5;box-shadow:none!important} .ui.form .dropzone .dz-error-message{top:140px} .settings .content{margin-top:2px} .settings .content .segment,.settings .content>.header{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)} -.settings .list>.item .green{color:#21BA45} +.settings .list>.item .green{color:#21ba45} .settings .list>.item:not(:first-child){border-top:1px solid #eaeaea;padding:1rem;margin:15px -1rem -1rem -1rem} .settings .list>.item>.mega-octicon{display:table-cell} .settings .list>.item>.mega-octicon+.content{display:table-cell;padding:0 0 0 .5em;vertical-align:top} .settings .list>.item .info{margin-top:10px} -.settings .list>.item .info .tab.segment{border:none;padding:10px 0 0} +.settings .list>.item .info .tab.segment{border:0;padding:10px 0 0} .settings .list.key .meta{padding-top:5px;color:#666} .settings .list.email>.item:not(:first-child){min-height:60px} .settings .list.collaborator>.item{padding:0} @@ -778,7 +778,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .edit-label.modal .form .precolors,.new-label.segment .form .precolors{padding-left:0;padding-right:0;margin:3px 10px auto 10px;width:120px} .edit-label.modal .form .precolors .color,.new-label.segment .form .precolors .color{float:left;width:15px;height:15px} #avatar-arrow:after,#avatar-arrow:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} -#avatar-arrow:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px} +#avatar-arrow:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} #avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} #delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important} .tab-size-1{-moz-tab-size:1!important;-o-tab-size:1!important;tab-size:1!important} @@ -817,13 +817,13 @@ tbody.commit-list{vertical-align:baseline} .repo-buttons .disabled-repo-button .label{opacity:.5} .repo-buttons .disabled-repo-button a.button{opacity:.5;cursor:not-allowed} .repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important} -.repo-buttons .ui.labeled.button>.label{border-left:none!important;margin:0!important} +.repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important} .CodeMirror{font:14px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} .CodeMirror.cm-s-default{border-radius:3px;padding:0!important} .CodeMirror .cm-comment{background:inherit!important} .repository.file.editor .tab[data-tab=write]{padding:0!important} -.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:none!important} -.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:none;border-right:none;border-bottom:none} +.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:0!important} +.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:0;border-right:0;border-bottom:0} .organization{padding-top:15px} .organization .head .ui.header .text{vertical-align:middle;font-size:1.6rem;margin-left:15px} .organization .head .ui.header .ui.right{margin-top:5px} @@ -858,7 +858,7 @@ tbody.commit-list{vertical-align:baseline} .organization.teams .detail .item{padding:10px 15px} .organization.teams .detail .item:not(:last-child){border-bottom:1px solid #eee} .organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px} -.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #DDD} +.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #ddd} .organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px} .organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0} .organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px} @@ -920,7 +920,7 @@ tbody.commit-list{vertical-align:baseline} .feeds .list .header .ui.label{margin-top:-4px;padding:4px 5px;font-weight:400} .feeds .list .header .plus.icon{margin-top:5px} .feeds .list ul{list-style:none;margin:0;padding-left:0} -.feeds .list ul li:not(:last-child){border-bottom:1px solid #EAEAEA} +.feeds .list ul li:not(:last-child){border-bottom:1px solid #ebebeb} .feeds .list ul li.private{background-color:#fcf8e9} .feeds .list ul li a{padding:6px 1.2em;display:block} .feeds .list ul li a .octicon{color:#888} @@ -942,7 +942,7 @@ tbody.commit-list{vertical-align:baseline} .admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .admin.config #test-mail-btn{margin-left:5px} .explore{padding-top:15px} -.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important} +.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#fafafa!important;border-width:1px!important} .explore .navbar .octicon{width:16px;text-align:center;margin-right:5px} .ui.repository.list .item{padding-bottom:25px} .ui.repository.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px} @@ -965,7 +965,7 @@ tbody.commit-list{vertical-align:baseline} .focus-lines-new .ui.button.add-code-comment.add-code-comment-right,.focus-lines-old .ui.button.add-code-comment.add-code-comment-left{opacity:1} .comment-code-cloud{padding:4px;position:relative;border:1px solid #f1f1f1;margin:13px 10px 5px auto} .comment-code-cloud:before{content:" ";width:0;height:0;border-left:13px solid transparent;border-right:13px solid transparent;border-bottom:13px solid #f1f1f1;left:20px;position:absolute;top:-13px} -.comment-code-cloud .attached.tab{border:none;padding:0;margin:0} +.comment-code-cloud .attached.tab{border:0;padding:0;margin:0} .comment-code-cloud .attached.tab.markdown{padding:1em;min-height:168px} .comment-code-cloud .attached.header{padding:.1rem 1rem} .comment-code-cloud .right.menu.options .item{padding:.85714286em .442857em;cursor:pointer} diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index b78ffad05c..dd2b13542a 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -47,9 +47,9 @@ footer{background:#2e323e;border-top:1px solid #313131} .ui.dropdown .menu>.header{color:#dbdbdb} .ui.red.label,.ui.red.labels .label{background-color:#7d3434!important;border-color:#8a2121!important} .ui.menu{background:#404552;border:1px solid #353945} -.ui.menu .active.item:hover,.ui.vertical.menu .active.item:hover{color:#dbdbdb;background:#4B5162} +.ui.menu .active.item:hover,.ui.vertical.menu .active.item:hover{color:#dbdbdb;background:#4b5162} .ui.link.menu .item:hover,.ui.menu .dropdown.item:hover,.ui.menu .link.item:hover,.ui.menu a.item:hover{color:#dbdbdb;background:#454b5a} -.ui.menu .active.item{background:#4B5162;color:#dbdbdb} +.ui.menu .active.item{background:#4b5162;color:#dbdbdb} .ui.input input{background:#404552;border:2px solid #353945;color:#dbdbdb} .ui.input input:focus,.ui.input.focus input{background:#404552;border:2px solid #353945;color:#dbdbdb} .ui.accordion .title:not(.ui){color:#dbdbdb} @@ -67,7 +67,7 @@ footer{background:#2e323e;border-top:1px solid #313131} .ui.menu .item.disabled,.ui.menu .item.disabled:hover{color:#626773} .ui.pagination.menu .active.item{color:#dbdbdb;background-color:#87ab63} .repository .header-wrapper{background-color:#2a2e3a} -.ui.tabular.menu .active.item{background:#383c4a;color:#dbdbdb;border-left:1px solid transparent;border-right:1px solid transparent;border-top:none} +.ui.tabular.menu .active.item{background:#383c4a;color:#dbdbdb;border-left:1px solid transparent;border-right:1px solid transparent;border-top:0} .ui.tabular.menu .item{color:#9e9e9e} .ui.tabular.menu .item:hover{color:#dbdbdb} .ui.breadcrumb .divider,.ui.header{color:#9e9e9e} @@ -75,8 +75,8 @@ footer{background:#2e323e;border-top:1px solid #313131} .ui.menu .item>.label{background:#565454} .ui.blue.button,.ui.blue.buttons .button{background-color:#87ab63} .ui.blue.button:hover,.ui.blue.buttons .button:hover{background-color:#a0cc75} -.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{background:#404552;border:2px solid #353945} -.ui.form input:not([type]):focus,.ui.form input[type=date]:focus,.ui.form input[type=datetime-local]:focus,.ui.form input[type=email]:focus,.ui.form input[type=number]:focus,.ui.form input[type=password]:focus,.ui.form input[type=search]:focus,.ui.form input[type=tel]:focus,.ui.form input[type=text]:focus,.ui.form input[type=time]:focus,.ui.form input[type=url]:focus{background:#404552;border:2px solid #4b505f;color:#dbdbdb} +.ui.form input:not([type]),.ui.form input[type=text],.ui.form input[type=email],.ui.form input[type=search],.ui.form input[type=password],.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=tel],.ui.form input[type=time],.ui.form input[type=url],.ui.form input[type=number]{color:#9e9e9e;background:#404552;border:2px solid #353945} +.ui.form input:not([type]):focus,.ui.form input[type=text]:focus,.ui.form input[type=email]:focus,.ui.form input[type=search]:focus,.ui.form input[type=password]:focus,.ui.form input[type=date]:focus,.ui.form input[type=datetime-local]:focus,.ui.form input[type=tel]:focus,.ui.form input[type=time]:focus,.ui.form input[type=url]:focus,.ui.form input[type=number]:focus{background:#404552;border:2px solid #4b505f;color:#dbdbdb} .ui.action.input:not([class*="left action"]) input:focus{border-right-color:#4b505f!important} .ui.green.button,.ui.green.buttons .button{background-color:#87ab63} .ui.green.button:hover,.ui.green.buttons .button:hover{background-color:#a0cc75} @@ -126,13 +126,12 @@ footer{background:#2e323e;border-top:1px solid #313131} .repository .diff-file-box .code-diff tbody tr .added-code{background-color:#3a523a} .repository .diff-file-box .code-diff .lines-num{border-right:1px solid #2d2d2d} .repository .diff-file-box .file-body.file-code .lines-num{color:#9e9e9e;background:#2e323e} -.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{border-color:#2d2d2d!important} .repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #2d2d2d} .hljs-section,.hljs-selector-id,.hljs-title{color:#986c88} .hljs-doctag,.hljs-string{color:#949494} .repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#5f3737} .repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#292727!important} -.ui.vertical.menu .active.item{background:#4B5162} +.ui.vertical.menu .active.item{background:#4b5162} .ui.vertical.menu .item{background:#353945} .ui.vertical.menu .header.item{background:#404552} .ui.vertical.menu{background:#353945;border:1px solid #333640} @@ -161,9 +160,8 @@ footer{background:#2e323e;border-top:1px solid #313131} @media only screen and (max-width:1200px){.ui.menu.new-menu:after{background-image:linear-gradient(to right,rgba(42,46,42,0),#2a2e2a 100%)} } input{background:#2e323e} -.ui.secondary.pointing.menu .active.item{border:none;background:#383c4a} +.ui.secondary.pointing.menu .active.item{border:0;background:#383c4a} .settings .key.list .item:not(:first-child){border-top:1px solid #404552} -.ui.form input:not([type]),.ui.form input[type=date],.ui.form input[type=datetime-local],.ui.form input[type=email],.ui.form input[type=number],.ui.form input[type=password],.ui.form input[type=search],.ui.form input[type=tel],.ui.form input[type=text],.ui.form input[type=time],.ui.form input[type=url]{color:#9e9e9e} .ui.attached.info.message,.ui.info.message{box-shadow:0 0 0 1px #4b5e71 inset,0 0 0 0 transparent} .ui.bottom.attached.message{background-color:#2c662d;color:#87ab63} .ui.bottom.attached.message .pull-right{color:#87ab63} @@ -210,7 +208,7 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb .repository.file.list #file-content .code-view .lines-num{background:#2e323e} .repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e} .ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #a27558 inset!important;color:#a27558!important} -.repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} +.repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb} .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#2a2e3a} .repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#283e2d!important;border-color:#314a37!important} @@ -227,11 +225,11 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb .ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} .editor-toolbar{background-color:#404552} .editor-toolbar a{color:#87ab63!important} -.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:none} +.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:0} .CodeMirror-gutters{background-color:#2b2b2b} .repository .diff-detail-box{background-color:#383c4a} .repository .diff-detail-box .detail-files{background-color:inherit} -.comment-code-cloud .ui.attached.tabular.menu{background:none transparent;border:none} +.comment-code-cloud .ui.attached.tabular.menu{background:none transparent;border:0} .comment-code-cloud .footer .markdown-info{color:inherit} .file-comment{color:#888} .ui.comments .comment .author{color:#dbdbdb} diff --git a/public/less/_admin.less b/public/less/_admin.less index 24d5af159c..af68a43dbd 100644 --- a/public/less/_admin.less +++ b/public/less/_admin.less @@ -21,7 +21,8 @@ } &:not(.select) { - th, td { + th, + td { &:first-of-type { padding-left: 15px !important; } @@ -31,7 +32,7 @@ .ui.header, .ui.segment { - box-shadow: 0 1px 2px 0 rgba(34, 36, 38, .15); + box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15); } &.user { diff --git a/public/less/_base.less b/public/less/_base.less index 1dd17541bb..13ae1ad665 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -55,11 +55,16 @@ } /* We're going to just override the semantic fonts here */ - h1, h2, h3, h4, h5 { + h1, + h2, + h3, + h4, + h5 { font-family: Lato, @fonts, sans-serif; } - .home .hero h1, .home .hero h2 { + .home .hero h1, + .home .hero h2 { font-family: 'PT Sans Narrow', Lato, @fonts, sans-serif; } @@ -67,7 +72,18 @@ .ui.button, .ui.card > .content > .header.ui.card > .content > .header, .ui.category.search > .results .category > .name, - .ui.form input:not([type]), .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=email], .ui.form input[type=file], .ui.form input[type=number], .ui.form input[type=password], .ui.form input[type=search], .ui.form input[type=tel], .ui.form input[type=text], .ui.form input[type=time], .ui.form input[type=url], + .ui.form input:not([type]), + .ui.form input[type="date"], + .ui.form input[type="datetime-local"], + .ui.form input[type="email"], + .ui.form input[type="file"], + .ui.form input[type="number"], + .ui.form input[type="password"], + .ui.form input[type="search"], + .ui.form input[type="tel"], + .ui.form input[type="text"], + .ui.form input[type="time"], + .ui.form input[type="url"], .ui.header, .ui.items > .item > .content > .header, .ui.list .list > .item .header, @@ -79,7 +95,8 @@ .ui.search > .results .result .title, .ui.search > .results > .message .header, body, - .ui.input > input, .ui.input input, + .ui.input > input, + .ui.input input, .ui.statistics .statistic > .value, .ui.statistic > .value, .ui.statistics .statistic > .label, @@ -94,7 +111,7 @@ .override-fonts(@default-fonts); body { - background-color: #fff; + background-color: #ffffff; overflow-y: auto; -webkit-font-smoothing: antialiased; display: flex; @@ -139,17 +156,18 @@ a { } .rounded { - border-radius: .28571429rem !important; + border-radius: 0.28571429rem !important; } -pre, code { +pre, +code { font: 12px @monospaced-fonts, monospace; &.raw { padding: 7px 12px; margin: 10px 0; background-color: #f8f8f8; - border: 1px solid #ddd; + border: 1px solid #dddddd; border-radius: 3px; font-size: 13px; line-height: 1.5; @@ -183,7 +201,7 @@ pre, code { &.light { background-color: white; - border-bottom: 1px solid #DDDDDD; + border-bottom: 1px solid #dddddd; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.04); } @@ -206,7 +224,7 @@ pre, code { } .top.menu a.item:hover { - color: rgba(0, 0, 0, .45); + color: rgba(0, 0, 0, 0.45); } .top.menu .menu { @@ -218,14 +236,14 @@ pre, code { margin-right: 0; } - margin-right: .75em; + margin-right: 0.75em; } .searchbox { - background-color: rgb(244, 244, 244) !important; + background-color: #f4f4f4 !important; &:focus { - background-color: rgb(233, 233, 233) !important; + background-color: #e9e9e9 !important; } } @@ -237,7 +255,7 @@ pre, code { #navbar { width: 100vw; min-height: 52px; - padding: 0 .5rem; + padding: 0 0.5rem; } #navbar .brand { @@ -270,7 +288,8 @@ pre, code { float: right; } - &.button, &.menu .item { + &.button, + &.menu .item { user-select: auto; } @@ -306,11 +325,11 @@ pre, code { /* This fixes the commit graph button on the commits page */ .menu:not(.vertical) .item > .button.compact { - padding: .58928571em 1.125em; + padding: 0.58928571em 1.125em; } .menu:not(.vertical) .item > .button.small { - font-size: .92857143rem; + font-size: 0.92857143rem; } &.menu .ui.dropdown.item .menu .item { @@ -333,7 +352,7 @@ pre, code { color: #d95c5c !important; &:hover { - color: #E67777 !important; + color: #e67777 !important; } } } @@ -342,7 +361,7 @@ pre, code { color: #428bca !important; a { - color: #15c !important; + color: #1155cc !important; &:hover { color: #428bca !important; @@ -351,10 +370,10 @@ pre, code { } &.black { - color: #444; + color: #444444; &:hover { - color: #000; + color: #000000; } } @@ -362,16 +381,16 @@ pre, code { color: #767676 !important; a { - color: #444 !important; + color: #444444 !important; &:hover { - color: #000 !important; + color: #000000 !important; } } } &.light.grey { - color: #888 !important; + color: #888888 !important; } &.green { @@ -383,7 +402,7 @@ pre, code { } &.yellow { - color: #FBBD08 !important; + color: #fbbd08 !important; } &.gold { @@ -443,7 +462,8 @@ pre, code { color: black; } - & > span, .pull-right > span { + & > span, + .pull-right > span { color: #21ba45; } } @@ -455,12 +475,12 @@ pre, code { .warning { &.header { - background-color: #F9EDBE !important; - border-color: #F0C36D; + background-color: #f9edbe !important; + border-color: #efc16b; } &.segment { - border-color: #F0C36D; + border-color: #efc16b; } } @@ -471,7 +491,8 @@ pre, code { &.top { background-color: #e6f1f6 !important; - h3, h4 { + h3, + h4 { margin-top: 0; } @@ -533,7 +554,7 @@ pre, code { } &.black { - background-color: #444; + background-color: #444444; } &.grey { @@ -541,7 +562,7 @@ pre, code { } &.light.grey { - background-color: #888 !important; + background-color: #888888 !important; } &.green { @@ -553,7 +574,7 @@ pre, code { } &.yellow { - background-color: #FBBD08 !important; + background-color: #fbbf09 !important; } &.gold { @@ -577,7 +598,7 @@ pre, code { .file-comment { font: 12px @monospaced-fonts, monospace; - color: rgba(0, 0, 0, .87); + color: rgba(0, 0, 0, 0.87); } @@ -611,7 +632,7 @@ footer { .container { width: 100vw !important; - padding: 0 .5rem; + padding: 0 0.5rem; .fa { width: 16px; @@ -625,7 +646,7 @@ footer { margin-left: 5px; &:first-child { - border-left: none; + border-left: 0; } } } @@ -637,7 +658,8 @@ footer { } .ui { - &.left, &.right { + &.left, + &.right { line-height: 40px; } } @@ -665,12 +687,14 @@ footer { width: (2px * @i) !important; height: (2px * @i) !important; } + .generate-img(@n, (@i + 1)); } // Conditional display @media only screen and (min-width: 768px) { - .mobile-only, .ui.button.mobile-only { + .mobile-only, + .ui.button.mobile-only { display: none; } @@ -726,7 +750,7 @@ footer { padding-top: 15px !important; margin-top: -15px !important; margin-bottom: 15px !important; - background-color: #FAFAFA !important; + background-color: #fafafa !important; border-width: 1px !important; } @@ -828,7 +852,7 @@ footer { } .archived-icon { - color: lighten(#000, 70%) !important; + color: lighten(#000000, 70%) !important; } .oauth2-authorize-application-box { @@ -837,13 +861,13 @@ footer { /* Tab color tweaks */ .ui.tabular.menu .item { - color: rgba(0, 0, 0, .5); + color: rgba(0, 0, 0, 0.5); } .ui.tabular.menu .item:hover { - color: rgba(0, 0, 0, .8); + color: rgba(0, 0, 0, 0.8); } .ui.tabular.menu .item.active { - color: rgba(0, 0, 0, .9); + color: rgba(0, 0, 0, 0.9); } diff --git a/public/less/_dashboard.less b/public/less/_dashboard.less index f59daf49d2..1b5d231499 100644 --- a/public/less/_dashboard.less +++ b/public/less/_dashboard.less @@ -71,7 +71,7 @@ .dashboard-navbar { width: 100vw; - padding: 0 .5rem; + padding: 0 0.5rem; } } @@ -142,7 +142,7 @@ li { &:not(:last-child) { - border-bottom: 1px solid #EAEAEA; + border-bottom: 1px solid #ebebeb; } &.private { @@ -154,7 +154,7 @@ display: block; .octicon { - color: #888; + color: #888888; &.rear { font-size: 15px; diff --git a/public/less/_editor.less b/public/less/_editor.less index ee671d8b4b..453b8b433e 100644 --- a/public/less/_editor.less +++ b/public/less/_editor.less @@ -16,11 +16,11 @@ } .repository.file.editor .tab[data-tab="write"] .editor-toolbar { - border: none !important; + border: 0 !important; } .repository.file.editor .tab[data-tab="write"] .CodeMirror { - border-left: none; - border-right: none; - border-bottom: none; + border-left: 0; + border-right: 0; + border-bottom: 0; } diff --git a/public/less/_explore.less b/public/less/_explore.less index 1d635c8b45..809a138a6c 100644 --- a/public/less/_explore.less +++ b/public/less/_explore.less @@ -6,7 +6,7 @@ padding-top: 15px !important; margin-top: -15px !important; margin-bottom: 15px !important; - background-color: #FAFAFA !important; + background-color: #fafafa !important; border-width: 1px !important; .octicon { @@ -22,7 +22,7 @@ padding-bottom: 25px; &:not(:first-child) { - border-top: 1px solid #eee; + border-top: 1px solid #eeeeee; padding-top: 25px; } @@ -35,7 +35,7 @@ } .metas { - color: #888; + color: #888888; font-size: 14px; font-weight: normal; @@ -68,7 +68,7 @@ padding-bottom: 25px; &:not(:first-child) { - border-top: 1px solid #eee; + border-top: 1px solid #eeeeee; padding-top: 25px; } @@ -85,7 +85,7 @@ } a { - color: #333; + color: #333333; &:hover { text-decoration: underline; diff --git a/public/less/_form.less b/public/less/_form.less index 641df7caaf..419b16ecb4 100644 --- a/public/less/_form.less +++ b/public/less/_form.less @@ -1,8 +1,8 @@ .form { .help { color: #999999; - padding-top: .6em; - padding-bottom: .6em; + padding-top: 0.6em; + padding-bottom: 0.6em; display: inline-block; } } @@ -31,6 +31,7 @@ @media only screen and (min-width: 768px) { width: 800px !important; + .header { padding-left: @create-page-form-input-padding+30px; } @@ -54,6 +55,7 @@ width: 50% !important; } } + @media only screen and (max-width: 767px) { .optional .title { margin-left: 15px; @@ -105,7 +107,8 @@ } @media screen and (max-height: 575px) { - #rc-imageselect, .g-recaptcha { + #rc-imageselect, + .g-recaptcha { transform: scale(0.77); transform-origin: 0 0; } @@ -131,7 +134,8 @@ width: @input-padding; } - .inline.field > label, input { + .inline.field > label, + input { @media only screen and (max-width: 768px) { width: 100% !important; } @@ -167,11 +171,14 @@ } @media only screen and (max-width: 768px) { - label, input, .selection.dropdown { + label, + input, + .selection.dropdown { width: 100% !important; } - .field button, .field a { + .field button, + .field a { margin-bottom: 1em; width: 100%; } @@ -222,7 +229,8 @@ .new.org .ui.form { @media only screen and (max-width: 768px) { - .field button, .field a { + .field button, + .field a { margin-bottom: 1em; width: 100%; } diff --git a/public/less/_home.less b/public/less/_home.less index 7ea8a9a6f3..53fd76f098 100644 --- a/public/less/_home.less +++ b/public/less/_home.less @@ -13,6 +13,7 @@ font-size: 2em; } } + @media only screen and (min-width: 768px) { h1 { font-size: 5.5em; @@ -35,7 +36,7 @@ } p.large { - font-size: 16px + font-size: 16px; } .stackable { @@ -52,7 +53,8 @@ } footer { - .ui.container .left, .ui.container .right { + .ui.container .left, + .ui.container .right { @media only screen and (max-width: 880px) { display: block; text-align: center; diff --git a/public/less/_markdown.less b/public/less/_markdown.less index d8a616919d..af46d6a3b2 100644 --- a/public/less/_markdown.less +++ b/public/less/_markdown.less @@ -26,7 +26,7 @@ } .absent { - color: #c00; + color: #cc0000; } .anchor { @@ -67,7 +67,7 @@ h5 .octicon-link, h6 .octicon-link { display: none; - color: #000; + color: #000000; vertical-align: middle; } @@ -110,7 +110,7 @@ padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; - border-bottom: 1px solid #eee; + border-bottom: 1px solid #eeeeee; } h1 .anchor { @@ -121,7 +121,7 @@ padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; - border-bottom: 1px solid #eee; + border-bottom: 1px solid #eeeeee; } h2 .anchor { @@ -155,7 +155,7 @@ h6 { font-size: 1em; - color: #777; + color: #777777; } h6 .anchor { @@ -182,7 +182,7 @@ padding: 0; margin: 16px 0; background-color: #e7e7e7; - border: 0 none; + border: 0; } ul, @@ -232,8 +232,8 @@ blockquote { padding: 0 15px; - color: #777; - border-left: 4px solid #ddd; + color: #777777; + border-left: 4px solid #dddddd; } blockquote > :first-child { @@ -247,7 +247,6 @@ table { width: auto; overflow: auto; - word-break: normal; word-break: keep-all; display: block; } @@ -259,12 +258,12 @@ table th, table td { padding: 6px 13px !important; - border: 1px solid #ddd !important; + border: 1px solid #dddddd !important; } table tr { - background-color: #fff; - border-top: 1px solid #ccc; + background-color: #ffffff; + border-top: 1px solid #cccccc; } table tr:nth-child(2n) { @@ -292,7 +291,7 @@ padding: 7px; margin: 13px 0 0; overflow: hidden; - border: 1px solid #ddd; + border: 1px solid #dddddd; } span.frame span img { @@ -304,7 +303,7 @@ display: block; padding: 5px 0 0; clear: both; - color: #333; + color: #333333; } span.align-center { @@ -452,13 +451,13 @@ padding: 3px 5px; font-size: 11px; line-height: 10px; - color: #555; + color: #555555; vertical-align: middle; background-color: #fcfcfc; - border: solid 1px #ccc; - border-bottom-color: #bbb; + border: solid 1px #cccccc; + border-bottom-color: #bbbbbb; border-radius: 3px; - box-shadow: inset 0 -1px 0 #bbb; + box-shadow: inset 0 -1px 0 #bbbbbb; } input[type="checkbox"] { @@ -478,7 +477,7 @@ .csv-data .blob-num { padding: 10px 8px 9px; text-align: right; - background: #fff; + background: #ffffff; border: 0; } @@ -492,7 +491,9 @@ border-top: 0; } - .ui.list .list, ol.ui.list ol, ul.ui.list ul { + .ui.list .list, + ol.ui.list ol, + ul.ui.list ul { padding-left: 2em; } } diff --git a/public/less/_organization.less b/public/less/_organization.less index f7e855edec..27dc7544fd 100644 --- a/public/less/_organization.less +++ b/public/less/_organization.less @@ -110,7 +110,7 @@ .item { margin-left: 0; margin-right: 0; - border-bottom: 1px solid #eee; + border-bottom: 1px solid #eeeeee; .ui.avatar { width: 48px; @@ -130,7 +130,7 @@ padding: 10px 15px; &:not(:last-child) { - border-bottom: 1px solid #eee; + border-bottom: 1px solid #eeeeee; } } } @@ -142,7 +142,7 @@ line-height: 32px; &:not(:last-child) { - border-bottom: 1px solid #DDD; + border-bottom: 1px solid #dddddd; } .button { diff --git a/public/less/_repository.less b/public/less/_repository.less index e31bc89642..f063d3b1a3 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -101,10 +101,10 @@ margin: 2px 0; .text { - color: #444; + color: #444444; &:hover { - color: #000; + color: #000000; } } } @@ -119,12 +119,12 @@ } .header-wrapper { - background-color: #FAFAFA; + background-color: #fafafa; margin-top: -15px; padding-top: 15px; .ui.tabs.divider { - border-bottom: none; + border-bottom: 0; } .ui.tabular .octicon { @@ -184,7 +184,7 @@ margin-bottom: 0; .ui.menu { - border-bottom: none; + border-bottom: 0; } } @@ -212,7 +212,7 @@ padding: 0 5px; &:first-child { - border-radius: .28571429rem 0 0 .28571429rem; + border-radius: 0.28571429rem 0 0 0.28571429rem; } } @@ -283,7 +283,7 @@ .octicon { margin-left: 3px; margin-right: 5px; - color: #777; + color: #777777; &.octicon-mail-reply { margin-right: 10px; @@ -329,11 +329,11 @@ } tr:hover { - background-color: #ffffEE; + background-color: #ffffee; } .jumpable-path { - color: #888; + color: #888888; } } @@ -369,7 +369,7 @@ } .btn-octicon.disabled { - color: #bbb; + color: #bbbbbb; cursor: default; } @@ -413,7 +413,7 @@ .lines-num { vertical-align: top; text-align: right; - color: #999; + color: #999999; background: #f5f5f5; width: 1%; user-select: none; @@ -454,7 +454,7 @@ .lines-commit { vertical-align: top; - color: #999; + color: #999999; padding: 0; background: #f5f5f5; width: 1%; @@ -551,12 +551,12 @@ position: relative; padding: 15px; margin-bottom: 10px; - border: 1px solid #ddd; + border: 1px solid #dddddd; border-radius: 3px; #avatar-arrow; &:after { - border-right-color: #fff; + border-right-color: #ffffff; } .quick-pull-choice { @@ -622,7 +622,7 @@ #avatar-arrow; &:after { - border-right-color: #fff; + border-right-color: #ffffff; } .markdown { @@ -666,7 +666,7 @@ .index { font-weight: 300; - color: #aaa; + color: #aaaaaa; letter-spacing: -1px; } @@ -681,7 +681,7 @@ .pull-desc { code { - color: #0166E6; + color: #0166e6; } } @@ -695,7 +695,7 @@ } &.tab.segment { - border: none; + border: 0; padding: 10px 0 0; box-shadow: none; background-color: inherit; @@ -725,7 +725,7 @@ } .text { - margin: .3em 0 .5em .5em + margin: 0.3em 0 0.5em 0.5em; } .type-icon { @@ -734,7 +734,7 @@ } .divider { - margin: .5rem 0; + margin: 0.5rem 0; } .review-content { @@ -797,7 +797,7 @@ position: relative; color: #767676; background-color: #f7f7f7; - border-bottom: 1px solid #eee; + border-bottom: 1px solid #eeeeee; border-top-left-radius: 3px; border-top-right-radius: 3px; @@ -832,10 +832,10 @@ margin: 5px; padding: 5px; height: 150px; - border: solid 1px #eee; + border: solid 1px #eeeeee; border-radius: 3px; max-width: 150px; - background-color: #fff; + background-color: #ffffff; &:before { content: ' '; @@ -869,7 +869,7 @@ } .tab.segment { - border: none; + border: 0; padding: 10px 0 0; } @@ -983,12 +983,12 @@ #avatar-arrow; &:after { - border-right-color: #fff; + border-right-color: #ffffff; } } .tab.segment { - border: none; + border: 0; padding: 10px 0 0; } @@ -1006,16 +1006,16 @@ .item { padding-top: 10px; padding-bottom: 10px; - border-bottom: 1px dashed #AAA; + border-bottom: 1px dashed #aaaaaa; a { font-size: 15px; padding-top: 5px; padding-right: 10px; - color: #666; + color: #666666; &:hover { - color: #000; + color: #000000; } &.open-issues { @@ -1036,12 +1036,12 @@ > .item { padding-top: 10px; padding-bottom: 10px; - border-bottom: 1px dashed #AAA; + border-bottom: 1px dashed #aaaaaa; > a { padding-top: 5px; padding-right: 10px; - color: #000; + color: #000000; &:hover { color: #4078c0; @@ -1060,7 +1060,7 @@ } .meta { - color: #999; + color: #999999; padding-top: 5px; .issue-stats .octicon { @@ -1079,10 +1079,10 @@ font-size: 15px; padding-top: 5px; padding-right: 10px; - color: #666; + color: #666666; &:hover { - color: #000; + color: #000000; } } } @@ -1115,7 +1115,7 @@ #avatar-arrow; &:after { - border-right-color: #fff; + border-right-color: #ffffff; } } } @@ -1197,38 +1197,38 @@ } &.ui.basic.striped.table tbody tr:nth-child(2n) { - background-color: rgba(0, 0, 0, .02) !important; + background-color: rgba(0, 0, 0, 0.02) !important; } } #commits-table td.sha .sha.label, #repo-files-table .sha.label { &.isSigned { - border: 1px solid #BBB; + border: 1px solid #bbbbbb; .detail.icon { - background: #FAFAFA; + background: #fafafa; margin: -6px -10px -4px 0px; padding: 5px 3px 5px 6px; - border-left: 1px solid #BBB; + border-left: 1px solid #bbbbbb; border-top-left-radius: 0; border-bottom-left-radius: 0; } } &.isSigned.isVerified { - border: 1px solid #21BA45; - background: fade(#21BA45, 10%); + border: 1px solid #21ba45; + background: fade(#21ba45, 10%); .detail.icon { - border-left: 1px solid fade(#21BA45, 50%); + border-left: 1px solid fade(#21ba45, 50%); } } } .diff-detail-box { padding: 7px 0; - background: #fff; + background: #ffffff; line-height: 30px; > div:after { @@ -1247,7 +1247,7 @@ list-style: none; padding-bottom: 4px; margin-bottom: 4px; - border-bottom: 1px dashed #DDD; + border-bottom: 1px dashed #dddddd; padding-left: 6px; } } @@ -1277,7 +1277,7 @@ } .detail-files { - background: #fff; + background: #ffffff; margin: 0; } } @@ -1308,7 +1308,7 @@ .file { flex: 1; - color: #888; + color: #888888; word-break: break-all; } @@ -1327,7 +1327,7 @@ .file-body.file-code { .lines-num { text-align: right; - color: #A7A7A7; + color: #a6a6a6; background: #fafafa; width: 1%; user-select: none; @@ -1340,7 +1340,7 @@ } .lines-num-old { - border-right: 1px solid #DDD; + border-right: 1px solid #dddddd; } } @@ -1349,7 +1349,7 @@ td { padding: 0 0 0 10px; - border-top: none; + border-top: 0; } pre { @@ -1372,8 +1372,8 @@ &.tag-code td, td.tag-code { - background-color: #F0F0F0 !important; - border-color: #D2CECE !important; + background-color: #f0f0f0 !important; + border-color: #d3cfcf !important; padding-top: 8px; padding-bottom: 8px; // td.selected-line, td.selected-line pre { @@ -1484,7 +1484,7 @@ } .clone.button:first-child { - border-radius: .28571429rem 0 0 .28571429rem; + border-radius: 0.28571429rem 0 0 0.28571429rem; } .ui.action.small.input { @@ -1501,7 +1501,7 @@ &.release { #release-list { - border-top: 1px solid #DDD; + border-top: 1px solid #dddddd; margin-top: 20px; padding-top: 15px; @@ -1530,7 +1530,7 @@ } .detail { - border-left: 1px solid #DDD; + border-left: 1px solid #dddddd; .author { img { @@ -1550,14 +1550,14 @@ .list { padding-left: 0; - border-top: 1px solid #eee; + border-top: 1px solid #eeeeee; li { list-style: none; display: block; padding-top: 8px; padding-bottom: 8px; - border-bottom: 1px solid #eee; + border-bottom: 1px solid #eeeeee; } } } @@ -1565,14 +1565,14 @@ .dot { width: 9px; height: 9px; - background-color: #ccc; + background-color: #cccccc; z-index: 999; position: absolute; display: block; left: -5px; top: 40px; border-radius: 6px; - border: 1px solid #FFF; + border: 1px solid #ffffff; } } } @@ -1631,7 +1631,7 @@ .item { padding-top: 10px; padding-bottom: 10px; - border-bottom: 1px solid #DDD; + border-bottom: 1px solid #dddddd; .ui.avatar { float: left; @@ -1716,7 +1716,7 @@ line-height: 2em; &:not(:last-child) { - border-bottom: 1px solid #DDD; + border-bottom: 1px solid #dddddd; } } } @@ -1789,16 +1789,16 @@ .ui.attached.isSigned.isVerified { &:not(.positive) { - border-left: 1px solid #A3C293; - border-right: 1px solid #A3C293; + border-left: 1px solid #a3c293; + border-right: 1px solid #a3c293; } &.top:not(.positive) { - border-top: 1px solid #A3C293; + border-top: 1px solid #a3c293; } &:not(.positive):last-child { - border-bottom: 1px solid #A3C293; + border-bottom: 1px solid #a3c293; } } @@ -1818,12 +1818,12 @@ color: black; &:hover { - color: #666; + color: #666666; } } &.active { - background: rgba(0, 0, 0, .05); + background: rgba(0, 0, 0, 0.05); } } } @@ -1836,12 +1836,12 @@ left: auto !important; > .header { - margin: 0.75rem 0 .5rem; + margin: 0.75rem 0 0.5rem; } > .item { float: left; - padding: .5rem .5rem !important; + padding: 0.5rem 0.5rem !important; img.emoji { margin-right: 0; @@ -1851,10 +1851,10 @@ } .segment.reactions { - padding: .3em 1em; + padding: 0.3em 1em; .ui.label { - padding: .4em; + padding: 0.4em; &.disabled { cursor: default; @@ -1953,27 +1953,27 @@ > .item { padding-top: 15px; padding-bottom: 10px; - border-bottom: 1px dashed #AAA; + border-bottom: 1px dashed #aaaaaa; .title { - color: #444; + color: #444444; font-size: 15px; font-weight: bold; margin: 0 6px; &:hover { - color: #000; + color: #000000; } } .comment { padding-right: 10px; - color: #666; + color: #666666; } .desc { padding-top: 5px; - color: #999; + color: #999999; .checklist { padding-left: 5px; @@ -1983,13 +1983,13 @@ width: 80px; height: 6px; display: inline-block; - background-color: #eee; + background-color: #eeeeee; overflow: hidden; border-radius: 3px; vertical-align: 2px !important; .progress { - background-color: #ccc; + background-color: #cccccc; display: block; height: 100%; } @@ -1998,10 +1998,10 @@ a.milestone { padding-left: 5px; - color: #999 !important; + color: #999999 !important; &:hover { - color: #000 !important; + color: #000000 !important; } } @@ -2025,7 +2025,7 @@ .dropzone { width: 100%; margin-bottom: 10px; - border: 2px dashed #0087F7; + border: 2px dashed #0087f5; box-shadow: none !important; .dz-error-message { @@ -2040,14 +2040,14 @@ > .header, .segment { - box-shadow: 0 1px 2px 0 rgba(34, 36, 38, .15); + box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15); } } .list { > .item { .green { - color: #21BA45; + color: #21ba45; } &:not(:first-child) { @@ -2062,7 +2062,7 @@ > .mega-octicon + .content { display: table-cell; - padding: 0 0 0 .5em; + padding: 0 0 0 0.5em; vertical-align: top; } @@ -2070,7 +2070,7 @@ margin-top: 10px; .tab.segment { - border: none; + border: 0; padding: 10px 0 0; } } @@ -2079,7 +2079,7 @@ &.key { .meta { padding-top: 5px; - color: #666; + color: #666666; } } @@ -2163,7 +2163,7 @@ } &:before { - border-right-color: #D4D4D5; + border-right-color: #d3d3d4; border-width: 9px; margin-top: -9px; } @@ -2201,7 +2201,7 @@ display: table-cell; &.tiny { - height: .5em; + height: 0.5em; } } } @@ -2276,21 +2276,21 @@ tbody.commit-list { } .repo-buttons .disabled-repo-button .label { - opacity: .5; + opacity: 0.5; } .repo-buttons .disabled-repo-button a.button { - opacity: .5; + opacity: 0.5; cursor: not-allowed; } .repo-buttons .disabled-repo-button a.button:hover { background: none !important; - color: rgba(0, 0, 0, .6) !important; - box-shadow: 0 0 0 1px rgba(34, 36, 38, .15) inset !important; + color: rgba(0, 0, 0, 0.6) !important; + box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.15) inset !important; } .repo-buttons .ui.labeled.button > .label { - border-left: none !important; + border-left: 0 !important; margin: 0 !important; } diff --git a/public/less/_review.less b/public/less/_review.less index a4a813cfd8..c01e7533b4 100644 --- a/public/less/_review.less +++ b/public/less/_review.less @@ -41,7 +41,7 @@ .attached { &.tab { - border: none; + border: 0; padding: 0; margin: 0; @@ -52,7 +52,7 @@ } &.header { - padding: .1rem 1rem; + padding: 0.1rem 1rem; } } @@ -81,7 +81,7 @@ display: inline-block; margin: 5px 0; font-size: 12px; - color: rgba(0, 0, 0, .6) + color: rgba(0, 0, 0, 0.6); } .ui.right.floated { @@ -106,5 +106,5 @@ .file-comment { font: 12px @monospaced-fonts, monospace; - color: rgba(0, 0, 0, .87); + color: rgba(0, 0, 0, 0.87); } diff --git a/public/less/_tribute.less b/public/less/_tribute.less index 4db85a2cb6..ad097bef6d 100644 --- a/public/less/_tribute.less +++ b/public/less/_tribute.less @@ -24,8 +24,9 @@ } } - li.highlight, li:hover { - background: #2185D0; + li.highlight, + li:hover { + background: #2185d0; color: #ffffff; } } diff --git a/public/less/themes/_base.less b/public/less/themes/_base.less index 18d4f068c8..e339a6fa8e 100644 --- a/public/less/themes/_base.less +++ b/public/less/themes/_base.less @@ -1,3 +1,3 @@ // TODO: Instead of having each theme file define each // CSS/LESS item in this file and then overide -// in the theme files \ No newline at end of file +// in the theme files diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index 7a6fb64150..6d13bb2e52 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -7,19 +7,27 @@ color: #bababa; } -.repository.file.list .non-diff-file-content .code-view .lines-num, .repository.file.list .non-diff-file-content .code-view .lines-code ol { +.repository.file.list .non-diff-file-content .code-view .lines-num, +.repository.file.list .non-diff-file-content .code-view .lines-code ol { background-color: #2b2b2b !important; } -.hljs-strong, .hljs-emphasis { +.hljs-strong, +.hljs-emphasis { color: #a8a8a2; } -.hljs-bullet, .hljs-quote, .hljs-link, .hljs-number, .hljs-regexp, .hljs-literal { +.hljs-bullet, +.hljs-quote, +.hljs-link, +.hljs-number, +.hljs-regexp, +.hljs-literal { color: #6896ba; } -.hljs-code, .hljs-selector-class { +.hljs-code, +.hljs-selector-class { color: #a6e22e; } @@ -27,7 +35,12 @@ font-style: italic; } -.hljs-keyword, .hljs-selector-tag, .hljs-section, .hljs-attribute, .hljs-name, .hljs-variable { +.hljs-keyword, +.hljs-selector-tag, +.hljs-section, +.hljs-attribute, +.hljs-name, +.hljs-variable { color: #cb7832; } @@ -39,11 +52,23 @@ color: #6a8759; } -.hljs-subst, .hljs-type, .hljs-built_in, .hljs-builtin-name, .hljs-symbol, .hljs-selector-id, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-template-tag, .hljs-template-variable, .hljs-addition { +.hljs-subst, +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-symbol, +.hljs-selector-id, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-template-tag, +.hljs-template-variable, +.hljs-addition { color: #e0c46c; } -.hljs-comment, .hljs-deletion, .hljs-meta { +.hljs-comment, +.hljs-deletion, +.hljs-meta { color: #7f7f7f; } @@ -68,7 +93,8 @@ a:hover { color: #a0cc75; } -.ui.card > .extra a:not(.ui):hover, .ui.cards > .card > .extra a:not(.ui):hover { +.ui.card > .extra a:not(.ui):hover, +.ui.cards > .card > .extra a:not(.ui):hover { color: #a0cc75; } @@ -137,7 +163,7 @@ a:hover { } .following.bar .top.menu a.item:hover { - color: #fff; + color: #ffffff; } .repository.view.issue .comment-list .comment .content > .bottom.segment a { @@ -169,8 +195,10 @@ a:hover { border: 1px solid #333640; } -.ui.secondary.menu .dropdown.item:hover, .ui.secondary.menu .link.item:hover, .ui.secondary.menu a.item:hover { - color: #fff; +.ui.secondary.menu .dropdown.item:hover, +.ui.secondary.menu .link.item:hover, +.ui.secondary.menu a.item:hover { + color: #ffffff; } .ui.menu .ui.dropdown .menu > .item { @@ -178,7 +206,8 @@ a:hover { color: #9e9e9e !important; } -.ui.secondary.menu .dropdown.item > .menu, .ui.text.menu .dropdown.item > .menu { +.ui.secondary.menu .dropdown.item > .menu, +.ui.text.menu .dropdown.item > .menu { border: 1px solid #434444; } @@ -191,15 +220,17 @@ footer { background: #2c303a; } -.ui.menu .ui.dropdown .menu > .item:hover, .ui.menu .ui.dropdown .menu > .selected.item { - color: #fff !important; +.ui.menu .ui.dropdown .menu > .item:hover, +.ui.menu .ui.dropdown .menu > .selected.item { + color: #ffffff !important; } .ui.dropdown .menu > .header { color: #dbdbdb; } -.ui.red.label, .ui.red.labels .label { +.ui.red.label, +.ui.red.labels .label { background-color: #7d3434 !important; border-color: #8a2121 !important; } @@ -209,18 +240,22 @@ footer { border: 1px solid #353945; } -.ui.menu .active.item:hover, .ui.vertical.menu .active.item:hover { +.ui.menu .active.item:hover, +.ui.vertical.menu .active.item:hover { color: #dbdbdb; - background: #4B5162; + background: #4b5162; } -.ui.link.menu .item:hover, .ui.menu .dropdown.item:hover, .ui.menu .link.item:hover, .ui.menu a.item:hover { +.ui.link.menu .item:hover, +.ui.menu .dropdown.item:hover, +.ui.menu .link.item:hover, +.ui.menu a.item:hover { color: #dbdbdb; background: #454b5a; } .ui.menu .active.item { - background: #4B5162; + background: #4b5162; color: #dbdbdb; } @@ -230,7 +265,8 @@ footer { color: #dbdbdb; } -.ui.input input:focus, .ui.input.focus input { +.ui.input input:focus, +.ui.input.focus input { background: #404552; border: 2px solid #353945; color: #dbdbdb; @@ -257,31 +293,39 @@ footer { border-bottom: 1px dashed #475767; } -.ui.green.label, .ui.green.labels .label, .ui.basic.green.label { +.ui.green.label, +.ui.green.labels .label, +.ui.basic.green.label { background-color: #2d693b !important; border-color: #2d693b !important; } -.ui.basic.green.labels a.label:hover, a.ui.basic.green.label:hover { +.ui.basic.green.labels a.label:hover, +a.ui.basic.green.label:hover { background-color: #16ab39 !important; border-color: #16ab39 !important; - color: #fff !important; + color: #ffffff !important; } .issue.list > .item .comment { color: #129c92; } -.ui.basic.button, .ui.basic.buttons .button { +.ui.basic.button, +.ui.basic.buttons .button { color: #797979 !important; } -.ui.basic.red.active.button, .ui.basic.red.buttons .active.button { +.ui.basic.red.active.button, +.ui.basic.red.buttons .active.button { box-shadow: 0 0 0 1px #c75252 inset !important; color: #c75252 !important; } -.ui.basic.button:focus, .ui.basic.button:hover, .ui.basic.buttons .button:focus, .ui.basic.buttons .button:hover { +.ui.basic.button:focus, +.ui.basic.button:hover, +.ui.basic.buttons .button:focus, +.ui.basic.buttons .button:hover { background: transparent !important; color: #dbdbdb !important; } @@ -291,7 +335,8 @@ footer { color: #9e9e9e; } -.ui.menu .item.disabled, .ui.menu .item.disabled:hover { +.ui.menu .item.disabled, +.ui.menu .item.disabled:hover { color: #626773; } @@ -309,7 +354,7 @@ footer { color: #dbdbdb; border-left: 1px solid transparent; border-right: 1px solid transparent; - border-top: none; + border-top: 0; } .ui.tabular.menu .item { @@ -320,11 +365,13 @@ footer { color: #dbdbdb; } -.ui.header, .ui.breadcrumb .divider { +.ui.header, +.ui.breadcrumb .divider { color: #9e9e9e; } -.ui.blue.label, .ui.blue.labels .label { +.ui.blue.label, +.ui.blue.labels .label { background-color: #26577b !important; border-color: #26577b !important; } @@ -333,20 +380,43 @@ footer { background: #565454; } -.ui.blue.button, .ui.blue.buttons .button { +.ui.blue.button, +.ui.blue.buttons .button { background-color: #87ab63; } -.ui.blue.button:hover, .ui.blue.buttons .button:hover { +.ui.blue.button:hover, +.ui.blue.buttons .button:hover { background-color: #a0cc75; } -.ui.form input:not([type]), .ui.form input[type=text], .ui.form input[type=email], .ui.form input[type=search], .ui.form input[type=password], .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=tel], .ui.form input[type=time], .ui.form input[type=url], .ui.form input[type=number] { +.ui.form input:not([type]), +.ui.form input[type="text"], +.ui.form input[type="email"], +.ui.form input[type="search"], +.ui.form input[type="password"], +.ui.form input[type="date"], +.ui.form input[type="datetime-local"], +.ui.form input[type="tel"], +.ui.form input[type="time"], +.ui.form input[type="url"], +.ui.form input[type="number"] { + color: #9e9e9e; background: #404552; border: 2px solid #353945; } -.ui.form input:not([type]):focus, .ui.form input[type=text]:focus, .ui.form input[type=email]:focus, .ui.form input[type=search]:focus, .ui.form input[type=password]:focus, .ui.form input[type=date]:focus, .ui.form input[type=datetime-local]:focus, .ui.form input[type=tel]:focus, .ui.form input[type=time]:focus, .ui.form input[type=url]:focus, .ui.form input[type=number]:focus { +.ui.form input:not([type]):focus, +.ui.form input[type="text"]:focus, +.ui.form input[type="email"]:focus, +.ui.form input[type="search"]:focus, +.ui.form input[type="password"]:focus, +.ui.form input[type="date"]:focus, +.ui.form input[type="datetime-local"]:focus, +.ui.form input[type="tel"]:focus, +.ui.form input[type="time"]:focus, +.ui.form input[type="url"]:focus, +.ui.form input[type="number"]:focus { background: #404552; border: 2px solid #4b505f; color: #dbdbdb; @@ -356,11 +426,13 @@ footer { border-right-color: #4b505f !important; } -.ui.green.button, .ui.green.buttons .button { +.ui.green.button, +.ui.green.buttons .button { background-color: #87ab63; } -.ui.green.button:hover, .ui.green.buttons .button:hover { +.ui.green.button:hover, +.ui.green.buttons .button:hover { background-color: #a0cc75; } @@ -370,7 +442,8 @@ footer { color: #dbdbdb; } -.ui.labeled.button:not([class*="left labeled"]) > .label, .ui[class*="left labeled"].button > .button { +.ui.labeled.button:not([class*="left labeled"]) > .label, +.ui[class*="left labeled"].button > .button { background: #404552; border: 1px solid #4c505c; color: #87ab63; @@ -414,11 +487,15 @@ footer { border-bottom: 1px solid #304251; } -.hljs, .hljs-keyword, .hljs-selector-tag, .hljs-subst { +.hljs, +.hljs-keyword, +.hljs-selector-tag, +.hljs-subst { color: #9daccc; } -.markdown:not(code) .highlight pre, .markdown:not(code) pre { +.markdown:not(code) .highlight pre, +.markdown:not(code) pre { background-color: #2a2e3a; border: 1px solid #404552; } @@ -432,7 +509,7 @@ footer { } .ui.dropdown .menu > .message:not(.ui) { - color: rgb(99, 99, 99); + color: #636363; } .ui.input { @@ -453,12 +530,15 @@ footer { border: 1px solid #404552; } -.ui.active.button:active, .ui.button:active, .ui.button:focus { +.ui.active.button:active, +.ui.button:active, +.ui.button:focus { background-color: #2e3e4e; color: #dbdbdb; } -.ui.dropdown .menu .selected.item, .ui.dropdown.selected { +.ui.dropdown .menu .selected.item, +.ui.dropdown.selected { color: #dbdbdb; } @@ -528,11 +608,13 @@ footer { color: #dbdbdb !important; } -.ui.basic.green.active.button, .ui.basic.green.buttons .active.button { +.ui.basic.green.active.button, +.ui.basic.green.buttons .active.button { color: #13ae38 !important; } -.ui.form textarea, .ui.form textarea:focus { +.ui.form textarea, +.ui.form textarea:focus { background: #1a2632; border: 1px solid #313c47; color: #dbdbdb; @@ -552,7 +634,7 @@ footer { } .repository .diff-file-box .code-diff-unified tbody tr.add-code td { - background-color: rgb(40, 62, 45) !important; + background-color: #283e2d !important; border-color: #314a37 !important; } @@ -569,19 +651,18 @@ footer { background: #2e323e; } -.repository .diff-file-box .code-diff tbody tr.tag-code td, .repository .diff-file-box .code-diff tbody tr td.tag-code { - border-color: #2d2d2d !important; -} - .repository .diff-file-box .file-body.file-code .lines-num-old { border-right: 1px solid #2d2d2d; } -.hljs-title, .hljs-section, .hljs-selector-id { +.hljs-title, +.hljs-section, +.hljs-selector-id { color: #986c88; } -.hljs-string, .hljs-doctag { +.hljs-string, +.hljs-doctag { color: #949494; } @@ -589,12 +670,13 @@ footer { background-color: #5f3737; } -.repository .diff-file-box .code-diff tbody tr.tag-code td, .repository .diff-file-box .code-diff tbody tr td.tag-code { +.repository .diff-file-box .code-diff tbody tr.tag-code td, +.repository .diff-file-box .code-diff tbody tr td.tag-code { background-color: #292727 !important; } .ui.vertical.menu .active.item { - background: #4B5162; + background: #4b5162; } .ui.vertical.menu .item { @@ -618,19 +700,21 @@ footer { color: #87ab63 !important; } -.ui.selection.active.dropdown, .ui.selection.active.dropdown .menu { +.ui.selection.active.dropdown, +.ui.selection.active.dropdown .menu { border-color: #4e5361; - box-shadow: 0 2px 3px 0 rgba(34, 36, 38, .15); + box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15); } -.ui.selection.active.dropdown:hover, .ui.selection.active.dropdown:hover .menu { +.ui.selection.active.dropdown:hover, +.ui.selection.active.dropdown:hover .menu { border-color: #4e5361; - box-shadow: 0 2px 3px 0 rgba(34, 36, 38, .15); + box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15); } .ui.selection.dropdown { background: #404552; - border: 1px solid rgb(64, 69, 82); + border: 1px solid #404552; color: #9e9e9e; } @@ -642,16 +726,19 @@ footer { border-bottom: 1px solid #313c47; } -.ui.card, .ui.cards > .card { +.ui.card, +.ui.cards > .card { background: #353945; box-shadow: 0 1px 3px 0 #4c505c, 0 0 0 1px #4c505c; } -.ui.card > .content > .header, .ui.cards > .card > .content > .header { +.ui.card > .content > .header, +.ui.cards > .card > .content > .header { color: #dbdbdb; } -.ui.card > .extra a:not(.ui), .ui.cards > .card > .extra a:not(.ui) { +.ui.card > .extra a:not(.ui), +.ui.cards > .card > .extra a:not(.ui) { color: #87ab63; } @@ -683,15 +770,23 @@ footer { background: #4b5162; } -.ui.secondary.pointing.menu .dropdown.item:hover, .ui.secondary.pointing.menu .link.item:hover, .ui.secondary.pointing.menu a.item:hover { +.ui.secondary.pointing.menu .dropdown.item:hover, +.ui.secondary.pointing.menu .link.item:hover, +.ui.secondary.pointing.menu a.item:hover { color: #dbdbdb; } -.ui.checkbox label, .ui.checkbox + label, .ui.form .field > label { +.ui.checkbox label, +.ui.checkbox + label, +.ui.form .field > label { color: #9e9e9e; } -.ui.form .inline.field > label, .ui.form .inline.field > p, .ui.form .inline.fields .field > label, .ui.form .inline.fields .field > p, .ui.form .inline.fields > label { +.ui.form .inline.field > label, +.ui.form .inline.field > p, +.ui.form .inline.fields .field > label, +.ui.form .inline.fields .field > p, +.ui.form .inline.fields > label { color: #9e9e9e; } @@ -717,7 +812,7 @@ input { } .ui.secondary.pointing.menu .active.item { - border: none; + border: 0; background: #383c4a; } @@ -725,11 +820,8 @@ input { border-top: 1px solid #404552; } -.ui.form input:not([type]), .ui.form input[type=text], .ui.form input[type=email], .ui.form input[type=search], .ui.form input[type=password], .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=tel], .ui.form input[type=time], .ui.form input[type=url], .ui.form input[type=number] { - color: #9e9e9e; -} - -.ui.attached.info.message, .ui.info.message { +.ui.attached.info.message, +.ui.info.message { box-shadow: 0 0 0 1px #4b5e71 inset, 0 0 0 0 transparent; } @@ -762,65 +854,84 @@ input { box-shadow: 0 0 0 1px rgba(121, 71, 66, 0.5) inset, 0 0 0 0 transparent; } -.ui.red.button, .ui.red.buttons .button { +.ui.red.button, +.ui.red.buttons .button { background-color: #7d3434; } -.ui.red.button:hover, .ui.red.buttons .button:hover { +.ui.red.button:hover, +.ui.red.buttons .button:hover { background-color: #984646; } -.ui.checkbox label:hover, .ui.checkbox + label:hover { +.ui.checkbox label:hover, +.ui.checkbox + label:hover { color: #dbdbdb !important; } -.ui.checkbox input:checked ~ .box:after, .ui.checkbox input:checked ~ label:after { - color: rgb(127, 152, 173); +.ui.checkbox input:checked ~ .box:after, +.ui.checkbox input:checked ~ label:after { + color: #7f98ad; } -.ui.checkbox input:checked ~ .box:before, .ui.checkbox input:checked ~ label:before { +.ui.checkbox input:checked ~ .box:before, +.ui.checkbox input:checked ~ label:before { background: #304251; } -.ui.checkbox .box:hover::before, .ui.checkbox label:hover::before { +.ui.checkbox .box:hover::before, +.ui.checkbox label:hover::before { background: #304251; } -.ui.checkbox .box:before, .ui.checkbox label:before { +.ui.checkbox .box:before, +.ui.checkbox label:before { background: #304251; border: 1px solid #304251; } -.ui.checkbox .box:active::before, .ui.checkbox label:active::before { +.ui.checkbox .box:active::before, +.ui.checkbox label:active::before { background: #304251; - border-color: rgba(34, 36, 38, .35); + border-color: rgba(34, 36, 38, 0.35); } -.ui.checkbox input:checked ~ .box:before, .ui.checkbox input:checked ~ label:before { +.ui.checkbox input:checked ~ .box:before, +.ui.checkbox input:checked ~ label:before { border-color: #304251; background: #304251; } -.ui.checkbox input:focus ~ .box:before, .ui.checkbox input:focus ~ label:before { +.ui.checkbox input:focus ~ .box:before, +.ui.checkbox input:focus ~ label:before { border-color: #304251; background: #304251; } -.ui.checkbox input:checked:focus ~ .box:before, .ui.checkbox input:checked:focus ~ label:before, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ .box:before, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ label:before { +.ui.checkbox input:checked:focus ~ .box:before, +.ui.checkbox input:checked:focus ~ label:before, +.ui.checkbox input:not([type="radio"]):indeterminate:focus ~ .box:before, +.ui.checkbox input:not([type="radio"]):indeterminate:focus ~ label:before { border-color: #304251; background: #304251; } -.ui.checkbox input:checked ~ .box:after, .ui.checkbox input:checked ~ label:after { +.ui.checkbox input:checked ~ .box:after, +.ui.checkbox input:checked ~ label:after { opacity: 1; - color: rgb(127, 152, 173); + color: #7f98ad; } -.ui.checkbox input:checked:focus ~ .box:after, .ui.checkbox input:checked:focus ~ label:after, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ .box:after, .ui.checkbox input:not([type=radio]):indeterminate:focus ~ label:after { - color: rgb(127, 152, 173); +.ui.checkbox input:checked:focus ~ .box:after, +.ui.checkbox input:checked:focus ~ label:after, +.ui.checkbox input:not([type="radio"]):indeterminate:focus ~ .box:after, +.ui.checkbox input:not([type="radio"]):indeterminate:focus ~ label:after { + color: #7f98ad; } -.ui.checkbox input:focus ~ .box:after, .ui.checkbox input:focus ~ label, .ui.checkbox input:focus ~ label:after { +.ui.checkbox input:focus ~ .box:after, +.ui.checkbox input:focus ~ label, +.ui.checkbox input:focus ~ label:after { color: #9a9a9a; } @@ -842,7 +953,9 @@ input { box-shadow: 0 0 0 1px rgba(121, 71, 66, 0.5) inset, 0 0 0 0 transparent; } -.hljs-tag, .hljs-name, .hljs-attribute { +.hljs-tag, +.hljs-name, +.hljs-attribute { color: #ef5e77; } @@ -850,16 +963,22 @@ input { border-bottom: 1px solid #4c505c; } -.ui.form textarea, .ui.form textarea:focus { +.ui.form textarea, +.ui.form textarea:focus { background: #404552; border: 2px solid #353945; } -.hljs-number, .hljs-literal, .hljs-variable, .hljs-template-variable, .hljs-tag .hljs-attr { +.hljs-number, +.hljs-literal, +.hljs-variable, +.hljs-template-variable, +.hljs-tag .hljs-attr { color: #bd84bf; } -.hljs-string, .hljs-doctag { +.hljs-string, +.hljs-doctag { color: #8ab398; } @@ -867,16 +986,19 @@ input { border: 2px dashed #4c505c; } -.ui.basic.red.button, .ui.basic.red.buttons .button { +.ui.basic.red.button, +.ui.basic.red.buttons .button { box-shadow: 0 0 0 1px #a04141 inset !important; color: #a04141 !important; } -.ui.list .list > .item .header, .ui.list > .item .header { +.ui.list .list > .item .header, +.ui.list > .item .header { color: #dedede; } -.ui.list .list > .item .description, .ui.list > .item .description { +.ui.list .list > .item .description, +.ui.list > .item .description { color: #9e9e9e; } @@ -888,31 +1010,41 @@ input { background: #2e323e; } -.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, .repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { +.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, +.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { color: #7c9b5e; } -.ui.blue.button:focus, .ui.blue.buttons .button:focus { +.ui.blue.button:focus, +.ui.blue.buttons .button:focus { background-color: #87ab63; } -.ui.basic.blue.button:hover, .ui.basic.blue.buttons .button:hover { +.ui.basic.blue.button:hover, +.ui.basic.blue.buttons .button:hover { box-shadow: 0 0 0 1px #87ab63 inset !important; color: #87ab63 !important; } -.ui.basic.blue.button:focus, .ui.basic.blue.buttons .button:focus { +.ui.basic.blue.button:focus, +.ui.basic.blue.buttons .button:focus { box-shadow: 0 0 0 1px #87ab63 inset !important; color: #87ab63 !important; } -.repository.file.list #file-content .code-view .lines-num pre, .repository.file.list #file-content .code-view .lines-code pre, .repository.file.list #file-content .code-view .lines-num ol, .repository.file.list #file-content .code-view .lines-code ol, .repository.file.list #file-content .code-view .lines-num .hljs, .repository.file.list #file-content .code-view .lines-code .hljs { +.repository.file.list #file-content .code-view .lines-num pre, +.repository.file.list #file-content .code-view .lines-code pre, +.repository.file.list #file-content .code-view .lines-num ol, +.repository.file.list #file-content .code-view .lines-code ol, +.repository.file.list #file-content .code-view .lines-num .hljs, +.repository.file.list #file-content .code-view .lines-code .hljs { background-color: #2a2e3a; } -a.ui.label:hover, a.ui.labels .label:hover { +a.ui.label:hover, +a.ui.labels .label:hover { background-color: #505667; - color: rgb(219, 219, 219); + color: #dbdbdb; } .repository .label.list .item { @@ -923,43 +1055,62 @@ a.ui.label:hover, a.ui.labels .label:hover { background: #2e323e; } -.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, .repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { +.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, +.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { color: #7c9b5e; } -.ui.basic.blue.button, .ui.basic.blue.buttons .button { +.ui.basic.blue.button, +.ui.basic.blue.buttons .button { box-shadow: 0 0 0 1px #a27558 inset !important; color: #a27558 !important; } -.repository.file.list #file-content .code-view .lines-num pre, .repository.file.list #file-content .code-view .lines-code pre, .repository.file.list #file-content .code-view .lines-num ol, .repository.file.list #file-content .code-view .lines-code ol, .repository.file.list #file-content .code-view .lines-num .hljs, .repository.file.list #file-content .code-view .lines-code .hljs { - background-color: #2a2e3a; +.repository.file.list #file-content .code-view { + .lines-num pre, + .lines-code pre, + .lines-num ol, + .lines-code ol, + .lines-num .hljs, + .hljs { + background-color: #2a2e3a; + } } -a.ui.label:hover, a.ui.labels .label:hover { +a.ui.label:hover, +a.ui.labels .label:hover { background-color: #505667; - color: rgb(219, 219, 219); + color: #dbdbdb; } -.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4) { +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1), +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2), +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4) { background-color: #2a2e3a; } -.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4), .repository .diff-file-box .code-diff-split tbody tr td.add-code { +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3), +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4), +.repository .diff-file-box .code-diff-split tbody tr td.add-code { background-color: #283e2d !important; border-color: #314a37 !important; } -.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr td.del-code { +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1), +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2), +.repository .diff-file-box .code-diff-split tbody tr td.del-code { background-color: #3c2626 !important; border-color: #634343 !important; } -.ui.blue.button:focus, .ui.blue.buttons .button:focus { +.ui.blue.button:focus, +.ui.blue.buttons .button:focus { background-color: #a27558; } -.ui.blue.button:active, .ui.blue.buttons .button:active { +.ui.blue.button:active, +.ui.blue.buttons .button:active { background-color: #a27558; } @@ -993,7 +1144,8 @@ a.ui.label:hover, a.ui.labels .label:hover { background: #383c4a; } -.ui.basic.blue.button, .ui.basic.blue.buttons .button { +.ui.basic.blue.button, +.ui.basic.blue.buttons .button { box-shadow: 0 0 0 1px #87ab63 inset !important; color: #87ab63 !important; } @@ -1009,7 +1161,7 @@ a.ui.label:hover, a.ui.labels .label:hover { .CodeMirror { color: #9daccc; background-color: #2b2b2b; - border-top: none; + border-top: 0; } .CodeMirror-gutters { @@ -1027,7 +1179,7 @@ a.ui.label:hover, a.ui.labels .label:hover { .comment-code-cloud { .ui.attached.tabular.menu { background: none transparent; - border: none; + border: 0; } .footer .markdown-info { @@ -1036,7 +1188,7 @@ a.ui.label:hover, a.ui.labels .label:hover { } .file-comment { - color: #888; + color: #888888; } .ui.comments .comment { From 61238407453072f015cc747224468fca5a08bd76 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 May 2019 10:55:52 +0800 Subject: [PATCH 012/220] Remove macaron dependent on modules/log (#6933) --- modules/log/colors_router.go | 83 ++++++++++++++++++++++++++++ modules/log/router.go | 103 ----------------------------------- routers/routes/routes.go | 19 ++++++- 3 files changed, 101 insertions(+), 104 deletions(-) create mode 100644 modules/log/colors_router.go delete mode 100644 modules/log/router.go diff --git a/modules/log/colors_router.go b/modules/log/colors_router.go new file mode 100644 index 0000000000..e291a0da99 --- /dev/null +++ b/modules/log/colors_router.go @@ -0,0 +1,83 @@ +// Copyright 2019 The Gitea 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 log + +import ( + "time" +) + +var statusToColor = map[int][]byte{ + 100: ColorBytes(Bold), + 200: ColorBytes(FgGreen), + 300: ColorBytes(FgYellow), + 304: ColorBytes(FgCyan), + 400: ColorBytes(Bold, FgRed), + 401: ColorBytes(Bold, FgMagenta), + 403: ColorBytes(Bold, FgMagenta), + 500: ColorBytes(Bold, BgRed), +} + +// ColoredStatus addes colors for HTTP status +func ColoredStatus(status int, s ...string) *ColoredValue { + color, ok := statusToColor[status] + if !ok { + color, ok = statusToColor[(status/100)*100] + } + if !ok { + color = fgBoldBytes + } + if len(s) > 0 { + return NewColoredValueBytes(s[0], &color) + } + return NewColoredValueBytes(status, &color) +} + +var methodToColor = map[string][]byte{ + "GET": ColorBytes(FgBlue), + "POST": ColorBytes(FgGreen), + "DELETE": ColorBytes(FgRed), + "PATCH": ColorBytes(FgCyan), + "PUT": ColorBytes(FgYellow, Faint), + "HEAD": ColorBytes(FgBlue, Faint), +} + +// ColoredMethod addes colors for HtTP methos on log +func ColoredMethod(method string) *ColoredValue { + color, ok := methodToColor[method] + if !ok { + return NewColoredValueBytes(method, &fgBoldBytes) + } + return NewColoredValueBytes(method, &color) +} + +var ( + durations = []time.Duration{ + 10 * time.Millisecond, + 100 * time.Millisecond, + 1 * time.Second, + 5 * time.Second, + 10 * time.Second, + } + + durationColors = [][]byte{ + ColorBytes(FgGreen), + ColorBytes(Bold), + ColorBytes(FgYellow), + ColorBytes(FgRed, Bold), + ColorBytes(BgRed), + } + + wayTooLong = ColorBytes(BgMagenta) +) + +// ColoredTime addes colors for time on log +func ColoredTime(duration time.Duration) *ColoredValue { + for i, k := range durations { + if duration < k { + return NewColoredValueBytes(duration, &durationColors[i]) + } + } + return NewColoredValueBytes(duration, &wayTooLong) +} diff --git a/modules/log/router.go b/modules/log/router.go deleted file mode 100644 index 842202c781..0000000000 --- a/modules/log/router.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 The Gitea 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 log - -import ( - "net/http" - "time" - - macaron "gopkg.in/macaron.v1" -) - -var statusToColor = map[int][]byte{ - 100: ColorBytes(Bold), - 200: ColorBytes(FgGreen), - 300: ColorBytes(FgYellow), - 304: ColorBytes(FgCyan), - 400: ColorBytes(Bold, FgRed), - 401: ColorBytes(Bold, FgMagenta), - 403: ColorBytes(Bold, FgMagenta), - 500: ColorBytes(Bold, BgRed), -} - -func coloredStatus(status int, s ...string) *ColoredValue { - color, ok := statusToColor[status] - if !ok { - color, ok = statusToColor[(status/100)*100] - } - if !ok { - color = fgBoldBytes - } - if len(s) > 0 { - return NewColoredValueBytes(s[0], &color) - } - return NewColoredValueBytes(status, &color) -} - -var methodToColor = map[string][]byte{ - "GET": ColorBytes(FgBlue), - "POST": ColorBytes(FgGreen), - "DELETE": ColorBytes(FgRed), - "PATCH": ColorBytes(FgCyan), - "PUT": ColorBytes(FgYellow, Faint), - "HEAD": ColorBytes(FgBlue, Faint), -} - -func coloredMethod(method string) *ColoredValue { - color, ok := methodToColor[method] - if !ok { - return NewColoredValueBytes(method, &fgBoldBytes) - } - return NewColoredValueBytes(method, &color) -} - -var durations = []time.Duration{ - 10 * time.Millisecond, - 100 * time.Millisecond, - 1 * time.Second, - 5 * time.Second, - 10 * time.Second, -} - -var durationColors = [][]byte{ - ColorBytes(FgGreen), - ColorBytes(Bold), - ColorBytes(FgYellow), - ColorBytes(FgRed, Bold), - ColorBytes(BgRed), -} - -var wayTooLong = ColorBytes(BgMagenta) - -func coloredTime(duration time.Duration) *ColoredValue { - for i, k := range durations { - if duration < k { - return NewColoredValueBytes(duration, &durationColors[i]) - } - } - return NewColoredValueBytes(duration, &wayTooLong) -} - -// SetupRouterLogger will setup macaron to routing to the main gitea log -func SetupRouterLogger(m *macaron.Macaron, level Level) { - if GetLevel() <= level { - m.Use(RouterHandler(level)) - } -} - -// RouterHandler is a macaron handler that will log the routing to the default gitea log -func RouterHandler(level Level) func(ctx *macaron.Context) { - return func(ctx *macaron.Context) { - start := time.Now() - - GetLogger("router").Log(0, level, "Started %s %s for %s", coloredMethod(ctx.Req.Method), ctx.Req.RequestURI, ctx.RemoteAddr()) - - rw := ctx.Resp.(macaron.ResponseWriter) - ctx.Next() - - status := rw.Status() - GetLogger("router").Log(0, level, "Completed %s %s %v %s in %v", coloredMethod(ctx.Req.Method), ctx.Req.RequestURI, coloredStatus(status), coloredStatus(status, http.StatusText(rw.Status())), coloredTime(time.Since(start))) - } -} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 938afcab79..5a5fc518b9 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -94,6 +94,21 @@ func setupAccessLogger(m *macaron.Macaron) { }) } +// RouterHandler is a macaron handler that will log the routing to the default gitea log +func RouterHandler(level log.Level) func(ctx *macaron.Context) { + return func(ctx *macaron.Context) { + start := time.Now() + + log.GetLogger("router").Log(0, level, "Started %s %s for %s", log.ColoredMethod(ctx.Req.Method), ctx.Req.RequestURI, ctx.RemoteAddr()) + + rw := ctx.Resp.(macaron.ResponseWriter) + ctx.Next() + + status := rw.Status() + log.GetLogger("router").Log(0, level, "Completed %s %s %v %s in %v", log.ColoredMethod(ctx.Req.Method), ctx.Req.RequestURI, log.ColoredStatus(status), log.ColoredStatus(status, http.StatusText(rw.Status())), log.ColoredTime(time.Since(start))) + } +} + // NewMacaron initializes Macaron instance. func NewMacaron() *macaron.Macaron { gob.Register(&u2f.Challenge{}) @@ -102,7 +117,9 @@ func NewMacaron() *macaron.Macaron { loggerAsWriter := log.NewLoggerAsWriter("INFO", log.GetLogger("macaron")) m = macaron.NewWithLogger(loggerAsWriter) if !setting.DisableRouterLog && setting.RouterLogLevel != log.NONE { - log.SetupRouterLogger(m, setting.RouterLogLevel) + if log.GetLogger("router").GetLevel() <= setting.RouterLogLevel { + m.Use(RouterHandler(setting.RouterLogLevel)) + } } } else { m = macaron.New() From 0e057eb0336629652ae8e661b1bd497007730334 Mon Sep 17 00:00:00 2001 From: Xaver Maierhofer Date: Tue, 14 May 2019 06:11:22 +0200 Subject: [PATCH 013/220] Fix plain text overflow line wrap (#6915) --- public/css/index.css | 1 + public/less/_repository.less | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/public/css/index.css b/public/css/index.css index d53d4fb157..47e2519c5b 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -459,6 +459,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.file.list .non-diff-file-content .view-raw *{max-width:100%} .repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px} .repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em} +.repository.file.list .non-diff-file-content .plain-text pre{word-break:break-word;white-space:pre-wrap} .repository.file.list .non-diff-file-content pre{overflow:auto} .repository.file.list .non-diff-file-content .code-view *{font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px} .repository.file.list .non-diff-file-content .code-view table{width:100%} diff --git a/public/less/_repository.less b/public/less/_repository.less index f063d3b1a3..5970b366e2 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -393,6 +393,11 @@ .plain-text { padding: 1em 2em 1em 2em; + + pre { + word-break: break-word; + white-space: pre-wrap; + } } pre { From 8b36f01f453979d6b6ee14f9ac6e56fa6c7b035e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 May 2019 15:04:07 +0800 Subject: [PATCH 014/220] Move xorm logger bridge from log to models so that log module could be a standalone package (#6944) * move xorm logger bridge from log to models so that log module could be a standalone package * fix tests * save logger on xorm log bridge --- modules/log/xorm.go => models/log.go | 52 ++++++++++++---------------- models/models.go | 5 ++- modules/setting/log.go | 3 -- 3 files changed, 25 insertions(+), 35 deletions(-) rename modules/log/xorm.go => models/log.go (66%) diff --git a/modules/log/xorm.go b/models/log.go similarity index 66% rename from modules/log/xorm.go rename to models/log.go index c08b7fd7d5..4994545c5f 100644 --- a/modules/log/xorm.go +++ b/models/log.go @@ -2,11 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package log +package models import ( "fmt" + "code.gitea.io/gitea/modules/log" + "github.com/go-xorm/core" ) @@ -14,80 +16,72 @@ import ( type XORMLogBridge struct { showSQL bool level core.LogLevel + logger *log.Logger } -var ( - // XORMLogger the logger for xorm - XORMLogger *XORMLogBridge -) - -// InitXORMLogger inits a log bridge for xorm -func InitXORMLogger(showSQL bool) { - XORMLogger = &XORMLogBridge{ +// NewXORMLogger inits a log bridge for xorm +func NewXORMLogger(showSQL bool) core.ILogger { + return &XORMLogBridge{ showSQL: showSQL, + logger: log.GetLogger("xorm"), } } -// GetGiteaLevel returns the minimum Gitea logger level -func (l *XORMLogBridge) GetGiteaLevel() Level { - return GetLogger("xorm").GetLevel() -} - // Log a message with defined skip and at logging level -func (l *XORMLogBridge) Log(skip int, level Level, format string, v ...interface{}) error { - return GetLogger("xorm").Log(skip+1, level, format, v...) +func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...interface{}) error { + return l.logger.Log(skip+1, level, format, v...) } // Debug show debug log func (l *XORMLogBridge) Debug(v ...interface{}) { - l.Log(2, DEBUG, fmt.Sprint(v...)) + l.Log(2, log.DEBUG, fmt.Sprint(v...)) } // Debugf show debug log func (l *XORMLogBridge) Debugf(format string, v ...interface{}) { - l.Log(2, DEBUG, format, v...) + l.Log(2, log.DEBUG, format, v...) } // Error show error log func (l *XORMLogBridge) Error(v ...interface{}) { - l.Log(2, ERROR, fmt.Sprint(v...)) + l.Log(2, log.ERROR, fmt.Sprint(v...)) } // Errorf show error log func (l *XORMLogBridge) Errorf(format string, v ...interface{}) { - l.Log(2, ERROR, format, v...) + l.Log(2, log.ERROR, format, v...) } // Info show information level log func (l *XORMLogBridge) Info(v ...interface{}) { - l.Log(2, INFO, fmt.Sprint(v...)) + l.Log(2, log.INFO, fmt.Sprint(v...)) } // Infof show information level log func (l *XORMLogBridge) Infof(format string, v ...interface{}) { - l.Log(2, INFO, format, v...) + l.Log(2, log.INFO, format, v...) } // Warn show warning log func (l *XORMLogBridge) Warn(v ...interface{}) { - l.Log(2, WARN, fmt.Sprint(v...)) + l.Log(2, log.WARN, fmt.Sprint(v...)) } // Warnf show warnning log func (l *XORMLogBridge) Warnf(format string, v ...interface{}) { - l.Log(2, WARN, format, v...) + l.Log(2, log.WARN, format, v...) } // Level get logger level func (l *XORMLogBridge) Level() core.LogLevel { - switch l.GetGiteaLevel() { - case TRACE, DEBUG: + switch l.logger.GetLevel() { + case log.TRACE, log.DEBUG: return core.LOG_DEBUG - case INFO: + case log.INFO: return core.LOG_INFO - case WARN: + case log.WARN: return core.LOG_WARNING - case ERROR, CRITICAL: + case log.ERROR, log.CRITICAL: return core.LOG_ERR } return core.LOG_OFF diff --git a/models/models.go b/models/models.go index 352c07e0c3..c7e58737ed 100644 --- a/models/models.go +++ b/models/models.go @@ -15,7 +15,6 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" // Needed for the MySQL driver @@ -261,7 +260,7 @@ func NewTestEngine(x *xorm.Engine) (err error) { } x.SetMapper(core.GonicMapper{}) - x.SetLogger(log.XORMLogger) + x.SetLogger(NewXORMLogger(!setting.ProdMode)) x.ShowSQL(!setting.ProdMode) return x.StoreEngine("InnoDB").Sync2(tables...) } @@ -276,7 +275,7 @@ func SetEngine() (err error) { x.SetMapper(core.GonicMapper{}) // WARNING: for serv command, MUST remove the output to os.stdout, // so use log file to instead print to stdout. - x.SetLogger(log.XORMLogger) + x.SetLogger(NewXORMLogger(setting.LogSQL)) x.ShowSQL(setting.LogSQL) return nil } diff --git a/modules/setting/log.go b/modules/setting/log.go index cd2c5cc8c1..43a28309d2 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -295,8 +295,5 @@ func NewXORMLogService(disableConsole bool) { Cfg.Section("log").Key("XORM").MustString(",") generateNamedLogger("xorm", options) - log.InitXORMLogger(LogSQL) - } else { - log.InitXORMLogger(false) } } From 24a536d1450f6214dda8bc87645b4c8643e9e173 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 May 2019 21:52:18 +0800 Subject: [PATCH 015/220] Remove macaron dependent on models (#6940) --- models/login_source.go | 8 ++++++-- models/mail.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/models/login_source.go b/models/login_source.go index 69602b8b16..9b8173b84d 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -11,10 +11,10 @@ import ( "fmt" "net/smtp" "net/textproto" + "regexp" "strings" "github.com/Unknwon/com" - "github.com/go-macaron/binding" "github.com/go-xorm/core" "github.com/go-xorm/xorm" @@ -384,6 +384,10 @@ func composeFullName(firstname, surname, username string) string { } } +var ( + alphaDashDotPattern = regexp.MustCompile("[^\\w-\\.]") +) + // LoginViaLDAP queries if login/password is valid against the LDAP directory pool, // and create a local user if success when enabled. func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoRegister bool) (*User, error) { @@ -408,7 +412,7 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR sr.Username = login } // Validate username make sure it satisfies requirement. - if binding.AlphaDashDotPattern.MatchString(sr.Username) { + if alphaDashDotPattern.MatchString(sr.Username) { return nil, fmt.Errorf("Invalid pattern for attribute 'username' [%s]: must be valid alpha or numeric or dash(-_) or dot characters", sr.Username) } diff --git a/models/mail.go b/models/mail.go index b3e1e0d833..6be0df95ba 100644 --- a/models/mail.go +++ b/models/mail.go @@ -33,7 +33,7 @@ const ( var templates *template.Template -// InitMailRender initializes the macaron mail renderer +// InitMailRender initializes the mail renderer func InitMailRender(tmpls *template.Template) { templates = tmpls } From 488d34691ad79bae13320f3e831a7ff46c245a89 Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Tue, 14 May 2019 07:40:27 -0700 Subject: [PATCH 016/220] Ignore non-standard refs in git push (#6758) When replicating to gitea from a remote system which makes use of git refs to store extra data (for example, gerrit), pushing a lot of refs to gitea can cause problems due to the extra processing that the pre and post receive hooks perform. But it's still useful for gitea to be able to serve those refs. This change skips unecessary processing of refs other than branches or tags. We don't need to check any ref that isn't a branch for branch protection (protection will never be enabled). So in the pre-receive hook, we wrap that check in a test for whether the ref is a branch. We also don't need to add information to the activity stream about pushes to non-standard refs, so we skip that step in the post-receive hook for refs which are not branches or tags. For some concrete examples, gerrit maintains a ref for every patchset of every change in the form refs/changes/XX/YYYY/Z. Many systems use refs/notes to store additonal data about commits. This change allows these and other schemes to be used without affecting gitea. --- cmd/hook.go | 83 +++++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/cmd/hook.go b/cmd/hook.go index 46f97d5542..f8bd34c4e9 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -89,34 +89,37 @@ func runHookPreReceive(c *cli.Context) error { newCommitID := string(fields[1]) refFullName := string(fields[2]) - branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) - protectBranch, err := private.GetProtectedBranchBy(repoID, branchName) - if err != nil { - fail("Internal error", fmt.Sprintf("retrieve protected branches information failed: %v", err)) - } - - if protectBranch != nil && protectBranch.IsProtected() { - // check and deletion - if newCommitID == git.EmptySHA { - fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "") - } - - // detect force push - if git.EmptySHA != oldCommitID { - output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath) - if err != nil { - fail("Internal error", "Fail to detect force push: %v", err) - } else if len(output) > 0 { - fail(fmt.Sprintf("branch %s is protected from force push", branchName), "") - } - } - - userID, _ := strconv.ParseInt(userIDStr, 10, 64) - canPush, err := private.CanUserPush(protectBranch.ID, userID) + // If the ref is a branch, check if it's protected + if strings.HasPrefix(refFullName, git.BranchPrefix) { + branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) + protectBranch, err := private.GetProtectedBranchBy(repoID, branchName) if err != nil { - fail("Internal error", "Fail to detect user can push: %v", err) - } else if !canPush { - fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "") + fail("Internal error", fmt.Sprintf("retrieve protected branches information failed: %v", err)) + } + + if protectBranch != nil && protectBranch.IsProtected() { + // check and deletion + if newCommitID == git.EmptySHA { + fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "") + } + + // detect force push + if git.EmptySHA != oldCommitID { + output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath) + if err != nil { + fail("Internal error", "Fail to detect force push: %v", err) + } else if len(output) > 0 { + fail(fmt.Sprintf("branch %s is protected from force push", branchName), "") + } + } + + userID, _ := strconv.ParseInt(userIDStr, 10, 64) + canPush, err := private.CanUserPush(protectBranch.ID, userID) + if err != nil { + fail("Internal error", "Fail to detect user can push: %v", err) + } else if !canPush { + fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "") + } } } } @@ -169,16 +172,22 @@ func runHookPostReceive(c *cli.Context) error { newCommitID := string(fields[1]) refFullName := string(fields[2]) - if err := private.PushUpdate(models.PushUpdateOptions{ - RefFullName: refFullName, - OldCommitID: oldCommitID, - NewCommitID: newCommitID, - PusherID: pusherID, - PusherName: pusherName, - RepoUserName: repoUser, - RepoName: repoName, - }); err != nil { - log.GitLogger.Error("Update: %v", err) + // Only trigger activity updates for changes to branches or + // tags. Updates to other refs (eg, refs/notes, refs/changes, + // or other less-standard refs spaces are ignored since there + // may be a very large number of them). + if strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) { + if err := private.PushUpdate(models.PushUpdateOptions{ + RefFullName: refFullName, + OldCommitID: oldCommitID, + NewCommitID: newCommitID, + PusherID: pusherID, + PusherName: pusherName, + RepoUserName: repoUser, + RepoName: repoName, + }); err != nil { + log.GitLogger.Error("Update: %v", err) + } } if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) { From e55c874dd2a6162a374a9fac46c55db57bd17c5f Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 14 May 2019 16:20:35 +0100 Subject: [PATCH 017/220] Add work path CLI option (#6922) Makes it possible to set the work path as a CLI option instead of relying on environment variables which are somewhat opaque --- contrib/pr/checkout.go | 2 +- docs/content/doc/usage/command-line.en-us.md | 8 ++++++-- integrations/integration_test.go | 2 +- main.go | 15 ++++++++++++--- models/ssh_key_test.go | 2 +- modules/setting/setting.go | 5 ++++- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 607a503189..7af27c2a9e 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -43,7 +43,7 @@ func runPR() { if err != nil { log.Fatal(err) } - setting.SetCustomPathAndConf("", "") + setting.SetCustomPathAndConf("", "", "") setting.NewContext() setting.RepoRootPath, err = ioutil.TempDir(os.TempDir(), "repos") diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index 9959ac30ab..ab52109e93 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -25,8 +25,12 @@ All global options can be placed at the command level. - `--help`, `-h`: Show help text and exit. Optional. - `--version`, `-v`: Show version and exit. Optional. (example: `Gitea version 1.1.0+218-g7b907ed built with: bindata, sqlite`). -- `--custom-path path`, `-C path`: Location of the Gitea custom folder. Optional. (default: $PWD/custom). -- `--config path`, `-c path`: Gitea configuration file path. Optional. (default: custom/conf/app.ini). +- `--custom-path path`, `-C path`: Location of the Gitea custom folder. Optional. (default: `AppWorkPath`/custom or `$GITEA_CUSTOM`). +- `--config path`, `-c path`: Gitea configuration file path. Optional. (default: `custom`/conf/app.ini). +- `--work-path path`, `-w path`: Gitea `AppWorkPath`. Optional. (default: LOCATION_OF_GITEA_BINARY or `$GITEA_WORK_DIR`) + +NB: The defaults custom-path, config and work-path can also be +changed at build time (if preferred). ### Commands diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 93dacaf78a..80a42efb5c 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -118,7 +118,7 @@ func initIntegrationTest() { setting.CustomConf = giteaConf } - setting.SetCustomPathAndConf("", "") + setting.SetCustomPathAndConf("", "", "") setting.NewContext() setting.CheckLFSVersion() models.LoadConfigs() diff --git a/main.go b/main.go index 102450f906..4d94d00aba 100644 --- a/main.go +++ b/main.go @@ -68,7 +68,7 @@ arguments - which can alternatively be run by running the subcommand web.` // Now adjust these commands to add our global configuration options // First calculate the default paths and set the AppHelpTemplates in this context - setting.SetCustomPathAndConf("", "") + setting.SetCustomPathAndConf("", "", "") setAppHelpTemplates() // default configuration flags @@ -84,6 +84,11 @@ arguments - which can alternatively be run by running the subcommand web.` Usage: "Custom configuration file path", }, cli.VersionFlag, + cli.StringFlag{ + Name: "work-path, w", + Value: setting.AppWorkPath, + Usage: "Set the gitea working path", + }, } // Set the default to be equivalent to cmdWeb and add the default flags @@ -114,10 +119,11 @@ func setFlagsAndBeforeOnSubcommands(command *cli.Command, defaultFlags []cli.Fla func establishCustomPath(ctx *cli.Context) error { var providedCustom string var providedConf string + var providedWorkPath string currentCtx := ctx for { - if len(providedCustom) != 0 && len(providedConf) != 0 { + if len(providedCustom) != 0 && len(providedConf) != 0 && len(providedWorkPath) != 0 { break } if currentCtx == nil { @@ -129,10 +135,13 @@ func establishCustomPath(ctx *cli.Context) error { if currentCtx.IsSet("config") && len(providedConf) == 0 { providedConf = currentCtx.String("config") } + if currentCtx.IsSet("work-path") && len(providedWorkPath) == 0 { + providedWorkPath = currentCtx.String("work-path") + } currentCtx = currentCtx.Parent() } - setting.SetCustomPathAndConf(providedCustom, providedConf) + setting.SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath) setAppHelpTemplates() diff --git a/models/ssh_key_test.go b/models/ssh_key_test.go index f310935a32..82f5f9724b 100644 --- a/models/ssh_key_test.go +++ b/models/ssh_key_test.go @@ -14,7 +14,7 @@ import ( ) func init() { - setting.SetCustomPathAndConf("", "") + setting.SetCustomPathAndConf("", "", "") setting.NewContext() } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index d7f361c01e..461e394a62 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -479,7 +479,10 @@ func CheckLFSVersion() { // SetCustomPathAndConf will set CustomPath and CustomConf with reference to the // GITEA_CUSTOM environment variable and with provided overrides before stepping // back to the default -func SetCustomPathAndConf(providedCustom, providedConf string) { +func SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath string) { + if len(providedWorkPath) != 0 { + AppWorkPath = filepath.ToSlash(providedWorkPath) + } if giteaCustom, ok := os.LookupEnv("GITEA_CUSTOM"); ok { CustomPath = giteaCustom } From 95d3d42c5fd51bcc64774841edad158f6e5ef60f Mon Sep 17 00:00:00 2001 From: Xaver Maierhofer Date: Tue, 14 May 2019 18:02:59 +0200 Subject: [PATCH 018/220] Fix code overflow (#6914) --- public/css/index.css | 1 + public/less/_admin.less | 6 ++++++ templates/admin/config.tmpl | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/public/css/index.css b/public/css/index.css index 47e2519c5b..fa449ec69f 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -942,6 +942,7 @@ tbody.commit-list{vertical-align:baseline} .admin dl.admin-dl-horizontal dd{margin-left:275px} .admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .admin.config #test-mail-btn{margin-left:5px} +.admin code,.admin pre{white-space:pre-wrap;word-wrap:break-word} .explore{padding-top:15px} .explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#fafafa!important;border-width:1px!important} .explore .navbar .octicon{width:16px;text-align:center;margin-right:5px} diff --git a/public/less/_admin.less b/public/less/_admin.less index af68a43dbd..0bd685142a 100644 --- a/public/less/_admin.less +++ b/public/less/_admin.less @@ -65,4 +65,10 @@ margin-left: 5px; } } + + code, + pre { + white-space: pre-wrap; + word-wrap: break-word; + } } diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index b4fcb4d610..7a81eb2668 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -254,7 +254,7 @@
    {{.i18n.Tr "admin.config.session_provider"}}
    {{.SessionConfig.Provider}}
    {{.i18n.Tr "admin.config.provider_config"}}
    -
    {{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig}}{{else}}-{{end}}
    +
    {{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig  | JsonPrettyPrint}}{{else}}-{{end}}
    {{.i18n.Tr "admin.config.cookie_name"}}
    {{.SessionConfig.CookieName}}
    {{.i18n.Tr "admin.config.gc_interval_time"}}
    From 710245e81e0d65c72231dbb3b5c9f860cdc71899 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 15 May 2019 09:57:00 +0800 Subject: [PATCH 019/220] Refactor models.NewRepoContext to extract git related codes to modules/git (#6941) * refactor models.NewRepoContext to extract git related codes to modules/git * fix imports * refactor --- models/repo.go | 47 +++----------------------------------- modules/git/git.go | 26 +++++++++++++++++++-- modules/setting/git.go | 3 ++- modules/setting/setting.go | 3 +++ routers/admin/admin.go | 3 ++- routers/init.go | 1 - 6 files changed, 34 insertions(+), 49 deletions(-) diff --git a/models/repo.go b/models/repo.go index 2f87e2f514..b37120236f 100644 --- a/models/repo.go +++ b/models/repo.go @@ -13,7 +13,6 @@ import ( "io/ioutil" "net/url" "os" - "os/exec" "path" "path/filepath" "regexp" @@ -32,11 +31,9 @@ import ( "code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/util" - "github.com/Unknwon/cae/zip" "github.com/Unknwon/com" "github.com/go-xorm/builder" "github.com/go-xorm/xorm" - version "github.com/mcuadros/go-version" ini "gopkg.in/ini.v1" ) @@ -67,8 +64,8 @@ var ( ItemsPerPage = 40 ) -// LoadRepoConfig loads the repository config -func LoadRepoConfig() { +// loadRepoConfig loads the repository config +func loadRepoConfig() { // Load .gitignore and license files and readme templates. types := []string{"gitignore", "license", "readme", "label"} typeFiles := make([][]string, 4) @@ -119,45 +116,7 @@ func LoadRepoConfig() { // NewRepoContext creates a new repository context func NewRepoContext() { - zip.Verbose = false - - // Check Git installation. - if _, err := exec.LookPath("git"); err != nil { - log.Fatal("Failed to test 'git' command: %v (forgotten install?)", err) - } - - // Check Git version. - var err error - setting.Git.Version, err = git.BinVersion() - if err != nil { - log.Fatal("Failed to get Git version: %v", err) - } - - log.Info("Git Version: %s", setting.Git.Version) - if version.Compare("1.7.1", setting.Git.Version, ">") { - log.Fatal("Gitea requires Git version greater or equal to 1.7.1") - } - - // Git requires setting user.name and user.email in order to commit changes. - for configKey, defaultValue := range map[string]string{"user.name": "Gitea", "user.email": "gitea@fake.local"} { - if stdout, stderr, err := process.GetManager().Exec("NewRepoContext(get setting)", "git", "config", "--get", configKey); err != nil || strings.TrimSpace(stdout) == "" { - // ExitError indicates this config is not set - if _, ok := err.(*exec.ExitError); ok || strings.TrimSpace(stdout) == "" { - if _, stderr, gerr := process.GetManager().Exec("NewRepoContext(set "+configKey+")", "git", "config", "--global", configKey, defaultValue); gerr != nil { - log.Fatal("Failed to set git %s(%s): %s", configKey, gerr, stderr) - } - log.Info("Git config %s set to %s", configKey, defaultValue) - } else { - log.Fatal("Failed to get git %s(%s): %s", configKey, err, stderr) - } - } - } - - // Set git some configurations. - if _, stderr, err := process.GetManager().Exec("NewRepoContext(git config --global core.quotepath false)", - "git", "config", "--global", "core.quotepath", "false"); err != nil { - log.Fatal("Failed to execute 'git config --global core.quotepath false': %s", stderr) - } + loadRepoConfig() RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) } diff --git a/modules/git/git.go b/modules/git/git.go index abae0423c2..632af539cc 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -11,6 +11,8 @@ import ( "strings" "time" + "code.gitea.io/gitea/modules/process" + "github.com/mcuadros/go-version" ) @@ -31,6 +33,8 @@ var ( // GitExecutable is the command name of git // Could be updated to an absolute path while initialization GitExecutable = "git" + + gitVersion string ) func log(format string, args ...interface{}) { @@ -46,8 +50,6 @@ func log(format string, args ...interface{}) { } } -var gitVersion string - // BinVersion returns current Git version from shell. func BinVersion() (string, error) { if len(gitVersion) > 0 { @@ -89,6 +91,26 @@ func init() { if version.Compare(gitVersion, GitVersionRequired, "<") { panic(fmt.Sprintf("Git version not supported. Requires version > %v", GitVersionRequired)) } + + // Git requires setting user.name and user.email in order to commit changes. + for configKey, defaultValue := range map[string]string{"user.name": "Gitea", "user.email": "gitea@fake.local"} { + if stdout, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", configKey); err != nil || strings.TrimSpace(stdout) == "" { + // ExitError indicates this config is not set + if _, ok := err.(*exec.ExitError); ok || strings.TrimSpace(stdout) == "" { + if _, stderr, gerr := process.GetManager().Exec("git.Init(set "+configKey+")", "git", "config", "--global", configKey, defaultValue); gerr != nil { + panic(fmt.Sprintf("Failed to set git %s(%s): %s", configKey, gerr, stderr)) + } + } else { + panic(fmt.Sprintf("Failed to get git %s(%s): %s", configKey, err, stderr)) + } + } + } + + // Set git some configurations. + if _, stderr, err := process.GetManager().Exec("git.Init(git config --global core.quotepath false)", + GitExecutable, "config", "--global", "core.quotepath", "false"); err != nil { + panic(fmt.Sprintf("Failed to execute 'git config --global core.quotepath false': %s", stderr)) + } } // Fsck verifies the connectivity and validity of the objects in the database diff --git a/modules/setting/git.go b/modules/setting/git.go index 0ad16fc81e..8625c0e780 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -16,7 +16,6 @@ import ( var ( // Git settings Git = struct { - Version string `ini:"-"` DisableDiffHighlight bool MaxGitDiffLines int MaxGitDiffLineCharacters int @@ -65,6 +64,8 @@ func newGit() { log.Fatal("Error retrieving git version: %v", err) } + log.Info("Git Version: %s", binVersion) + if version.Compare(binVersion, "2.9", ">=") { // Explicitly disable credential helper, otherwise Git credentials might leak git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=") diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 461e394a62..de89c67d04 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -27,6 +27,7 @@ import ( _ "code.gitea.io/gitea/modules/minwinsvc" // import minwinsvc for windows services "code.gitea.io/gitea/modules/user" + "github.com/Unknwon/cae/zip" "github.com/Unknwon/com" _ "github.com/go-macaron/cache/memcache" // memcache plugin for cache _ "github.com/go-macaron/cache/redis" @@ -931,6 +932,8 @@ func NewContext() { sec = Cfg.Section("U2F") U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimRight(AppURL, "/"))) U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimRight(AppURL, "/")) + + zip.Verbose = false } func loadInternalToken(sec *ini.Section) string { diff --git a/routers/admin/admin.go b/routers/admin/admin.go index 7b8422fc61..0e6fa2c242 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/cron" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" ) @@ -210,7 +211,7 @@ func Config(ctx *context.Context) { ctx.Data["DisableRouterLog"] = setting.DisableRouterLog ctx.Data["RunUser"] = setting.RunUser ctx.Data["RunMode"] = strings.Title(macaron.Env) - ctx.Data["GitVersion"] = setting.Git.Version + ctx.Data["GitVersion"], _ = git.BinVersion() ctx.Data["RepoRootPath"] = setting.RepoRootPath ctx.Data["CustomRootPath"] = setting.CustomPath ctx.Data["StaticRootPath"] = setting.StaticRootPath diff --git a/routers/init.go b/routers/init.go index 47f837c523..88422cc6ed 100644 --- a/routers/init.go +++ b/routers/init.go @@ -86,7 +86,6 @@ func GlobalInit() { log.Fatal("Failed to initialize OAuth2 support: %v", err) } - models.LoadRepoConfig() models.NewRepoContext() // Booting long running goroutines. From 5fb1ad70113d3272232c266b4ff58e9f7f646594 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Wed, 15 May 2019 08:01:53 -0400 Subject: [PATCH 020/220] Webhook Logs show proper HTTP Method, and allow change HTTP method in form (#6953) * Fix #6951 - logs show proper HTTP Method, and allow change HTTP method in form * enforce POST method for webhook * set default if method is empty --- models/webhook.go | 25 ++++++++++++-------- routers/api/v1/utils/hook.go | 1 + routers/repo/webhook.go | 1 + templates/repo/settings/webhook/history.tmpl | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/models/webhook.go b/models/webhook.go index 51b91879ee..48c4de2ea3 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -755,17 +755,15 @@ func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payl func (t *HookTask) deliver() { t.IsDelivered = true - t.RequestInfo = &HookRequest{ - Headers: map[string]string{}, - } - t.ResponseInfo = &HookResponse{ - Headers: map[string]string{}, - } timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second var req *httplib.Request - if t.HTTPMethod == http.MethodPost { + switch t.HTTPMethod { + case "": + log.Info("HTTP Method for webhook %d empty, setting to POST as default", t.ID) + fallthrough + case http.MethodPost: req = httplib.Post(t.URL) switch t.ContentType { case ContentTypeJSON: @@ -773,10 +771,10 @@ func (t *HookTask) deliver() { case ContentTypeForm: req.Param("payload", t.PayloadContent) } - } else if t.HTTPMethod == http.MethodGet { + case http.MethodGet: req = httplib.Get(t.URL).Param("payload", t.PayloadContent) - } else { - t.ResponseInfo.Body = fmt.Sprintf("Invalid http method: %v", t.HTTPMethod) + default: + log.Error("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod) return } @@ -792,10 +790,17 @@ func (t *HookTask) deliver() { SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}) // Record delivery information. + t.RequestInfo = &HookRequest{ + Headers: map[string]string{}, + } for k, vals := range req.Headers() { t.RequestInfo.Headers[k] = strings.Join(vals, ",") } + t.ResponseInfo = &HookResponse{ + Headers: map[string]string{}, + } + defer func() { t.Delivered = time.Now().UnixNano() if t.IsSucceed { diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index da15850ec5..92846c5f2a 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -98,6 +98,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID URL: form.Config["url"], ContentType: models.ToHookContentType(form.Config["content_type"]), Secret: form.Config["secret"], + HTTPMethod: "POST", HookEvent: &models.HookEvent{ ChooseEvents: true, HookEvents: models.HookEvents{ diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index 7695f208ce..8daf721b50 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -564,6 +564,7 @@ func WebHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) { w.Secret = form.Secret w.HookEvent = ParseHookEvent(form.WebhookForm) w.IsActive = form.Active + w.HTTPMethod = form.HTTPMethod if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) return diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl index 7f85c702b5..577f357720 100644 --- a/templates/repo/settings/webhook/history.tmpl +++ b/templates/repo/settings/webhook/history.tmpl @@ -45,7 +45,7 @@ {{if .RequestInfo}}
    {{$.i18n.Tr "repo.settings.webhook.headers"}}
    Request URL: {{.URL}}
    -Request method: POST
    +Request method: {{if .HTTPMethod}}{{.HTTPMethod}}{{else}}POST{{end}}
     {{ range $key, $val := .RequestInfo.Headers }}{{$key}}: {{$val}}
     {{end}}
    {{$.i18n.Tr "repo.settings.webhook.payload"}}
    From 56ae539bed7d822980ebaae8db316a0177fc028c Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 15 May 2019 16:24:39 +0100 Subject: [PATCH 021/220] SearchRepositoryByName improvements and unification (#6897) --- integrations/api_repo_test.go | 48 ++++++----- models/repo_list.go | 142 +++++++++++++++++---------------- models/repo_list_test.go | 8 +- routers/api/v1/repo/repo.go | 49 +++--------- routers/user/home.go | 58 ++++---------- routers/user/profile.go | 96 ++++++++-------------- templates/swagger/v1_json.tmpl | 13 +++ 7 files changed, 179 insertions(+), 235 deletions(-) diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index d03ddcb353..8dedfd1ae0 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -69,40 +69,41 @@ func TestAPISearchRepo(t *testing.T) { name, requestURL string expectedResults }{ - {name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{ + {name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{ nil: {count: 21}, user: {count: 21}, user2: {count: 21}}, }, - {name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{ + {name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10&private=false", expectedResults: expectedResults{ nil: {count: 10}, user: {count: 10}, user2: {count: 10}}, }, - {name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default", expectedResults: expectedResults{ + {name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default&private=false", expectedResults: expectedResults{ nil: {count: 10}, user: {count: 10}, user2: {count: 10}}, }, - {name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s", "big_test_"), expectedResults: expectedResults{ + {name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s&private=false", "big_test_"), expectedResults: expectedResults{ nil: {count: 7, repoName: "big_test_"}, user: {count: 7, repoName: "big_test_"}, user2: {count: 7, repoName: "big_test_"}}, }, {name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{ - nil: {count: 4}, - user: {count: 8, includesPrivate: true}, - user2: {count: 4}}, + nil: {count: 5}, + user: {count: 9, includesPrivate: true}, + user2: {count: 5, includesPrivate: true}}, }, {name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{ nil: {count: 1}, - user: {count: 1}, - user2: {count: 2, includesPrivate: true}}, + user: {count: 2, includesPrivate: true}, + user2: {count: 2, includesPrivate: true}, + user4: {count: 1}}, }, {name: "RepositoriesAccessibleAndRelatedToUser3", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user3.ID), expectedResults: expectedResults{ nil: {count: 1}, - user: {count: 1}, - user2: {count: 1}, + user: {count: 4, includesPrivate: true}, + user2: {count: 2, includesPrivate: true}, user3: {count: 4, includesPrivate: true}}, }, {name: "RepositoriesOwnedByOrganization", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", orgUser.ID), expectedResults: expectedResults{ @@ -112,12 +113,12 @@ func TestAPISearchRepo(t *testing.T) { }, {name: "RepositoriesAccessibleAndRelatedToUser4", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user4.ID), expectedResults: expectedResults{ nil: {count: 3}, - user: {count: 3}, - user4: {count: 6, includesPrivate: true}}}, + user: {count: 4, includesPrivate: true}, + user4: {count: 7, includesPrivate: true}}}, {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeSource", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "source"), expectedResults: expectedResults{ nil: {count: 0}, - user: {count: 0}, - user4: {count: 0, includesPrivate: true}}}, + user: {count: 1, includesPrivate: true}, + user4: {count: 1, includesPrivate: true}}}, {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "fork"), expectedResults: expectedResults{ nil: {count: 1}, user: {count: 1}, @@ -136,8 +137,8 @@ func TestAPISearchRepo(t *testing.T) { user4: {count: 2, includesPrivate: true}}}, {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{ nil: {count: 0}, - user: {count: 0}, - user4: {count: 0, includesPrivate: true}}}, + user: {count: 1, includesPrivate: true}, + user4: {count: 1, includesPrivate: true}}}, } for _, testCase := range testCases { @@ -164,14 +165,19 @@ func TestAPISearchRepo(t *testing.T) { var body api.SearchResults DecodeJSON(t, response, &body) - assert.Len(t, body.Data, expected.count) + repoNames := make([]string, 0, len(body.Data)) + for _, repo := range body.Data { + repoNames = append(repoNames, fmt.Sprintf("%d:%s:%t", repo.ID, repo.FullName, repo.Private)) + } + assert.Len(t, repoNames, expected.count) for _, repo := range body.Data { r := getRepo(t, repo.ID) hasAccess, err := models.HasAccess(userID, r) - assert.NoError(t, err) - assert.True(t, hasAccess) + assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err) + assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName) assert.NotEmpty(t, repo.Name) + assert.Equal(t, repo.Name, r.Name) if len(expected.repoName) > 0 { assert.Contains(t, repo.Name, expected.repoName) @@ -182,7 +188,7 @@ func TestAPISearchRepo(t *testing.T) { } if !expected.includesPrivate { - assert.False(t, repo.Private) + assert.False(t, repo.Private, "User: %d not expecting private repository: %s", userID, repo.FullName) } } }) diff --git a/models/repo_list.go b/models/repo_list.go index 83d2665e8c..9686676eae 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/go-xorm/builder" - "github.com/go-xorm/core" ) // RepositoryListDefaultPageSize is the default number of repositories @@ -112,15 +111,17 @@ func (repos MirrorRepositoryList) LoadAttributes() error { // SearchRepoOptions holds the search options type SearchRepoOptions struct { - Keyword string - OwnerID int64 - OrderBy SearchOrderBy - Private bool // Include private repositories in results - Starred bool - Page int - IsProfile bool - AllPublic bool // Include also all public repositories - PageSize int // Can be smaller than or equal to setting.ExplorePagingNum + UserID int64 + UserIsAdmin bool + Keyword string + OwnerID int64 + OrderBy SearchOrderBy + Private bool // Include private repositories in results + StarredByID int64 + Page int + IsProfile bool + AllPublic bool // Include also all public repositories + PageSize int // Can be smaller than or equal to setting.ExplorePagingNum // None -> include collaborative AND non-collaborative // True -> include just collaborative // False -> incude just non-collaborative @@ -168,72 +169,79 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err if opts.Page <= 0 { opts.Page = 1 } - var cond = builder.NewCond() - if !opts.Private { + if opts.Private { + if !opts.UserIsAdmin && opts.UserID != 0 && opts.UserID != opts.OwnerID { + // OK we're in the context of a User + // We should be Either + cond = cond.And(builder.Or( + // 1. Be able to see all non-private repositories that either: + cond.And( + builder.Eq{"is_private": false}, + builder.Or( + // A. Aren't in organisations __OR__ + builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})), + // B. Isn't a private organisation. (Limited is OK because we're logged in) + builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"visibility": structs.VisibleTypePrivate}))), + ), + // 2. Be able to see all repositories that we have access to + builder.In("id", builder.Select("repo_id"). + From("`access`"). + Where(builder.And( + builder.Eq{"user_id": opts.UserID}, + builder.Gt{"mode": int(AccessModeNone)}))), + // 3. Be able to see all repositories that we are in a team + builder.In("id", builder.Select("`team_repo`.repo_id"). + From("team_repo"). + Where(builder.Eq{"`team_user`.uid": opts.UserID}). + Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id")))) + } + } else { + // Not looking at private organisations + // We should be able to see all non-private repositories that either: cond = cond.And(builder.Eq{"is_private": false}) accessCond := builder.Or( - builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), - builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization}))) + // A. Aren't in organisations __OR__ + builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})), + // B. Isn't a private or limited organisation. + builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate})))) cond = cond.And(accessCond) } + // Restrict to starred repositories + if opts.StarredByID > 0 { + cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID}))) + } + + // Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate if opts.OwnerID > 0 { - if opts.Starred { - cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.OwnerID}))) - } else { - var accessCond = builder.NewCond() - if opts.Collaborate != util.OptionalBoolTrue { - accessCond = builder.Eq{"owner_id": opts.OwnerID} - } - - if opts.Collaborate != util.OptionalBoolFalse { - collaborateCond := builder.And( - builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID), - builder.Neq{"owner_id": opts.OwnerID}) - if !opts.Private { - collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false)) - } - - accessCond = accessCond.Or(collaborateCond) - } - - var exprCond builder.Cond - if DbCfg.Type == core.POSTGRES { - exprCond = builder.Expr("org_user.org_id = \"user\".id") - } else if DbCfg.Type == core.MSSQL { - exprCond = builder.Expr("org_user.org_id = [user].id") - } else { - exprCond = builder.Eq{"org_user.org_id": "user.id"} - } - - visibilityCond := builder.Or( - builder.In("owner_id", - builder.Select("org_id").From("org_user"). - LeftJoin("`user`", exprCond). - Where( - builder.And( - builder.Eq{"uid": opts.OwnerID}, - builder.Eq{"visibility": structs.VisibleTypePrivate})), - ), - builder.In("owner_id", - builder.Select("id").From("`user`"). - Where( - builder.Or( - builder.Eq{"visibility": structs.VisibleTypePublic}, - builder.Eq{"visibility": structs.VisibleTypeLimited})), - ), - builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})), - ) - cond = cond.And(visibilityCond) - - if opts.AllPublic { - accessCond = accessCond.Or(builder.Eq{"is_private": false}) - } - - cond = cond.And(accessCond) + var accessCond = builder.NewCond() + if opts.Collaborate != util.OptionalBoolTrue { + accessCond = builder.Eq{"owner_id": opts.OwnerID} } + + if opts.Collaborate != util.OptionalBoolFalse { + collaborateCond := builder.And( + builder.Or( + builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID), + builder.In("id", builder.Select("`team_repo`.repo_id"). + From("team_repo"). + Where(builder.Eq{"`team_user`.uid": opts.OwnerID}). + Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))), + builder.Neq{"owner_id": opts.OwnerID}) + if !opts.Private { + collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false)) + } + + accessCond = accessCond.Or(collaborateCond) + } + + if opts.AllPublic { + accessCond = accessCond.Or(builder.Eq{"is_private": false}) + } + + cond = cond.And(accessCond) } if opts.Keyword != "" { diff --git a/models/repo_list_test.go b/models/repo_list_test.go index e871c612f0..645de2a59a 100644 --- a/models/repo_list_test.go +++ b/models/repo_list_test.go @@ -117,7 +117,7 @@ func TestSearchRepositoryByName(t *testing.T) { count: 4}, {name: "PublicRepositoriesOfUserIncludingCollaborative", opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15}, - count: 4}, + count: 5}, {name: "PublicRepositoriesOfUser2IncludingCollaborative", opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18}, count: 1}, @@ -126,13 +126,13 @@ func TestSearchRepositoryByName(t *testing.T) { count: 3}, {name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative", opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true}, - count: 8}, + count: 9}, {name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative", opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true}, count: 4}, {name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative", opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true}, - count: 6}, + count: 7}, {name: "PublicRepositoriesOfOrganization", opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, count: 1}, @@ -150,7 +150,7 @@ func TestSearchRepositoryByName(t *testing.T) { count: 21}, {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true}, - count: 26}, + count: 27}, {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName", opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true}, count: 15}, diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 56aac8014c..62153893a6 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -56,6 +56,15 @@ func Search(ctx *context.APIContext) { // description: search only for repos that the user with the given id owns or contributes to // type: integer // format: int64 + // - name: starredBy + // in: query + // description: search only for repos that the user with the given id has starred + // type: integer + // format: int64 + // - name: private + // in: query + // description: include private repositories this user has access to (defaults to true) + // type: boolean // - name: page // in: query // description: page number of results to return (1-based) @@ -96,6 +105,10 @@ func Search(ctx *context.APIContext) { PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")), TopicOnly: ctx.QueryBool("topic"), Collaborate: util.OptionalBoolNone, + Private: ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")), + UserIsAdmin: ctx.IsUserSiteAdmin(), + UserID: ctx.Data["SignedUserID"].(int64), + StarredByID: ctx.QueryInt64("starredBy"), } if ctx.QueryBool("exclusive") { @@ -140,42 +153,6 @@ func Search(ctx *context.APIContext) { } var err error - if opts.OwnerID > 0 { - var repoOwner *models.User - if ctx.User != nil && ctx.User.ID == opts.OwnerID { - repoOwner = ctx.User - } else { - repoOwner, err = models.GetUserByID(opts.OwnerID) - if err != nil { - ctx.JSON(500, api.SearchError{ - OK: false, - Error: err.Error(), - }) - return - } - } - - if repoOwner.IsOrganization() { - opts.Collaborate = util.OptionalBoolFalse - } - - // Check visibility. - if ctx.IsSigned { - if ctx.User.ID == repoOwner.ID { - opts.Private = true - } else if repoOwner.IsOrganization() { - opts.Private, err = repoOwner.IsOwnedBy(ctx.User.ID) - if err != nil { - ctx.JSON(500, api.SearchError{ - OK: false, - Error: err.Error(), - }) - return - } - } - } - } - repos, count, err := models.SearchRepositoryByName(opts) if err != nil { ctx.JSON(500, api.SearchError{ diff --git a/routers/user/home.go b/routers/user/home.go index b53a47db94..9ccd5bdb26 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -499,50 +499,20 @@ func showOrgProfile(ctx *context.Context) { count int64 err error ) - if ctx.IsSigned && !ctx.User.IsAdmin { - env, err := org.AccessibleReposEnv(ctx.User.ID) - if err != nil { - ctx.ServerError("AccessibleReposEnv", err) - return - } - env.SetSort(orderBy) - if len(keyword) != 0 { - env.AddKeyword(keyword) - } - repos, err = env.Repos(page, setting.UI.User.RepoPagingNum) - if err != nil { - ctx.ServerError("env.Repos", err) - return - } - count, err = env.CountRepos() - if err != nil { - ctx.ServerError("env.CountRepos", err) - return - } - } else { - showPrivate := ctx.IsSigned && ctx.User.IsAdmin - if len(keyword) == 0 { - repos, err = models.GetUserRepositories(org.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String()) - if err != nil { - ctx.ServerError("GetRepositories", err) - return - } - count = models.CountUserRepositories(org.ID, showPrivate) - } else { - repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ - Keyword: keyword, - OwnerID: org.ID, - OrderBy: orderBy, - Private: showPrivate, - Page: page, - IsProfile: true, - PageSize: setting.UI.User.RepoPagingNum, - }) - if err != nil { - ctx.ServerError("SearchRepositoryByName", err) - return - } - } + repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ + Keyword: keyword, + OwnerID: org.ID, + OrderBy: orderBy, + Private: ctx.IsSigned, + UserIsAdmin: ctx.IsUserSiteAdmin(), + UserID: ctx.Data["SignedUserID"].(int64), + Page: page, + IsProfile: true, + PageSize: setting.UI.User.RepoPagingNum, + }) + if err != nil { + ctx.ServerError("SearchRepositoryByName", err) + return } if err := org.GetMembers(); err != nil { diff --git a/routers/user/profile.go b/routers/user/profile.go index a7dab18c7a..bda29522d9 100644 --- a/routers/user/profile.go +++ b/routers/user/profile.go @@ -170,74 +170,44 @@ func Profile(ctx *context.Context) { } case "stars": ctx.Data["PageIsProfileStarList"] = true - if len(keyword) == 0 { - repos, err = ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String()) - if err != nil { - ctx.ServerError("GetStarredRepos", err) - return - } - - count, err = ctxUser.GetStarredRepoCount(showPrivate) - if err != nil { - ctx.ServerError("GetStarredRepoCount", err) - return - } - } else { - repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ - Keyword: keyword, - OwnerID: ctxUser.ID, - OrderBy: orderBy, - Private: showPrivate, - Page: page, - PageSize: setting.UI.User.RepoPagingNum, - Starred: true, - Collaborate: util.OptionalBoolFalse, - TopicOnly: topicOnly, - }) - if err != nil { - ctx.ServerError("SearchRepositoryByName", err) - return - } + repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ + Keyword: keyword, + OrderBy: orderBy, + Private: ctx.IsSigned, + UserIsAdmin: ctx.IsUserSiteAdmin(), + UserID: ctx.Data["SignedUserID"].(int64), + Page: page, + PageSize: setting.UI.User.RepoPagingNum, + StarredByID: ctxUser.ID, + Collaborate: util.OptionalBoolFalse, + TopicOnly: topicOnly, + }) + if err != nil { + ctx.ServerError("SearchRepositoryByName", err) + return } total = int(count) default: - if len(keyword) == 0 { - repos, err = models.GetUserRepositories(ctxUser.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String()) - if err != nil { - ctx.ServerError("GetRepositories", err) - return - } - - if showPrivate { - total = ctxUser.NumRepos - } else { - count, err := models.GetPublicRepositoryCount(ctxUser) - if err != nil { - ctx.ServerError("GetPublicRepositoryCount", err) - return - } - total = int(count) - } - } else { - repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ - Keyword: keyword, - OwnerID: ctxUser.ID, - OrderBy: orderBy, - Private: showPrivate, - Page: page, - IsProfile: true, - PageSize: setting.UI.User.RepoPagingNum, - Collaborate: util.OptionalBoolFalse, - TopicOnly: topicOnly, - }) - if err != nil { - ctx.ServerError("SearchRepositoryByName", err) - return - } - - total = int(count) + repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ + Keyword: keyword, + OwnerID: ctxUser.ID, + OrderBy: orderBy, + Private: ctx.IsSigned, + UserIsAdmin: ctx.IsUserSiteAdmin(), + UserID: ctx.Data["SignedUserID"].(int64), + Page: page, + IsProfile: true, + PageSize: setting.UI.User.RepoPagingNum, + Collaborate: util.OptionalBoolFalse, + TopicOnly: topicOnly, + }) + if err != nil { + ctx.ServerError("SearchRepositoryByName", err) + return } + + total = int(count) } ctx.Data["Repos"] = repos ctx.Data["Total"] = total diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0752e7be2b..c0790ac23e 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -1085,6 +1085,19 @@ "name": "uid", "in": "query" }, + { + "type": "integer", + "format": "int64", + "description": "search only for repos that the user with the given id has starred", + "name": "starredBy", + "in": "query" + }, + { + "type": "boolean", + "description": "include private repositories this user has access to (defaults to true)", + "name": "private", + "in": "query" + }, { "type": "integer", "description": "page number of results to return (1-based)", From 7dd983797c218d7ae45e67d79517e95ad3dd24b8 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 15 May 2019 15:52:29 +0000 Subject: [PATCH 022/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 788a2201fe..e87b2c9231 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1268,7 +1268,9 @@ settings.protected_branch_can_push_yes=プッシュできます settings.protected_branch_can_push_no=プッシュできません settings.branch_protection=ブランチ '%s' の保護 settings.protect_this_branch=ブランチの保護を有効にする +settings.protect_this_branch_desc=ブランチの削除を防ぎ、ブランチへのいかなるプッシュも無効にします。 settings.protect_whitelist_committers=プッシュ・ホワイトリストを有効にする +settings.protect_whitelist_committers_desc=ホワイトリストに登録したユーザーまたはチームに、このブランチへのプッシュを許可します。(強制プッシュ以外) settings.protect_whitelist_users=プッシュ・ホワイトリストに含むユーザー: settings.protect_whitelist_search_users=ユーザーを検索… settings.protect_whitelist_teams=プッシュ・ホワイトリストに含むチーム: From 775a5a5b0f4c1a7aa7b301569fe89d7c6e751c46 Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 15 May 2019 22:37:06 +0100 Subject: [PATCH 023/220] Stop colorizing files by default (#6949) --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 3 +-- docs/content/doc/advanced/logging-documentation.en-us.md | 3 +-- modules/setting/log.go | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 6b209b97bb..f40d35cdba 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -334,7 +334,7 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` ### Console log mode (`log.console`, `log.console.*`, or `MODE=console`) -- For the console logger `COLORIZE` will default to `true` if not on windows. +- For the console logger `COLORIZE` will default to `true` if not on windows or the terminal is determined to be able to color. - `STDERR`: **false**: Use Stderr instead of Stdout. ### File log mode (`log.file`, `log.file.*` or `MODE=file`) @@ -344,7 +344,6 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` - `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file, 28 represents 256Mb. - `DAILY_ROTATE`: **true**: Rotate logs daily. - `MAX_DAYS`: **7**: Delete the log file after n days -- NB: `COLORIZE`: will default to `true` if not on windows. - `COMPRESS`: **true**: Compress old log files by default with gzip - `COMPRESSION_LEVEL`: **-1**: Compression level diff --git a/docs/content/doc/advanced/logging-documentation.en-us.md b/docs/content/doc/advanced/logging-documentation.en-us.md index d9a21affce..df35786943 100644 --- a/docs/content/doc/advanced/logging-documentation.en-us.md +++ b/docs/content/doc/advanced/logging-documentation.en-us.md @@ -213,7 +213,7 @@ from `[log.sublogger]`. a stacktrace. This value is inherited. * `MODE` is the mode of the log output. It will default to the sublogger name. Thus `[log.console.macaron]` will default to `MODE = console`. -* `COLORIZE` will default to `true` for `file` and `console` as +* `COLORIZE` will default to `true` for `console` as described, otherwise it will default to `false`. ### Non-inherited default values @@ -274,7 +274,6 @@ Other values: * `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file, 28 represents 256Mb. * `DAILY_ROTATE`: **true**: Rotate logs daily. * `MAX_DAYS`: **7**: Delete the log file after n days -* NB: `COLORIZE`: will default to `true` if not on windows. * `COMPRESS`: **true**: Compress old log files by default with gzip * `COMPRESSION_LEVEL`: **-1**: Compression level diff --git a/modules/setting/log.go b/modules/setting/log.go index 43a28309d2..9f4bbf9d87 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -10,7 +10,6 @@ import ( "os" "path" "path/filepath" - "runtime" "strings" "code.gitea.io/gitea/modules/log" @@ -113,7 +112,6 @@ func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions panic(err.Error()) } - logConfig["colorize"] = sec.Key("COLORIZE").MustBool(runtime.GOOS != "windows") logConfig["filename"] = logPath logConfig["rotate"] = sec.Key("LOG_ROTATE").MustBool(true) logConfig["maxsize"] = 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)) From d9dcd093403b3194bcf3b4be36eaf90250e06ed1 Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 16 May 2019 07:57:47 +0200 Subject: [PATCH 024/220] add make targets for js and css, add js linter (#6952) * add make targets for js,css, add javascript linter - add `make js`, deprecating `make javascripts` - add `make css`, deprecating `make generate-stylesheets` and `make stylesheets-check` - changed the unclean css check to only run on CI - add JS linting via eslint with basic configuration and fixed discovered issues - changed autoprefixer to use official `postcss-cli` avoiding the need to loop in the makefile - moved browserslist to package.json so other future tools can use it too. - update documentation for new make targets and added JS section * fix indentation * move functions used in html to 'exported' list * Run lessc binary without having to install anything to node_modules * use relative paths to node bin scripts, removing npx * Revert "use relative paths to node bin scripts, removing npx" This reverts commit 119b725525a8430b32ee7a6e6009b4ece544e39b. * fix lessc and postcss plugins * check for node_modules and use actual bin names --- .drone.yml | 3 +- .eslintrc | 25 + CONTRIBUTING.md | 12 +- Makefile | 60 +- .../doc/advanced/hacking-on-gitea.en-us.md | 34 +- package-lock.json | 728 +++++++++++++++++- package.json | 11 +- public/js/draw.js | 8 +- public/js/index.js | 142 ++-- 9 files changed, 891 insertions(+), 132 deletions(-) create mode 100644 .eslintrc diff --git a/.drone.yml b/.drone.yml index 4a88427eee..662529bf2e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -50,7 +50,8 @@ pipeline: pull: true commands: - npm install - - make stylesheets-check + - make css + - make js when: event: [ push, tag, pull_request ] diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000..41cad889b1 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,25 @@ +root: true + +extends: + - eslint:recommended + +parserOptions: + ecmaVersion: 2015 + +env: + browser: true + jquery: true + es6: true + +globals: + Clipboard: false + CodeMirror: false + emojify: false + SimpleMDE: false + Vue: false + Dropzone: false + u2fApi: false + hljs: false + +rules: + no-unused-vars: [error, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 260727f15e..fd3b35030f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,9 +65,9 @@ high-level discussions. ## Testing redux Before submitting a pull request, run all the tests for the whole tree -to make sure your changes don't cause regression elsewhere. +to make sure your changes don't cause regression elsewhere. -Here's how to run the test suite: +Here's how to run the test suite: - Install the correct version of the drone-cli package. As of this writing, the correct drone-cli version is @@ -75,7 +75,7 @@ Here's how to run the test suite: - Ensure you have enough free disk space. You will need at least 15-20 Gb of free disk space to hold all of the containers drone creates (a default AWS or GCE disk size won't work -- see - [#6243](https://github.com/go-gitea/gitea/issues/6243)). + [#6243](https://github.com/go-gitea/gitea/issues/6243)). - Change into the base directory of your copy of the gitea repository, and run `drone exec --local --build-event pull_request`. @@ -114,7 +114,7 @@ Generally, the go build tools are installed as-needed in the `Makefile`. An exception are the tools to build the CSS and images. - To build CSS: Install [Node.js](https://nodejs.org/en/download/package-manager) at version 8.0 or above - with `npm` and then run `npm install` and `make generate-stylesheets`. + with `npm` and then run `npm install` and `make css`. - To build Images: ImageMagick, inkscape and zopflipng binaries must be available in your `PATH` to run `make generate-images`. @@ -214,7 +214,7 @@ to the maintainers team. If a maintainer is inactive for more than 3 months and forgets to leave the maintainers team, the owners may move him or her from the maintainers team to the advisors team. For security reasons, Maintainers should use 2FA for their accounts and -if possible provide gpg signed commits. +if possible provide gpg signed commits. https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/ https://help.github.com/articles/signing-commits-with-gpg/ @@ -281,7 +281,7 @@ be reviewed by two maintainers and must pass the automatic tests. * Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`. * When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin` * If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged. -* Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`. +* Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`. * And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically created a release and upload all the compiled binary. (But currently it didn't add the release notes automatically. Maybe we should fix that.) * If needed send PR for changelog on branch `master`. * Send PR to [blog repository](https://github.com/go-gitea/blog) announcing the release. diff --git a/Makefile b/Makefile index 2b77ce5dca..718836be65 100644 --- a/Makefile +++ b/Makefile @@ -365,33 +365,55 @@ release-compress: fi cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done; -.PHONY: javascripts -javascripts: public/js/index.js - -.IGNORE: public/js/index.js -public/js/index.js: $(JAVASCRIPTS) - cat $< >| $@ - -.PHONY: stylesheets-check -stylesheets-check: generate-stylesheets - @diff=$$(git diff public/css/*); \ - if [ -n "$$diff" ]; then \ - echo "Please run 'make generate-stylesheets' and commit the result:"; \ - echo "$${diff}"; \ +.PHONY: js +js: + @if ([ ! -d "$(PWD)/node_modules" ]); then \ + echo "node_modules directory is absent, please run 'npm install' first"; \ exit 1; \ fi; - -.PHONY: generate-stylesheets -generate-stylesheets: @hash npx > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ echo "Please install npm version 5.2+"; \ exit 1; \ fi; - $(eval BROWSERS := "> 1%, last 2 firefox versions, last 2 safari versions, ie 11") - npx lesshint public/less/ + npx eslint public/js + +.PHONY: css +css: + @if ([ ! -d "$(PWD)/node_modules" ]); then \ + echo "node_modules directory is absent, please run 'npm install' first"; \ + exit 1; \ + fi; + @hash npx > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + echo "Please install npm version 5.2+"; \ + exit 1; \ + fi; + + npx lesshint public/less/ npx lessc --clean-css="--s0 -b" public/less/index.less public/css/index.css $(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css="--s0 -b" public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;) - $(foreach file, $(wildcard public/css/*),npx postcss --use autoprefixer --autoprefixer.browsers $(BROWSERS) -o $(file) $(file);) + npx postcss --use autoprefixer --no-map --replace public/css/* + + @diff=$$(git diff public/css/*); \ + if ([ ! -z "$CI" ] && [ -n "$$diff" ]); then \ + echo "Generated files in public/css have changed, please commit the result:"; \ + echo "$${diff}"; \ + exit 1; \ + fi; + +.PHONY: javascripts +javascripts: + echo "'make javascripts' is deprecated, please use 'make js'" + $(MAKE) js + +.PHONY: stylesheets-check +stylesheets-check: + echo "'make stylesheets-check' is deprecated, please use 'make css'" + $(MAKE) css + +.PHONY: generate-stylesheets +generate-stylesheets: + echo "'make generate-stylesheets' is deprecated, please use 'make css'" + $(MAKE) css .PHONY: swagger-ui swagger-ui: diff --git a/docs/content/doc/advanced/hacking-on-gitea.en-us.md b/docs/content/doc/advanced/hacking-on-gitea.en-us.md index 1fabc1a118..48a4510545 100644 --- a/docs/content/doc/advanced/hacking-on-gitea.en-us.md +++ b/docs/content/doc/advanced/hacking-on-gitea.en-us.md @@ -136,30 +136,36 @@ You should lint, vet and spell-check with: make vet lint misspell-check ``` -### Updating the stylesheets +### Updating CSS -To generate the stylsheets, you will need [Node.js](https://nodejs.org/) at version 8.0 or above. - -At present we use [less](http://lesscss.org/) and [postcss](https://postcss.org) to generate our stylesheets. Do -**not** edit the files in `public/css/` directly, as they are generated from -`lessc` from the files in `public/less/`. - -If you wish to work on the stylesheets, you will need to install `lessc` the -less compiler and `postcss`. The recommended way to do this is using `npm install`: +To generate the CSS, you will need [Node.js](https://nodejs.org/) 8.0 or greater and the build dependencies: ```bash -cd "$GOPATH/src/code.gitea.io/gitea" npm install ``` -You can then edit the less stylesheets and regenerate the stylesheets using: +At present we use [less](http://lesscss.org/) and [postcss](https://postcss.org) to generate our CSS. Do +**not** edit the files in `public/css` directly, as they are generated from `lessc` from the files in `public/less`. + +Edit files in `public/less`, run the linter, regenerate the CSS and commit all changed files: ```bash -make generate-stylesheets +make css ``` -You should commit both the changes to the css and the less files when making -PRs. +### Updating JS + +To run the JavaScript linter you will need [Node.js](https://nodejs.org/) 8.0 or greater and the build dependencies: + +```bash +npm install +``` + +Edit files in `public/js` and run the linter: + +```bash +make js +``` ### Updating the API diff --git a/package-lock.json b/package-lock.json index 57a39821e9..6a81145ec1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,6 +2,26 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -18,12 +38,23 @@ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, "ajv": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", "dev": true, - "optional": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -35,22 +66,19 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true, - "optional": true + "dev": true }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "optional": true + "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, - "optional": true, "requires": { "punycode": "^2.1.0" } @@ -63,6 +91,18 @@ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -159,6 +199,12 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -385,6 +431,12 @@ } } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -408,6 +460,21 @@ } } }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -473,6 +540,19 @@ "parse-json": "^4.0.0" } }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, "cssesc": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", @@ -500,6 +580,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -551,12 +637,27 @@ "path-type": "^3.0.0" } }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "electron-to-chromium": { "version": "1.3.133", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.133.tgz", "integrity": "sha512-lyoC8aoqbbDqsprb6aPdt9n3DpOZZzdz/T4IZKsR0/dkZIxnJVUjjcpOSwA66jPRIOyDAamCTAUqweU05kKNSg==", "dev": true }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -572,12 +673,158 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -634,6 +881,17 @@ } } }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -703,8 +961,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true, - "optional": true + "dev": true }, "fast-glob": { "version": "2.2.6", @@ -720,6 +977,30 @@ "micromatch": "^3.1.10" } }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -743,6 +1024,23 @@ } } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true + }, "flatten": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", @@ -808,6 +1106,12 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -855,6 +1159,12 @@ "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", "dev": true }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, "globby": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", @@ -933,6 +1243,15 @@ } } }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ignore": { "version": "3.3.10", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", @@ -956,6 +1275,12 @@ "resolve-from": "^3.0.0" } }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", @@ -978,6 +1303,44 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "inquirer": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", + "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -1067,6 +1430,12 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -1105,6 +1474,12 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -1117,12 +1492,24 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -1139,6 +1526,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -1545,6 +1938,16 @@ "strip-json-comments": "^2.0.0" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", @@ -1605,6 +2008,12 @@ "to-regex": "^3.0.2" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1614,6 +2023,12 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", @@ -1635,12 +2050,27 @@ } } }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -1660,6 +2090,18 @@ "to-regex": "^3.0.1" } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, "node-releases": { "version": "1.1.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.19.tgz", @@ -1746,6 +2188,52 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -1774,6 +2262,18 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, "path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", @@ -1900,12 +2400,23 @@ "uniq": "^1.0.1" } }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "optional": true + "dev": true }, "regex-not": { "version": "1.0.2", @@ -1917,6 +2428,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", @@ -1941,12 +2458,49 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -1967,8 +2521,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true + "dev": true }, "semver": { "version": "5.7.0", @@ -1999,12 +2552,44 @@ } } }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -2173,6 +2758,25 @@ } } }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -2188,6 +2792,67 @@ "has-flag": "^3.0.0" } }, + "table": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/table/-/table-5.3.3.tgz", + "integrity": "sha512-3wUNCgdWX6PNpOe3amTTPWPuF6VGvgzjKCaO1snFj0z7Y3mUPWf5+zDtxUVGispJkDECPmR29wbzh6bVMOHbcw==", + "dev": true, + "requires": { + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -2257,6 +2922,12 @@ } } }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -2267,6 +2938,15 @@ "safe-buffer": "^5.0.1" } }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -2360,11 +3040,35 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } } } } diff --git a/package.json b/package.json index 094941980f..1bbe6cf8ae 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,16 @@ "license": "MIT", "devDependencies": { "autoprefixer": "9.5.1", + "eslint": "5.16.0", "less": "3.9.0", "less-plugin-clean-css": "1.5.1", "lesshint": "^6.3.6", - "postcss-cli-simple": "3.0.0" - } + "postcss-cli": "6.1.2" + }, + "browserslist": [ + "> 1%", + "last 2 firefox versions", + "last 2 safari versions", + "ie 11" + ] } diff --git a/public/js/draw.js b/public/js/draw.js index fd99e1a73d..518d1ec545 100644 --- a/public/js/draw.js +++ b/public/js/draw.js @@ -1,13 +1,15 @@ +/* globals gitGraph */ + $(document).ready(function () { var graphList = []; - + if (!document.getElementById('graph-canvas')) { return; } - + $("#graph-raw-list li span.node-relation").each(function () { graphList.push($(this).text()); }) - + gitGraph(document.getElementById('graph-canvas'), graphList); }) diff --git a/public/js/index.js b/public/js/index.js index 79d0569f9b..96d55eca87 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1,3 +1,6 @@ +/* globals wipPrefixes, issuesTribute, emojiTribute */ +/* exported timeAddManual, toggleStopwatch, cancelStopwatch, initHeatmap */ +/* exported toggleDeadlineForm, setDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */ 'use strict'; function htmlEncode(text) { @@ -89,7 +92,7 @@ if (!Array.from) { if (typeof Object.assign != 'function') { // Must be writable: true, enumerable: false, configurable: true Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 + value: function assign(target, _varArgs) { // .length of function is 2 'use strict'; if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object'); @@ -131,8 +134,8 @@ function initCommentPreviewTab($form) { var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]'); $previewPanel.html(data); emojify.run($previewPanel[0]); - $('pre code', $previewPanel[0]).each(function (i, block) { - hljs.highlightBlock(block); + $('pre code', $previewPanel[0]).each(function () { + hljs.highlightBlock(this); }); } ); @@ -161,8 +164,8 @@ function initEditPreviewTab($form) { var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]'); $previewPanel.html(data); emojify.run($previewPanel[0]); - $('pre code', $previewPanel[0]).each(function (i, block) { - hljs.highlightBlock(block); + $('pre code', $previewPanel[0]).each(function () { + hljs.highlightBlock(this); }); } ); @@ -355,7 +358,8 @@ function reload() { } function initImagePaste(target) { - target.each(function(i, field) { + target.each(function() { + var field = this; field.addEventListener('paste', function(event){ retrieveImageFromClipboardAsBlob(event, function(img) { var name = img.name.substr(0, img.name.lastIndexOf('.')); @@ -606,7 +610,7 @@ function initInstall() { $('#sql_settings').show(); $('#pgsql_settings').toggle(dbType === "PostgreSQL"); - $.each(dbDefaults, function(type, defaultHost) { + $.each(dbDefaults, function(_type, defaultHost) { if ($('#db_host').val() == defaultHost) { $('#db_host').val(dbDefaults[dbType]); return false; @@ -636,8 +640,7 @@ function initInstall() { }); $('#enable-openid-signin input').change(function () { if ($(this).is(':checked')) { - if ( $('#disable-registration input').is(':checked') ) { - } else { + if (!$('#disable-registration input').is(':checked')) { $('#enable-openid-signup').checkbox('check'); } } else { @@ -669,7 +672,7 @@ function initRepository() { $dropdown.dropdown({ fullTextSearch: true, selectOnKeydown: false, - onChange: function (text, value, $choice) { + onChange: function (_text, _value, $choice) { if ($choice.data('url')) { window.location.href = $choice.data('url'); } @@ -756,9 +759,6 @@ function initRepository() { } // Milestones - if ($('.repository.milestones').length > 0) { - - } if ($('.repository.new.milestone').length > 0) { var $datepicker = $('.milestone.datepicker'); $datepicker.datetimepicker({ @@ -857,8 +857,8 @@ function initRepository() { } else { $renderContent.html(data.content); emojify.run($renderContent[0]); - $('pre code', $renderContent[0]).each(function (i, block) { - hljs.highlightBlock(block); + $('pre code', $renderContent[0]).each(function () { + hljs.highlightBlock(this); }); } }); @@ -912,7 +912,7 @@ function initRepository() { $(this).parent().hide(); }); $('.merge-button > .dropdown').dropdown({ - onChange: function (text, value, $choice) { + onChange: function (_text, _value, $choice) { if ($choice.data('do')) { $mergeButton.find('.button-text').text($choice.text()); $mergeButton.data('do', $choice.data('do')); @@ -930,16 +930,13 @@ function initRepository() { // Diff if ($('.repository.diff').length > 0) { - var $counter = $('.diff-counter'); - if ($counter.length >= 1) { - $counter.each(function (i, item) { - var $item = $(item); - var addLine = $item.find('span[data-line].add').data("line"); - var delLine = $item.find('span[data-line].del').data("line"); - var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100; - $item.find(".bar .add").css("width", addPercent + "%"); - }); - } + $('.diff-counter').each(function () { + var $item = $(this); + var addLine = $item.find('span[data-line].add').data("line"); + var delLine = $item.find('span[data-line].del').data("line"); + var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100; + $item.find(".bar .add").css("width", addPercent + "%"); + }); } // Quick start and repository home @@ -982,7 +979,7 @@ function initRepository() { var toggleMigrations = function(){ var authUserName = $('#auth_username').val(); var cloneAddr = $('#clone_addr').val(); - if (!$('#mirror').is(":checked") && (authUserName!=undefined && authUserName.length > 0) + if (!$('#mirror').is(":checked") && (authUserName!=undefined && authUserName.length > 0) && (cloneAddr!=undefined && (cloneAddr.startsWith("https://github.com") || cloneAddr.startsWith("http://github.com")))) { $('#migrate_items').show(); } else { @@ -1085,8 +1082,9 @@ function assingMenuAttributes(menu) { var id = Math.floor(Math.random() * Math.floor(1000000)); menu.attr('data-write', menu.attr('data-write') + id); menu.attr('data-preview', menu.attr('data-preview') + id); - menu.find('.item').each(function(i, item) { - $(item).attr('data-tab', $(item).attr('data-tab') + id); + menu.find('.item').each(function() { + var tab = $(this).attr('data-tab') + id; + $(this).attr('data-tab', tab); }); menu.parent().find("*[data-tab='write']").attr('data-tab', 'write' + id); menu.parent().find("*[data-tab='preview']").attr('data-tab', 'preview' + id); @@ -1170,22 +1168,20 @@ String.prototype.endsWith = function (pattern) { }; // Adding function to get the cursor position in a text field to jQuery object. -(function ($, undefined) { - $.fn.getCursorPosition = function () { - var el = $(this).get(0); - var pos = 0; - if ('selectionStart' in el) { - pos = el.selectionStart; - } else if ('selection' in document) { - el.focus(); - var Sel = document.selection.createRange(); - var SelLength = document.selection.createRange().text.length; - Sel.moveStart('character', -el.value.length); - pos = Sel.text.length - SelLength; - } - return pos; +$.fn.getCursorPosition = function () { + var el = $(this).get(0); + var pos = 0; + if ('selectionStart' in el) { + pos = el.selectionStart; + } else if ('selection' in document) { + el.focus(); + var Sel = document.selection.createRange(); + var SelLength = document.selection.createRange().text.length; + Sel.moveStart('character', -el.value.length); + pos = Sel.text.length - SelLength; } -})(jQuery); + return pos; +} function setSimpleMDE($editArea) { if (codeMirrorEditor) { @@ -1249,7 +1245,7 @@ function setCodeMirror($editArea) { codeMirrorEditor = CodeMirror.fromTextArea($editArea[0], { lineNumbers: true }); - codeMirrorEditor.on("change", function (cm, change) { + codeMirrorEditor.on("change", function (cm, _change) { $editArea.val(cm.getValue()); }); @@ -1271,10 +1267,13 @@ function initEditor() { $editFilename.keyup(function (e) { var $section = $('.breadcrumb span.section'); var $divider = $('.breadcrumb div.divider'); + var value; + var parts; + if (e.keyCode == 8) { if ($(this).getCursorPosition() == 0) { if ($section.length > 0) { - var value = $section.last().find('a').text(); + value = $section.last().find('a').text(); $(this).val(value + $(this).val()); $(this)[0].setSelectionRange(value.length, value.length); $section.last().remove(); @@ -1283,9 +1282,9 @@ function initEditor() { } } if (e.keyCode == 191) { - var parts = $(this).val().split('/'); + parts = $(this).val().split('/'); for (var i = 0; i < parts.length; ++i) { - var value = parts[i]; + value = parts[i]; if (i < parts.length - 1) { if (value.length) { $('' + value + '').insertBefore($(this)); @@ -1298,9 +1297,9 @@ function initEditor() { $(this)[0].setSelectionRange(0, 0); } } - var parts = []; - $('.breadcrumb span.section').each(function (i, element) { - element = $(element); + parts = []; + $('.breadcrumb span.section').each(function () { + var element = $(this); if (element.find('a').length) { parts.push(element.find('a').text()); } else { @@ -1319,10 +1318,11 @@ function initEditor() { var markdownFileExts = $editArea.data("markdown-file-exts").split(","); var lineWrapExtensions = $editArea.data("line-wrap-extensions").split(","); - $editFilename.on("keyup", function (e) { + $editFilename.on("keyup", function () { var val = $editFilename.val(), m, mode, spec, extension, extWithDot, previewLink, dataUrl, apiCall; extension = extWithDot = ""; - if (m = /.+\.([^.]+)$/.exec(val)) { + m = /.+\.([^.]+)$/.exec(val); + if (m) { extension = m[1]; extWithDot = "." + extension; } @@ -1684,15 +1684,6 @@ function buttonsClickOnEnter() { }); } -function hideWhenLostFocus(body, parent) { - $(document).click(function (e) { - var target = e.target; - if (!$(target).is(body) && !$(target).parents().is(parent)) { - $(body).hide(); - } - }); -} - function searchUsers() { var $searchUserBox = $('#search-user-box'); $searchUserBox.search({ @@ -1701,7 +1692,7 @@ function searchUsers() { url: suburl + '/api/v1/users/search?q={query}', onResponse: function(response) { var items = []; - $.each(response.data, function (i, item) { + $.each(response.data, function (_i, item) { var title = item.login; if (item.full_name && item.full_name.length > 0) { title += ' (' + htmlEncode(item.full_name) + ')'; @@ -1728,7 +1719,7 @@ function searchRepositories() { url: suburl + '/api/v1/repos/search?q={query}&uid=' + $searchRepoBox.data('uid'), onResponse: function(response) { var items = []; - $.each(response.data, function (i, item) { + $.each(response.data, function (_i, item) { items.push({ title: item.full_name.split("/")[1], description: item.full_name @@ -1752,8 +1743,8 @@ function initCodeView() { deSelect(); }); - $(window).on('hashchange', function (e) { - var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/); + $(window).on('hashchange', function () { + var m = window.location.hash.match(/^#(L\d+)-(L\d+)$/); var $list = $('.code-view ol.linenums > li'); var $first; if (m) { @@ -1803,7 +1794,7 @@ function u2fSigned(resp) { contentType: "application/json; charset=utf-8", }).done(function(res){ window.location.replace(res); - }).fail(function (xhr, textStatus) { + }).fail(function () { u2fError(1); }); } @@ -1821,7 +1812,7 @@ function u2fRegistered(resp) { success: function(){ reload(); }, - fail: function (xhr, textStatus) { + fail: function () { u2fError(1); } }); @@ -1889,7 +1880,7 @@ function u2fRegisterRequest() { } u2fError(reason.metaData.code); }); - }).fail(function(xhr, status, error) { + }).fail(function(xhr) { if(xhr.status === 409) { $("#nickname").closest("div.field").addClass("error"); } @@ -1962,7 +1953,7 @@ $(document).ready(function () { }); // make table element clickable like a link - $('tr[data-href]').click(function(event) { + $('tr[data-href]').click(function() { window.location = $(this).data('href'); }); @@ -2388,7 +2379,7 @@ function initVueComponents(){ var searchedURL = this.searchURL; var searchedQuery = this.searchQuery; - $.getJSON(searchedURL, function(result, textStatus, request) { + $.getJSON(searchedURL, function(result, _textStatus, request) { if (searchedURL == self.searchURL) { self.repos = result.data; var count = request.getResponseHeader('X-Total-Count'); @@ -2446,6 +2437,7 @@ function initVueApp() { }, }); } + function timeAddManual() { $('.mini.modal') .modal({ @@ -2796,7 +2788,7 @@ function initTopicbar() { $.post(saveBtn.data('link'), { "_csrf": csrf, "topics": topics - }, function(data, textStatus, xhr){ + }, function(_data, _textStatus, xhr){ if (xhr.responseJSON.status === 'ok') { viewDiv.children(".topic").remove(); if (topics.length) { @@ -2873,14 +2865,14 @@ function initTopicbar() { this.attr("data-value", value).contents().first().replaceWith(value); return $(this); }, - onAdd: function(addedValue, addedText, $addedChoice) { + onAdd: function(addedValue, _addedText, $addedChoice) { addedValue = addedValue.toLowerCase().trim(); $($addedChoice).attr('data-value', addedValue); $($addedChoice).attr('data-text', addedValue); } }); - $.fn.form.settings.rules.validateTopic = function(values, regExp) { + $.fn.form.settings.rules.validateTopic = function(_values, regExp) { var topics = topicDropdown.children('a.ui.label'), status = topics.length === 0 || topics.last().attr("data-value").match(regExp); if (!status) { @@ -2981,7 +2973,7 @@ function initIssueList() { var filteredResponse = {'success': true, 'results': []}; var currIssueId = $('#new-dependency-drop-list').data('issue-id'); // Parse the response from the api to work with our dropdown - $.each(response, function(index, issue) { + $.each(response, function(_i, issue) { // Don't list current issue in the dependency list. if(issue.id === currIssueId) { return; From 68a83cc5a240504e7d35ed2cdc1fae889fc08a1b Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Thu, 16 May 2019 11:48:40 -0400 Subject: [PATCH 025/220] Allow collaborators to view repo owned private org (#6965) Handle case where an orginization is private but a user who is not a member of the orgninization has been added as a collaborator of a repo within that org Fixes #6962 --- integrations/org_test.go | 9 +++++++++ models/fixtures/collaboration.yml | 6 ++++++ models/repo_permission.go | 16 ++++++++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/integrations/org_test.go b/integrations/org_test.go index 17b8958480..d86c82989d 100644 --- a/integrations/org_test.go +++ b/integrations/org_test.go @@ -92,6 +92,15 @@ func TestPrivateOrg(t *testing.T) { req = NewRequest(t, "GET", "/privated_org/private_repo_on_private_org") session.MakeRequest(t, req, http.StatusNotFound) + // non-org member who is collaborator on repo in private org + session = loginUser(t, "user4") + req = NewRequest(t, "GET", "/privated_org") + session.MakeRequest(t, req, http.StatusNotFound) + req = NewRequest(t, "GET", "/privated_org/public_repo_on_private_org") // colab of this repo + session.MakeRequest(t, req, http.StatusOK) + req = NewRequest(t, "GET", "/privated_org/private_repo_on_private_org") + session.MakeRequest(t, req, http.StatusNotFound) + // site admin session = loginUser(t, "user1") req = NewRequest(t, "GET", "/privated_org") diff --git a/models/fixtures/collaboration.yml b/models/fixtures/collaboration.yml index 18db9c36c5..d32e288e4c 100644 --- a/models/fixtures/collaboration.yml +++ b/models/fixtures/collaboration.yml @@ -9,3 +9,9 @@ repo_id: 4 user_id: 4 mode: 2 # write + +- + id: 3 + repo_id: 40 + user_id: 4 + mode: 2 # write \ No newline at end of file diff --git a/models/repo_permission.go b/models/repo_permission.go index 583bc8c812..25239f4dd4 100644 --- a/models/repo_permission.go +++ b/models/repo_permission.go @@ -168,7 +168,17 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss repo.mustOwner(e) } - if repo.Owner.IsOrganization() && !HasOrgVisible(repo.Owner, user) { + var isCollaborator bool + if user != nil { + isCollaborator, err = repo.isCollaborator(e, user.ID) + if err != nil { + return perm, err + } + } + + // Prevent strangers from checking out public repo of private orginization + // Allow user if they are collaborator of a repo within a private orginization but not a member of the orginization itself + if repo.Owner.IsOrganization() && !HasOrgVisible(repo.Owner, user) && !isCollaborator { perm.AccessMode = AccessModeNone return } @@ -207,9 +217,7 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss perm.UnitsMode = make(map[UnitType]AccessMode) // Collaborators on organization - if isCollaborator, err := repo.isCollaborator(e, user.ID); err != nil { - return perm, err - } else if isCollaborator { + if isCollaborator { for _, u := range repo.Units { perm.UnitsMode[u.Type] = perm.AccessMode } From 04f996f1f977fe00cc5ef55ac0548827221f9226 Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 16 May 2019 21:33:54 +0200 Subject: [PATCH 026/220] remove and disable package-lock (#6969) * remove and disable package-lock Using exact versions in package.json has the same effect as lockfiles without all the troubles the lockfiles bring (different versions of package manager generating different lockfiles primarily). Ensured we only use exact versions in package.json and stopped generation of new lockfiles via .npmrc which is support by both the npm and yarn package managers. Fixes: https://github.com/go-gitea/gitea/issues/6967 * enable save-exact --- .gitignore | 2 + .npmrc | 2 + package-lock.json | 3074 --------------------------------------------- package.json | 2 +- 4 files changed, 5 insertions(+), 3075 deletions(-) create mode 100644 .npmrc delete mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index a66bf9cff6..6cd2178380 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,8 @@ coverage.all /node_modules /modules/indexer/issues/indexers routers/repo/authorized_keys +/package-lock.json +/yarn.lock # Snapcraft snap/.snapcraft/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..0ca8d2a0b6 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +package-lock=false +save-exact=true diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 6a81145ec1..0000000000 --- a/package-lock.json +++ /dev/null @@ -1,3074 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true - }, - "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", - "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", - "dev": true - }, - "ajv": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", - "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "dependencies": { - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - } - } - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - }, - "dependencies": { - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - } - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "optional": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true, - "optional": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "autoprefixer": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.5.1.tgz", - "integrity": "sha512-KJSzkStUl3wP0D5sdMlP82Q52JLy5+atf2MHAre48+ckWkXgixmfHyWmA77wFDy6jTHU6mIgXv6hAQ2mf1PjJQ==", - "dev": true, - "requires": { - "browserslist": "^4.5.4", - "caniuse-lite": "^1.0.30000957", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.14", - "postcss-value-parser": "^3.3.1" - } - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browserslist": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.6.tgz", - "integrity": "sha512-o/hPOtbU9oX507lIqon+UvPYqpx3mHc8cV3QemSBTXwkG8gSQSK6UKvXcE/DcleU3+A59XTUHyCvZ5qGy8xVAg==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000963", - "electron-to-chromium": "^1.3.127", - "node-releases": "^1.1.17" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - }, - "camelcase": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30000967", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000967.tgz", - "integrity": "sha512-rUBIbap+VJfxTzrM4akJ00lkvVb5/n5v3EGXfWzSH5zT8aJmGzjA8HWhJ4U6kCpzxozUSnB+yvAYDRPY6mRpgQ==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", - "dev": true, - "optional": true, - "requires": { - "delayed-stream": "~1.0.0" - }, - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "optional": true - } - } - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz", - "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.0", - "parse-json": "^4.0.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "electron-to-chromium": { - "version": "1.3.133", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.133.tgz", - "integrity": "sha512-lyoC8aoqbbDqsprb6aPdt9n3DpOZZzdz/T4IZKsR0/dkZIxnJVUjjcpOSwA66jPRIOyDAamCTAUqweU05kKNSg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", - "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", - "dev": true - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", - "dev": true - }, - "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "dev": true, - "requires": { - "estraverse": "^4.0.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-glob": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", - "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - } - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", - "dev": true - }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "dependencies": { - "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", - "dev": true, - "optional": true - }, - "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "dev": true, - "optional": true, - "requires": { - "mime-db": "~1.37.0" - } - } - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true, - "optional": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "optional": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "optional": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "dev": true, - "optional": true - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "inquirer": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", - "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.11", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "less": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", - "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", - "dev": true, - "requires": { - "clone": "^2.1.2", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.4.1", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", - "request": "^2.83.0", - "source-map": "~0.6.0" - }, - "dependencies": { - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true, - "optional": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true, - "optional": true - }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true, - "optional": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "optional": true, - "requires": { - "prr": "~1.0.1" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "optional": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true, - "optional": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true, - "optional": true - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true, - "optional": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "optional": true - }, - "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", - "dev": true, - "optional": true - }, - "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "dev": true, - "optional": true, - "requires": { - "mime-db": "~1.37.0" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true, - "optional": true - }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dev": true, - "optional": true, - "requires": { - "asap": "~2.0.3" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true, - "optional": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true, - "optional": true - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "optional": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true, - "optional": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - } - } - }, - "less-plugin-clean-css": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/less-plugin-clean-css/-/less-plugin-clean-css-1.5.1.tgz", - "integrity": "sha1-zFeveqM5iVflbezr5jy2DCNClwM=", - "dev": true, - "requires": { - "clean-css": "^3.0.1" - }, - "dependencies": { - "clean-css": { - "version": "3.4.28", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", - "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", - "dev": true, - "requires": { - "commander": "2.8.x", - "source-map": "0.4.x" - } - }, - "commander": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", - "dev": true, - "requires": { - "graceful-readlink": ">= 1.0.0" - } - }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "lesshint": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/lesshint/-/lesshint-6.3.6.tgz", - "integrity": "sha512-yFUAwNAMkUzKRO0qa6d0N1xXW66RFuipFB3VVICwQB6aIyh9y11wUpcMp6e3adL46+0aGJIkDW6z12c+bWaLgA==", - "dev": true, - "requires": { - "commander": "^2.8.0", - "cosmiconfig": "^5.0.1", - "globby": "^8.0.0", - "lodash.merge": "^4.0.1", - "lodash.orderby": "^4.6.0", - "postcss": "^7.0.14", - "postcss-less": "^3.1.1", - "postcss-selector-parser": "^5.0.0", - "postcss-values-parser": "^2.0.0", - "strip-json-comments": "^2.0.0" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", - "dev": true - }, - "lodash.orderby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.orderby/-/lodash.orderby-4.6.0.tgz", - "integrity": "sha1-5pfwTOXXhSL1TZM4syuBozk+TrM=", - "dev": true - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "merge2": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", - "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-releases": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.19.tgz", - "integrity": "sha512-SH/B4WwovHbulIALsQllAVwqZZD1kPmKCqrhGfR29dXjLAVZMHvBjD3S6nL9D/J9QkmZ1R92/0wCMDKXUUvyyA==", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "optional": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - } - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.16.tgz", - "integrity": "sha512-MOo8zNSlIqh22Uaa3drkdIAgUGEL+AD1ESiSdmElLUmE2uVDo1QloiT/IfW9qRw8Gw+Y/w69UVMGwbufMSftxA==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-cli-simple": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-cli-simple/-/postcss-cli-simple-3.0.0.tgz", - "integrity": "sha512-bBknN0S66Zt4MIEeei6nTr4E4wr6NxuZBNE4L15p8CdlMCJWxOn3hIlnsfGz7HXVKGSja9+qs18kk3mzrMSrKw==", - "dev": true, - "requires": { - "async": "~2", - "postcss": "~5 || ~6 || ~7", - "yargs-parser": "~11" - }, - "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "dev": true, - "requires": { - "lodash": "^4.17.10" - } - }, - "postcss": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", - "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "postcss-less": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz", - "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==", - "dev": true, - "requires": { - "postcss": "^7.0.14" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "postcss-values-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", - "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", - "dev": true, - "requires": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - }, - "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/table/-/table-5.3.3.tgz", - "integrity": "sha512-3wUNCgdWX6PNpOe3amTTPWPuF6VGvgzjKCaO1snFj0z7Y3mUPWf5+zDtxUVGispJkDECPmR29wbzh6bVMOHbcw==", - "dev": true, - "requires": { - "ajv": "^6.9.1", - "lodash": "^4.17.11", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "optional": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", - "dev": true, - "optional": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true, - "optional": true - } - } - }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - } - } -} diff --git a/package.json b/package.json index 1bbe6cf8ae..94bf01f909 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "eslint": "5.16.0", "less": "3.9.0", "less-plugin-clean-css": "1.5.1", - "lesshint": "^6.3.6", + "lesshint": "6.3.6", "postcss-cli": "6.1.2" }, "browserslist": [ From 96b412bb875f534e37b9af3d9e71842a2dadb6e0 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 17 May 2019 13:41:01 +0100 Subject: [PATCH 027/220] Stop running hooks on pr merge (#6963) * Stop running hooks on pr merge * Remove SSH_ORIGINAL_COMMAND from the pushing environment --- models/helper_environment.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models/helper_environment.go b/models/helper_environment.go index 283584cc52..737a9a68c3 100644 --- a/models/helper_environment.go +++ b/models/helper_environment.go @@ -19,6 +19,8 @@ func PushingEnvironment(doer *User, repo *Repository) []string { sig := doer.NewGitSig() + // We should add "SSH_ORIGINAL_COMMAND=gitea-internal", + // once we have hook and pushing infrastructure working correctly return append(os.Environ(), "GIT_AUTHOR_NAME="+sig.Name, "GIT_AUTHOR_EMAIL="+sig.Email, @@ -30,7 +32,6 @@ func PushingEnvironment(doer *User, repo *Repository) []string { EnvPusherName+"="+doer.Name, EnvPusherID+"="+fmt.Sprintf("%d", doer.ID), ProtectedBranchRepoID+"="+fmt.Sprintf("%d", repo.ID), - "SSH_ORIGINAL_COMMAND=gitea-internal", ) } From c385dcc26b0da7fc1c245a1da316551cb6585ad3 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 18 May 2019 10:37:49 +0800 Subject: [PATCH 028/220] Fix index produces problem when issues/pulls deleted (#6973) * fix index produces problem when issues/pulls deleted * fix tests * fix tests * fix tests --- models/issue.go | 29 ++++++++++++++++++++++++++++- models/repo.go | 7 ------- routers/api/v1/repo/pull.go | 8 +++++++- routers/repo/pull.go | 8 +++++++- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/models/issue.go b/models/issue.go index f9394594be..999bd2f7a9 100644 --- a/models/issue.go +++ b/models/issue.go @@ -5,6 +5,7 @@ package models import ( + "errors" "fmt" "path" "regexp" @@ -1015,9 +1016,35 @@ type NewIssueOptions struct { IsPull bool } +// GetMaxIndexOfIssue returns the max index on issue +func GetMaxIndexOfIssue(repoID int64) (int64, error) { + return getMaxIndexOfIssue(x, repoID) +} + +func getMaxIndexOfIssue(e Engine, repoID int64) (int64, error) { + var ( + maxIndex int64 + has bool + err error + ) + + has, err = e.SQL("SELECT COALESCE((SELECT MAX(`index`) FROM issue WHERE repo_id = ?),0)", repoID).Get(&maxIndex) + if err != nil { + return 0, err + } else if !has { + return 0, errors.New("Retrieve Max index from issue failed") + } + return maxIndex, nil +} + func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { opts.Issue.Title = strings.TrimSpace(opts.Issue.Title) - opts.Issue.Index = opts.Repo.NextIssueIndex() + + maxIndex, err := getMaxIndexOfIssue(e, opts.Issue.RepoID) + if err != nil { + return err + } + opts.Issue.Index = maxIndex + 1 if opts.Issue.MilestoneID > 0 { milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID) diff --git a/models/repo.go b/models/repo.go index b37120236f..3283223d5b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -687,13 +687,6 @@ func (repo *Repository) getUsersWithAccessMode(e Engine, mode AccessMode) (_ []* return users, nil } -// NextIssueIndex returns the next issue index -// FIXME: should have a mutex to prevent producing same index for two issues that are created -// closely enough. -func (repo *Repository) NextIssueIndex() int64 { - return int64(repo.NumIssues+repo.NumPulls) + 1 -} - var ( descPattern = regexp.MustCompile(`https?://\S+`) ) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index dda8387913..f53ab4b8f3 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -251,9 +251,15 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption deadlineUnix = util.TimeStamp(form.Deadline.Unix()) } + maxIndex, err := models.GetMaxIndexOfIssue(repo.ID) + if err != nil { + ctx.ServerError("GetPatch", err) + return + } + prIssue := &models.Issue{ RepoID: repo.ID, - Index: repo.NextIssueIndex(), + Index: maxIndex + 1, Title: form.Title, PosterID: ctx.User.ID, Poster: ctx.User, diff --git a/routers/repo/pull.go b/routers/repo/pull.go index d1e2f0b0b3..412750dd55 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -946,9 +946,15 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) return } + maxIndex, err := models.GetMaxIndexOfIssue(repo.ID) + if err != nil { + ctx.ServerError("GetPatch", err) + return + } + pullIssue := &models.Issue{ RepoID: repo.ID, - Index: repo.NextIssueIndex(), + Index: maxIndex + 1, Title: form.Title, PosterID: ctx.User.ID, Poster: ctx.User, From 8de76b6e646e91c41143242dc0a8d3ae05b35023 Mon Sep 17 00:00:00 2001 From: David Schneiderbauer Date: Sat, 18 May 2019 15:40:05 +0200 Subject: [PATCH 029/220] fix u2f registrationlist ToRegistrations() method (#6980) --- models/u2f.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/u2f.go b/models/u2f.go index 200d417fcc..1224b4a5fb 100644 --- a/models/u2f.go +++ b/models/u2f.go @@ -48,7 +48,7 @@ type U2FRegistrationList []*U2FRegistration // ToRegistrations will convert all U2FRegistrations to u2f.Registrations func (list U2FRegistrationList) ToRegistrations() []u2f.Registration { - regs := make([]u2f.Registration, len(list)) + regs := make([]u2f.Registration, 0, len(list)) for _, reg := range list { r, err := reg.Parse() if err != nil { From 02542a2c15585002c673a9e3eb1ced036c8431d7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 May 2019 20:43:43 +0800 Subject: [PATCH 030/220] fix missing repo description when migrating (#7000) --- modules/migrations/migrate.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index d72c869626..ac55a2e727 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -76,6 +76,9 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } repo.IsPrivate = opts.Private repo.IsMirror = opts.Mirror + if opts.Description != "" { + repo.Description = opts.Description + } log.Trace("migrating git data") if err := uploader.CreateRepo(repo, opts.Wiki); err != nil { return err From 1f84970de0e510060e608eb94f7aaabc2378eef3 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 21 May 2019 15:20:17 +0800 Subject: [PATCH 031/220] Make webhook http connections resuable (#6976) * make http connections resuable * add error handler * fix lint --- models/webhook.go | 98 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/models/webhook.go b/models/webhook.go index 48c4de2ea3..7a28e37958 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -13,11 +13,12 @@ import ( "encoding/json" "fmt" "io/ioutil" + "net" "net/http" + "net/url" "strings" "time" - "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -753,47 +754,66 @@ func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payl return nil } -func (t *HookTask) deliver() { +func (t *HookTask) deliver() error { t.IsDelivered = true - timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second + var req *http.Request + var err error - var req *httplib.Request switch t.HTTPMethod { case "": log.Info("HTTP Method for webhook %d empty, setting to POST as default", t.ID) fallthrough case http.MethodPost: - req = httplib.Post(t.URL) switch t.ContentType { case ContentTypeJSON: - req = req.Header("Content-Type", "application/json").Body(t.PayloadContent) + req, err = http.NewRequest("POST", t.URL, strings.NewReader(t.PayloadContent)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") case ContentTypeForm: - req.Param("payload", t.PayloadContent) + var forms = url.Values{ + "payload": []string{t.PayloadContent}, + } + + req, err = http.NewRequest("POST", t.URL, strings.NewReader(forms.Encode())) + if err != nil { + + return err + } } case http.MethodGet: - req = httplib.Get(t.URL).Param("payload", t.PayloadContent) + u, err := url.Parse(t.URL) + if err != nil { + return err + } + vals := u.Query() + vals["payload"] = []string{t.PayloadContent} + u.RawQuery = vals.Encode() + req, err = http.NewRequest("GET", u.String(), nil) + if err != nil { + return err + } default: - log.Error("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod) - return + return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod) } - req = req.SetTimeout(timeout, timeout). - Header("X-Gitea-Delivery", t.UUID). - Header("X-Gitea-Event", string(t.EventType)). - Header("X-Gitea-Signature", t.Signature). - Header("X-Gogs-Delivery", t.UUID). - Header("X-Gogs-Event", string(t.EventType)). - Header("X-Gogs-Signature", t.Signature). - HeaderWithSensitiveCase("X-GitHub-Delivery", t.UUID). - HeaderWithSensitiveCase("X-GitHub-Event", string(t.EventType)). - SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}) + req.Header.Add("X-Gitea-Delivery", t.UUID) + req.Header.Add("X-Gitea-Event", string(t.EventType)) + req.Header.Add("X-Gitea-Signature", t.Signature) + req.Header.Add("X-Gogs-Delivery", t.UUID) + req.Header.Add("X-Gogs-Event", string(t.EventType)) + req.Header.Add("X-Gogs-Signature", t.Signature) + req.Header["X-GitHub-Delivery"] = []string{t.UUID} + req.Header["X-GitHub-Event"] = []string{string(t.EventType)} // Record delivery information. t.RequestInfo = &HookRequest{ Headers: map[string]string{}, } - for k, vals := range req.Headers() { + for k, vals := range req.Header { t.RequestInfo.Headers[k] = strings.Join(vals, ",") } @@ -830,10 +850,10 @@ func (t *HookTask) deliver() { } }() - resp, err := req.Response() + resp, err := webhookHTTPClient.Do(req) if err != nil { t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err) - return + return err } defer resp.Body.Close() @@ -847,9 +867,10 @@ func (t *HookTask) deliver() { p, err := ioutil.ReadAll(resp.Body) if err != nil { t.ResponseInfo.Body = fmt.Sprintf("read body: %s", err) - return + return err } t.ResponseInfo.Body = string(p) + return nil } // DeliverHooks checks and delivers undelivered hooks. @@ -864,7 +885,10 @@ func DeliverHooks() { // Update hook task status. for _, t := range tasks { - t.deliver() + if err = t.deliver(); err != nil { + log.Error("deliver: %v", err) + continue + } } // Start listening on new hook requests. @@ -884,12 +908,34 @@ func DeliverHooks() { continue } for _, t := range tasks { - t.deliver() + if err = t.deliver(); err != nil { + log.Error("deliver: %v", err) + } } } } +var webhookHTTPClient *http.Client + // InitDeliverHooks starts the hooks delivery thread func InitDeliverHooks() { + timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second + + webhookHTTPClient = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}, + Dial: func(netw, addr string) (net.Conn, error) { + conn, err := net.DialTimeout(netw, addr, timeout) + if err != nil { + return nil, err + } + + conn.SetDeadline(time.Now().Add(timeout)) + return conn, nil + + }, + }, + } + go DeliverHooks() } From 84bfd005377d0693a4ebd52fa305f57fba6be989 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 21 May 2019 20:11:09 +0100 Subject: [PATCH 032/220] Fix TestSearchRepo by waiting till indexing is done (#7004) * Fix TestSearchRepo by waiting till indexing is done * Update integrations/repo_search_test.go * changes as per @mrsdizzie --- integrations/repo_search_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/integrations/repo_search_test.go b/integrations/repo_search_test.go index d7d07ca8d0..3422aeaa12 100644 --- a/integrations/repo_search_test.go +++ b/integrations/repo_search_test.go @@ -5,8 +5,12 @@ package integrations import ( + "log" "net/http" "testing" + "time" + + "code.gitea.io/gitea/models" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" @@ -27,6 +31,27 @@ func resultFilenames(t testing.TB, doc *HTMLDoc) []string { func TestSearchRepo(t *testing.T) { prepareTestEnv(t) + repo, err := models.GetRepositoryByOwnerAndName("user2", "repo1") + assert.NoError(t, err) + + models.UpdateRepoIndexer(repo) + + log.Printf("Waiting for indexing\n") + + i := 0 + for i < 60 { + if repo.IndexerStatus != nil && len(repo.IndexerStatus.CommitSha) != 0 { + break + } + time.Sleep(1 * time.Second) + i++ + } + if i < 60 { + log.Printf("Indexing took: %ds\n", i) + } else { + log.Printf("Waited the limit: %ds for indexing, continuing\n", i) + } + req := NewRequestf(t, "GET", "/user2/repo1/search?q=Description&page=1") resp := MakeRequest(t, req, http.StatusOK) From 0d69dfb4ca102186e68227dfca9eea1ce09e445b Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 21 May 2019 22:32:52 +0100 Subject: [PATCH 033/220] Do not attempt to return blob on submodule (#6996) --- modules/git/tree_blob.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/git/tree_blob.go b/modules/git/tree_blob.go index 14237df6e8..eb8ddd0946 100644 --- a/modules/git/tree_blob.go +++ b/modules/git/tree_blob.go @@ -60,7 +60,7 @@ func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) { return nil, err } - if !entry.IsDir() { + if !entry.IsDir() && !entry.IsSubModule() { return entry.Blob(), nil } From 6eb53ac570ab9af51fc9cbd79f1db782edce57e0 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Tue, 21 May 2019 20:48:34 -0500 Subject: [PATCH 034/220] Fix documentation on Oauth2.Enable flag (#7011) * Fix documentation on Oauth2.Enable flag The docs list this as ENABLED, but in the source code it's ENABLE, meaning following the docs leads to confusion. * Update sample config for oauth2.ENABLE --- custom/conf/app.ini.sample | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 599569464c..3ce7268d9d 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -698,7 +698,7 @@ DEFAULT_MAX_BLOB_SIZE = 10485760 [oauth2] ; Enables OAuth2 provider -ENABLED = true +ENABLE = true ; Lifetime of an OAuth2 access token in seconds ACCESS_TOKEN_EXPIRATION_TIME=3600 ; Lifetime of an OAuth2 access token in hours diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index f40d35cdba..882f8a8a92 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -419,7 +419,7 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` ## OAuth2 (`oauth2`) -- `ENABLED`: **true**: Enables OAuth2 provider. +- `ENABLE`: **true**: Enables OAuth2 provider. - `ACCESS_TOKEN_EXPIRATION_TIME`: **3600**: Lifetime of an OAuth2 access token in seconds - `REFRESH_TOKEN_EXPIRATION_TIME`: **730**: Lifetime of an OAuth2 access token in hours - `INVALIDATE_REFRESH_TOKEN`: **false**: Check if refresh token got already used From 54bd63cd5c5645202625368c185b645c7771f687 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 23 May 2019 17:00:07 +0100 Subject: [PATCH 035/220] Change UpdateRepoIndex api to include watchers (#7012) * Change UpdateRepoIndex api to include watchers * Add timeout --- integrations/repo_search_test.go | 23 +++++++---------------- models/repo_indexer.go | 21 +++++++++++++-------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/integrations/repo_search_test.go b/integrations/repo_search_test.go index 3422aeaa12..282caa707e 100644 --- a/integrations/repo_search_test.go +++ b/integrations/repo_search_test.go @@ -5,7 +5,6 @@ package integrations import ( - "log" "net/http" "testing" "time" @@ -34,22 +33,14 @@ func TestSearchRepo(t *testing.T) { repo, err := models.GetRepositoryByOwnerAndName("user2", "repo1") assert.NoError(t, err) - models.UpdateRepoIndexer(repo) + waiter := make(chan error, 1) + models.UpdateRepoIndexer(repo, waiter) - log.Printf("Waiting for indexing\n") - - i := 0 - for i < 60 { - if repo.IndexerStatus != nil && len(repo.IndexerStatus.CommitSha) != 0 { - break - } - time.Sleep(1 * time.Second) - i++ - } - if i < 60 { - log.Printf("Indexing took: %ds\n", i) - } else { - log.Printf("Waited the limit: %ds for indexing, continuing\n", i) + select { + case err := <-waiter: + assert.NoError(t, err) + case <-time.After(1 * time.Minute): + assert.Fail(t, "UpdateRepoIndexer took too long") } req := NewRequestf(t, "GET", "/user2/repo1/search?q=Description&page=1") diff --git a/models/repo_indexer.go b/models/repo_indexer.go index 9a7daa0ff8..140ec66c03 100644 --- a/models/repo_indexer.go +++ b/models/repo_indexer.go @@ -57,8 +57,9 @@ func (repo *Repository) updateIndexerStatus(sha string) error { } type repoIndexerOperation struct { - repo *Repository - deleted bool + repo *Repository + deleted bool + watchers []chan<- error } var repoIndexerOperationQueue chan repoIndexerOperation @@ -312,26 +313,30 @@ func nonGenesisChanges(repo *Repository, revision string) (*repoChanges, error) func processRepoIndexerOperationQueue() { for { op := <-repoIndexerOperationQueue + var err error if op.deleted { - if err := indexer.DeleteRepoFromIndexer(op.repo.ID); err != nil { + if err = indexer.DeleteRepoFromIndexer(op.repo.ID); err != nil { log.Error("DeleteRepoFromIndexer: %v", err) } } else { - if err := updateRepoIndexer(op.repo); err != nil { + if err = updateRepoIndexer(op.repo); err != nil { log.Error("updateRepoIndexer: %v", err) } } + for _, watcher := range op.watchers { + watcher <- err + } } } // DeleteRepoFromIndexer remove all of a repository's entries from the indexer -func DeleteRepoFromIndexer(repo *Repository) { - addOperationToQueue(repoIndexerOperation{repo: repo, deleted: true}) +func DeleteRepoFromIndexer(repo *Repository, watchers ...chan<- error) { + addOperationToQueue(repoIndexerOperation{repo: repo, deleted: true, watchers: watchers}) } // UpdateRepoIndexer update a repository's entries in the indexer -func UpdateRepoIndexer(repo *Repository) { - addOperationToQueue(repoIndexerOperation{repo: repo, deleted: false}) +func UpdateRepoIndexer(repo *Repository, watchers ...chan<- error) { + addOperationToQueue(repoIndexerOperation{repo: repo, deleted: false, watchers: watchers}) } func addOperationToQueue(op repoIndexerOperation) { From 181b7c99eddb373b4415b160dde9109cd4191878 Mon Sep 17 00:00:00 2001 From: suisseWalter <42143099+suisseWalter@users.noreply.github.com> Date: Thu, 23 May 2019 19:12:59 +0200 Subject: [PATCH 036/220] Added Note about arm7 version to doc (#6983) Appended the Troubleshooting section with a subsection about the problems with the arm7 version and the recommendation to switch to arm6. --- docs/content/doc/installation/from-binary.en-us.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/content/doc/installation/from-binary.en-us.md b/docs/content/doc/installation/from-binary.en-us.md index 7e795029db..12e38e8096 100644 --- a/docs/content/doc/installation/from-binary.en-us.md +++ b/docs/content/doc/installation/from-binary.en-us.md @@ -143,6 +143,15 @@ bind: address already in use` Gitea needs to be started on another free port. Th is possible using `./gitea web -p $PORT`. It's possible another instance of Gitea is already running. +### Running Gitea on Raspbian + +As of v1.8, there is a problem with the arm7 version of Gitea and it doesn't run on Raspberry Pi and similar devices. + +It is therefore recommended to switch to the arm6 version which has been tested and shown to work on Raspberry Pi and similar devices. + + ### Git error after updating to a new version of Gitea If the binary file name has been changed during the update to a new version of Gitea, From d5a98a29690e13f717fb72e8635fbea57e58f546 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 24 May 2019 12:15:26 +0800 Subject: [PATCH 037/220] Add support of utf8mb4 for mysql (#6992) --- custom/conf/app.ini.sample | 3 +++ .../doc/advanced/config-cheat-sheet.en-us.md | 1 + .../doc/advanced/config-cheat-sheet.zh-cn.md | 3 ++- models/models.go | 9 +++++---- modules/auth/user_form.go | 1 + options/locale/locale_en-US.ini | 3 ++- public/js/index.js | 6 +++--- routers/install.go | 1 + templates/install.tmpl | 17 ++++++++++++++++- 9 files changed, 34 insertions(+), 10 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 3ce7268d9d..547bc9e935 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -260,6 +260,9 @@ PASSWD = ; For Postgres, either "disable" (default), "require", or "verify-full" ; For MySQL, either "false" (default), "true", or "skip-verify" SSL_MODE = disable +; For MySQL only, either "utf8" or "utf8mb4", default is "utf8". +; NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. +CHARSET = utf8 ; For "sqlite3" and "tidb", use an absolute path when you start gitea as service PATH = data/gitea.db ; For "sqlite3" only. Query timeout diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 882f8a8a92..9b9578ca48 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -160,6 +160,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `USER`: **root**: Database username. - `PASSWD`: **\**: Database user password. Use \`your password\` for quoting if you use special characters in the password. - `SSL_MODE`: **disable**: For PostgreSQL and MySQL only. +- `CHARSET`: **utf8**: For MySQL only, either "utf8" or "utf8mb4", default is "utf8". NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. - `PATH`: **data/gitea.db**: For SQLite3 only, the database file path. - `LOG_SQL`: **true**: Log the executed SQL. - `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 021233f2d2..4f34e0b905 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -78,7 +78,8 @@ menu: - `NAME`: 数据库名称。 - `USER`: 数据库用户名。 - `PASSWD`: 数据库用户密码。 -- `SSL_MODE`: PostgreSQL数据库是否启用SSL模式。 +- `SSL_MODE`: MySQL 或 PostgreSQL数据库是否启用SSL模式。 +- `CHARSET`: **utf8**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。 - `PATH`: Tidb 或者 SQLite3 数据文件存放路径。 - `LOG_SQL`: **true**: 显示生成的SQL,默认为真。 diff --git a/models/models.go b/models/models.go index c7e58737ed..85318af870 100644 --- a/models/models.go +++ b/models/models.go @@ -59,8 +59,8 @@ var ( // DbCfg holds the database settings DbCfg struct { - Type, Host, Name, User, Passwd, Path, SSLMode string - Timeout int + Type, Host, Name, User, Passwd, Path, SSLMode, Charset string + Timeout int } // EnableSQLite3 use SQLite3 @@ -160,6 +160,7 @@ func LoadConfigs() { DbCfg.Passwd = sec.Key("PASSWD").String() } DbCfg.SSLMode = sec.Key("SSL_MODE").MustString("disable") + DbCfg.Charset = sec.Key("CHARSET").In("utf8", []string{"utf8", "utf8mb4"}) DbCfg.Path = sec.Key("PATH").MustString(filepath.Join(setting.AppDataPath, "gitea.db")) DbCfg.Timeout = sec.Key("SQLITE_TIMEOUT").MustInt(500) } @@ -222,8 +223,8 @@ func getEngine() (*xorm.Engine, error) { if tls == "disable" { // allow (Postgres-inspired) default value to work in MySQL tls = "false" } - connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%scharset=utf8&parseTime=true&tls=%s", - DbCfg.User, DbCfg.Passwd, connType, DbCfg.Host, DbCfg.Name, Param, tls) + connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%scharset=%s&parseTime=true&tls=%s", + DbCfg.User, DbCfg.Passwd, connType, DbCfg.Host, DbCfg.Name, Param, DbCfg.Charset, tls) case "postgres": connStr = getPostgreSQLConnectionString(DbCfg.Host, DbCfg.User, DbCfg.Passwd, DbCfg.Name, Param, DbCfg.SSLMode) case "mssql": diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 38ee5415d9..8b9e5877d9 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -23,6 +23,7 @@ type InstallForm struct { DbPasswd string DbName string SSLMode string + Charset string `binding:"Required;In(utf8,utf8mb4)"` DbPath string AppName string `binding:"Required" locale:"install.app_name"` diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a85221ab74..f08bc6b5a5 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -86,8 +86,9 @@ host = Host user = Username password = Password db_name = Database Name -db_helper = Note to MySQL users: please use the InnoDB storage engine and the 'utf8_general_ci' character set. +db_helper = Note to MySQL users: please use the InnoDB storage engine and if you use "utf8mb4", your InnoDB version must be greater than 5.6 . ssl_mode = SSL +charset = Charset path = Path sqlite_helper = File path for the SQLite3 database.
    Enter an absolute path if you run Gitea as a service. err_empty_db_path = The SQLite3 database path cannot be empty. diff --git a/public/js/index.js b/public/js/index.js index 96d55eca87..745a631435 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -587,15 +587,14 @@ function initInstall() { var tidbDefault = 'data/gitea_tidb'; var dbType = $(this).val(); - if (dbType === "SQLite3" || dbType === "TiDB") { + if (dbType === "SQLite3") { $('#sql_settings').hide(); $('#pgsql_settings').hide(); + $('#mysql_settings').hide(); $('#sqlite_settings').show(); if (dbType === "SQLite3" && $('#db_path').val() == tidbDefault) { $('#db_path').val(sqliteDefault); - } else if (dbType === "TiDB" && $('#db_path').val() == sqliteDefault) { - $('#db_path').val(tidbDefault); } return; } @@ -610,6 +609,7 @@ function initInstall() { $('#sql_settings').show(); $('#pgsql_settings').toggle(dbType === "PostgreSQL"); + $('#mysql_settings').toggle(dbType === "MySQL"); $.each(dbDefaults, function(_type, defaultHost) { if ($('#db_host').val() == defaultHost) { $('#db_host').val(dbDefaults[dbType]); diff --git a/routers/install.go b/routers/install.go index 28bca2b4f7..a404e96b51 100644 --- a/routers/install.go +++ b/routers/install.go @@ -150,6 +150,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) { models.DbCfg.Passwd = form.DbPasswd models.DbCfg.Name = form.DbName models.DbCfg.SSLMode = form.SSLMode + models.DbCfg.Charset = form.Charset models.DbCfg.Path = form.DbPath if (models.DbCfg.Type == "sqlite3") && diff --git a/templates/install.tmpl b/templates/install.tmpl index f45052ccd0..f8d1ef04e4 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -28,7 +28,7 @@ -
    +
    @@ -64,6 +64,21 @@
    +
    +
    + + +
    +
    +
    From a98e085031bedb53a9776031afde7073af81feaf Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Fri, 24 May 2019 10:52:05 +0300 Subject: [PATCH 038/220] Show git-notes (#6984) * Show git-notes * Make git-notes heading text localizable * Refactor git-notes data fetching to a separate function * Display the author and time of git notes * Move note bubble inside the commit bubble * Revert "Move note bubble inside the commit bubble" This reverts commit c0951fe0e3b4dea38064515546b1825c1bcf19e1. * Add test for git-notes * testing ui * Polish CSS * Apply suggestions from code review Co-Authored-By: Lauris BH --- modules/git/notes.go | 60 ++++++++++++++++++ modules/git/notes_test.go | 24 +++++++ modules/git/repo_ref_test.go | 3 +- .../28/345b214c5967bd9cdd98cc7f88f2f1ac574e02 | Bin 0 -> 85 bytes .../a4/79ead1abb694ffca26f67b09c8313b12fa2a13 | Bin 0 -> 30 bytes .../ca/6b5ddf303169a72d2a2971acde4f6eea194e5c | 4 ++ .../tests/repos/repo1_bare/refs/notes/commits | 1 + modules/templates/helper.go | 12 ++++ options/locale/locale_en-US.ini | 1 + public/css/index.css | 2 + public/less/_repository.less | 9 +++ routers/repo/commit.go | 10 +++ templates/repo/diff/page.tmpl | 21 ++++++ 13 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 modules/git/notes.go create mode 100644 modules/git/notes_test.go create mode 100644 modules/git/tests/repos/repo1_bare/objects/28/345b214c5967bd9cdd98cc7f88f2f1ac574e02 create mode 100644 modules/git/tests/repos/repo1_bare/objects/a4/79ead1abb694ffca26f67b09c8313b12fa2a13 create mode 100644 modules/git/tests/repos/repo1_bare/objects/ca/6b5ddf303169a72d2a2971acde4f6eea194e5c create mode 100644 modules/git/tests/repos/repo1_bare/refs/notes/commits diff --git a/modules/git/notes.go b/modules/git/notes.go new file mode 100644 index 0000000000..7aa5d89a79 --- /dev/null +++ b/modules/git/notes.go @@ -0,0 +1,60 @@ +// Copyright 2019 The Gitea 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 ( + "io/ioutil" + + "gopkg.in/src-d/go-git.v4/plumbing" +) + +// NotesRef is the git ref where Gitea will look for git-notes data. +// The value ("refs/notes/commits") is the default ref used by git-notes. +const NotesRef = "refs/notes/commits" + +// Note stores information about a note created using git-notes. +type Note struct { + Message []byte + Commit *Commit +} + +// GetNote retrieves the git-notes data for a given commit. +func GetNote(repo *Repository, commitID string, note *Note) error { + notes, err := repo.GetCommit(NotesRef) + if err != nil { + return err + } + + entry, err := notes.GetTreeEntryByPath(commitID) + if err != nil { + return err + } + + blob := entry.Blob() + dataRc, err := blob.DataAsync() + if err != nil { + return err + } + + defer dataRc.Close() + d, err := ioutil.ReadAll(dataRc) + if err != nil { + return err + } + note.Message = d + + commit, err := repo.gogitRepo.CommitObject(plumbing.Hash(notes.ID)) + if err != nil { + return err + } + + lastCommits, err := getLastCommitForPaths(commit, "", []string{commitID}) + if err != nil { + return err + } + note.Commit = convertCommit(lastCommits[commitID]) + + return nil +} diff --git a/modules/git/notes_test.go b/modules/git/notes_test.go new file mode 100644 index 0000000000..a954377f54 --- /dev/null +++ b/modules/git/notes_test.go @@ -0,0 +1,24 @@ +// Copyright 2019 The Gitea 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 ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetNotes(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") + bareRepo1, err := OpenRepository(bareRepo1Path) + assert.NoError(t, err) + + note := Note{} + err = GetNote(bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e) + assert.NoError(t, err) + assert.Equal(t, []byte("Note contents\n"), note.Message) + assert.Equal(t, "Vladimir Panteleev", note.Commit.Author.Name) +} diff --git a/modules/git/repo_ref_test.go b/modules/git/repo_ref_test.go index 2a3ea26a76..d32b34994c 100644 --- a/modules/git/repo_ref_test.go +++ b/modules/git/repo_ref_test.go @@ -19,13 +19,14 @@ func TestRepository_GetRefs(t *testing.T) { refs, err := bareRepo1.GetRefs() assert.NoError(t, err) - assert.Len(t, refs, 4) + assert.Len(t, refs, 5) expectedRefs := []string{ BranchPrefix + "branch1", BranchPrefix + "branch2", BranchPrefix + "master", TagPrefix + "test", + NotesRef, } for _, ref := range refs { diff --git a/modules/git/tests/repos/repo1_bare/objects/28/345b214c5967bd9cdd98cc7f88f2f1ac574e02 b/modules/git/tests/repos/repo1_bare/objects/28/345b214c5967bd9cdd98cc7f88f2f1ac574e02 new file mode 100644 index 0000000000000000000000000000000000000000..05dc4725eaa5c817fd8af3f6c047b4dc9bad3216 GIT binary patch literal 85 zcmV-b0IL6Z0V^p=O;s?nU@$Z=Ff%bxury6dGD$JEG&8YCO*Kz7HZnCdFiS}@FibQv rGE6o#Hn1==PBb$$W>`}B>f-8cQ~sY)`&P|)!q8gimzFR9EFKteb^{)W literal 0 HcmV?d00001 diff --git a/modules/git/tests/repos/repo1_bare/objects/a4/79ead1abb694ffca26f67b09c8313b12fa2a13 b/modules/git/tests/repos/repo1_bare/objects/a4/79ead1abb694ffca26f67b09c8313b12fa2a13 new file mode 100644 index 0000000000000000000000000000000000000000..35d27dcbe7a6557b8143cd5f57ee6851674b3743 GIT binary patch literal 30 mcmb= 1 diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index f08bc6b5a5..d2079415d0 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1314,6 +1314,7 @@ settings.unarchive.error = An error occured while trying to un-archive the repo. diff.browse_source = Browse Source diff.parent = parent diff.commit = commit +diff.git-notes = Notes diff.data_not_available = Diff Content Not Available diff.show_diff_stats = Show Diff Stats diff.show_split_view = Split View diff --git a/public/css/index.css b/public/css/index.css index fa449ec69f..8cea4e2c1d 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -803,6 +803,8 @@ footer .ui.left,footer .ui.right{line-height:40px} .stats-table .table-cell.tiny{height:.5em} tbody.commit-list{vertical-align:baseline} .commit-body{white-space:pre-wrap} +.git-notes.top{text-align:left} +.git-notes .commit-body{margin:0} @media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px} .ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0} } diff --git a/public/less/_repository.less b/public/less/_repository.less index 5970b366e2..9956bbce74 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -2219,6 +2219,15 @@ tbody.commit-list { white-space: pre-wrap; } +.git-notes { + &.top { + text-align: left; + } + .commit-body { + margin: 0; + } +} + @media only screen and (max-width: 767px) { .ui.stackable.menu { &.mobile--margin-between-items > .item { diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 2978eda6c0..870ff568f3 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" ) const ( @@ -246,6 +247,15 @@ func Diff(ctx *context.Context) { ctx.Data["Parents"] = parents ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", commitID) + + note := &git.Note{} + err = git.GetNote(ctx.Repo.GitRepo, commitID, note) + if err == nil { + ctx.Data["Note"] = string(templates.ToUTF8WithFallback(note.Message)) + ctx.Data["NoteCommit"] = note.Commit + ctx.Data["NoteAuthor"] = models.ValidateCommitWithEmail(note.Commit) + } + if commit.ParentCount() > 0 { ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", parents[0]) } diff --git a/templates/repo/diff/page.tmpl b/templates/repo/diff/page.tmpl index c8f5a3d9f0..c35e2a415b 100644 --- a/templates/repo/diff/page.tmpl +++ b/templates/repo/diff/page.tmpl @@ -65,6 +65,27 @@
    {{end}} {{end}} + {{if .Note}} +
    + + {{.i18n.Tr "repo.diff.git-notes"}}: + {{if .NoteAuthor}} + + {{if .NoteAuthor.FullName}} + {{.NoteAuthor.FullName}} + {{else}} + {{.NoteCommit.Author.Name}} + {{end}} + + {{else}} + {{.NoteCommit.Author.Name}} + {{end}} + {{TimeSince .NoteCommit.Author.When $.Lang}} +
    +
    +
    {{RenderNote .Note $.RepoLink $.Repository.ComposeMetas}}
    +
    + {{end}} {{end}} {{template "repo/diff/box" .}} From 6ff9349a0941a25d5f0832936dd501bc8842927c Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 24 May 2019 09:12:13 +0000 Subject: [PATCH 039/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 1 - options/locale/locale_de-DE.ini | 1 - options/locale/locale_es-ES.ini | 1 - options/locale/locale_fi-FI.ini | 1 - options/locale/locale_fr-FR.ini | 1 - options/locale/locale_id-ID.ini | 1 - options/locale/locale_it-IT.ini | 1 - options/locale/locale_ja-JP.ini | 1 - options/locale/locale_lv-LV.ini | 1 - options/locale/locale_nb-NO.ini | 1 - options/locale/locale_nl-NL.ini | 1 - options/locale/locale_pl-PL.ini | 1 - options/locale/locale_pt-BR.ini | 1 - options/locale/locale_ru-RU.ini | 1 - options/locale/locale_sv-SE.ini | 1 - options/locale/locale_uk-UA.ini | 1 - options/locale/locale_zh-CN.ini | 1 - options/locale/locale_zh-TW.ini | 1 - 18 files changed, 18 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 9c9740c1e8..bd503ac561 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -86,7 +86,6 @@ host=Hostitel user=Uživatelské jméno password=Heslo db_name=Název databáze -db_helper=Poznámka pro uživatele MySQL: použijte InnoDB engine a "utf8_general_ci" znakovou sadu. ssl_mode=SSL path=Cesta sqlite_helper=Cesta k souboru SQLite3 databáze.
    Pokud spouštíte Gitea jako službu, zadejte absolutní cestu. diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 5ab5dd39cf..4df3f16825 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -86,7 +86,6 @@ host=Host user=Benutzername password=Passwort db_name=Datenbankname -db_helper=Hinweis für MySQL-Benutzer: Bitte verwende das InnoDB-Speichersubsystem und den Zeichensatz „utf8_general_ci“. ssl_mode=SSL path=Pfad sqlite_helper=Dateipfad zur SQLite3 Datenbank.
    Gebe einen absoluten Pfad an, wenn Gitea als Service gestartet wird. diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 8fadb94a59..4853680492 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -70,7 +70,6 @@ host=Servidor user=Nombre de usuario password=Contraseña db_name=Nombre de la base de datos -db_helper=Nota para usuarios de la base de datos MySQL: por favor use el motor InnoDB y el esquema de caracteres 'utf8_general_ci'. ssl_mode=SSL path=Ruta diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 72c20e448e..1537d49608 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -70,7 +70,6 @@ host=Isäntä user=Käyttäjätunnus password=Salasana db_name=Tietokannan nimi -db_helper=Huomio MySQL-käyttäjille: käytäthän InnoDB-kantamoottoria ja 'utf8_general_ci'-merkistöä. ssl_mode=SSL path=Polku no_admin_and_disable_registration=Et voi kytkeä rekisteröintiä pois luomatta sitä ennen ylläpitotiliä. diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index a6c57d2d04..c8dbfd9839 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -86,7 +86,6 @@ host=Hôte user=Nom d'utilisateur password=Mot de passe db_name=Nom de base de données -db_helper=Note aux utilisateurs de MySQL : veuillez utiliser le moteur de stockage InnoDB et le jeu de caractères 'utf8_general_ci'. ssl_mode=SSL path=Emplacement sqlite_helper=Chemin d'accès pour la base de données SQLite3.
    Entrer un chemin absolu si vous exécutez Gitea en tant que service. diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 86a1ef8bfe..381d838834 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -73,7 +73,6 @@ host=Host user=Nama Pengguna password=Kata Sandi db_name=Nama Basis Data -db_helper=Catatan untuk pengguna MySQL: Gunakan mesin penyimpanan InnoDB dan karakter set 'utf8_general_ci'. ssl_mode=SSL path=Jalur no_admin_and_disable_registration=Anda tidak dapat menonaktifkan pendaftaran tanpa membuat akun admin. diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 6028cb2c09..a5e74f9b58 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -73,7 +73,6 @@ host=Host user=Nome utente password=Password db_name=Nome del database -db_helper=Nota agli utenti MySQL: si prega di utilizza l'engine InnoDB ed il carattere di tipo 'utf8_general_ci'. ssl_mode=SSL path=Percorso no_admin_and_disable_registration=Non puoi disabilitare l'auto-registrazione degli utenti senza creare un account amministratore. diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index e87b2c9231..b58fdf3ff5 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -86,7 +86,6 @@ host=ホスト user=ユーザー名 password=パスワード db_name=データベース名 -db_helper=MySQLユーザーへの注意: InnoDBストレージエンジンを使用し、キャラクターセットは 'utf8_general_ci' にしてください。 ssl_mode=SSL path=パス sqlite_helper=SQLite3のデータベースファイルパス。
    Giteaをサービスとして実行する場合は絶対パスを入力します。 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index bb996bddb0..87df76d789 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -86,7 +86,6 @@ host=Resursdators user=Lietotāja vārds password=Parole db_name=Datu bāzes nosaukums -db_helper=MySQL lietotājiem: izmantojiet InnoDB dzini ar rakstzīmju kopu 'utf8_general_ci'. ssl_mode=SSL path=Ceļš sqlite_helper=Faila ceļš SQLite3 datu bāzei.
    Ievadiet absolūto ceļu, ja Gitea tiek startēts kā serviss. diff --git a/options/locale/locale_nb-NO.ini b/options/locale/locale_nb-NO.ini index 2f0d8395f2..5e316bf786 100644 --- a/options/locale/locale_nb-NO.ini +++ b/options/locale/locale_nb-NO.ini @@ -86,7 +86,6 @@ host=Tjener user=Brukernavn password=Passord db_name=Databasenavn -db_helper=Merknad til MySQL brukere: Bruk InnoDB lagringsmotoren og 'utf8_general_ci' tegnsett. ssl_mode=SSL path=Bane sqlite_helper=Filbanen for SQLite3 databasen.
    angi en absolutt bane hvis du kjører Gitea som en tjeneste. diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index a78ec7b73c..7f5fd504ae 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -86,7 +86,6 @@ host=Server user=Gebruikersnaam password=Wachtwoord db_name=Database naam -db_helper=Opmerking voor MySQL-gebruikers: gebruik het InnoDB opslagsysteem en de "utf8_general_ci" tekenset. ssl_mode=SSL path=Pad sqlite_helper=Bestandspad voor de SQLite3-database.
    Vul een volledig pad in als je GItea als een service uitvoert. diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 84d866c844..75fba79d02 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -84,7 +84,6 @@ host=Serwer user=Nazwa użytkownika password=Hasło db_name=Nazwa bazy danych -db_helper=Informacja dla użytkowników MySQL: używaj silnika bazy danych InnoDB oraz zestawu znaków "utf8_general_ci". ssl_mode=SSL path=Ścieżka no_admin_and_disable_registration=Nie możesz wyłączyć możliwości samodzielnej rejestracji kont użytkowników bez stworzenia konta administratora. diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 66ada006d8..bcd7ee4dba 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -86,7 +86,6 @@ host=Servidor user=Nome de usuário password=Senha db_name=Nome do banco de dados -db_helper=Nota para usuários do MySQL: por favor, use o mecanismo de armazenamento InnoDB e o conjunto de caracteres 'utf8_general_ci'. ssl_mode=SSL path=Caminho sqlite_helper=Caminho do arquivo do banco de dados SQLite3.
    Informe um caminho absoluto se você executar o Gitea como um serviço. diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index d761e93bf4..b1e2508db5 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -86,7 +86,6 @@ host=Хост user=Имя пользователя password=Пароль db_name=Имя базы данных -db_helper=Примечание для пользователей MySQL: пожалуйста, используйте хранилище InnoDB и набор символов 'utf8_general_ci'. ssl_mode=SSL path=Путь sqlite_helper=Путь к файлу базы данных SQLite3.
    Введите абсолютный путь, если вы запускаете Gitea как службу. diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index a32854ccb5..d50e8b1c3a 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -82,7 +82,6 @@ host=Server user=Användarnamn password=Lösenord db_name=Databasens namn -db_helper=Notis för MySQL-användare: Använd InnoDB-lagringsmotorn och teckenuppsättning 'utf8_general_ci'. ssl_mode=SSL path=Filväg sqlite_helper=Sökväg för SQLite3-databasen.
    Ange en absolut sökväg om du kör Gitea som en tjänst. diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 648e5f66ef..6c5f45c5c4 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -86,7 +86,6 @@ host=Хост user=Ім'я кристувача password=Пароль db_name=Ім'я бази даних -db_helper=Примітка для користувачів MySQL: будь ласка, використовуйте InnoDB механізм зберігання і набір символів 'utf8_general_ci'. ssl_mode=SSL path=Шлях sqlite_helper=Шлях до файлу для бази даних SQLite3.
    Введіть абсолютний шлях, якщо ви запускаєте Gіtea як сервіс. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 92cac39779..5ac415460d 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -86,7 +86,6 @@ host=数据库主机 user=用户名 password=数据库用户密码 db_name=数据库名称 -db_helper=MySQL 用户注意: 请使用 InnoDB 存储引擎和 "utf8_general_ci" 字符集。 ssl_mode=SSL path=数据库文件路径 sqlite_helper=SQLite3 数据库的文件路径。
    如果以服务的方式运行 Gitea,请输入绝对路径。 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 87d3edaf94..91e42a3857 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -74,7 +74,6 @@ host=主機 user=使用者名稱 password=密碼 db_name=資料庫名稱 -db_helper=MySQL 使用者注意: 請使用 InnoDB 儲存引擎和 "utf8_general_ci" 字元集。 ssl_mode=SSL path=資料庫文件路徑 no_admin_and_disable_registration=您不能夠在未建立管理員使用者的情況下禁止註冊。 From 8cd4c2242c6c0b3f53d9bd28b4b4e2cebfe46a04 Mon Sep 17 00:00:00 2001 From: jpicht Date: Fri, 24 May 2019 18:40:45 +0200 Subject: [PATCH 040/220] Fix default for allowing new organization creation for new users (#7017) Fixed #6542 When creating users DefaultAllowCreateOrganization was ignored. Signed-off-by: Julian Picht * fix TestCreateUser_Issue5882 Signed-off-by: Julian Picht --- models/user.go | 3 +-- models/user_test.go | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/models/user.go b/models/user.go index 90ca189ef0..7c7e81830e 100644 --- a/models/user.go +++ b/models/user.go @@ -849,10 +849,9 @@ func CreateUser(u *User) (err error) { return err } u.HashPassword(u.Passwd) - u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization + u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation u.MaxRepoCreation = -1 u.Theme = setting.UI.DefaultTheme - u.AllowCreateOrganization = !setting.Admin.DisableRegularOrgCreation if _, err = sess.Insert(u); err != nil { return err diff --git a/models/user_test.go b/models/user_test.go index f0a8dbdd47..6af9752c9b 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -261,6 +261,8 @@ func TestCreateUser_Issue5882(t *testing.T) { {&User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true}, } + setting.Service.DefaultAllowCreateOrganization = true + for _, v := range tt { setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation From 61f00bc238ac045332c350ae817338be161893e7 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 24 May 2019 16:44:08 +0000 Subject: [PATCH 041/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 3 +++ options/locale/locale_pt-BR.ini | 3 +++ 2 files changed, 6 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index b58fdf3ff5..f7c2bcd31e 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -86,7 +86,9 @@ host=ホスト user=ユーザー名 password=パスワード db_name=データベース名 +db_helper=MySQLユーザーへの注意事項: InnoDBストレージエンジンを使用してください。 "utf8mb4"を使用する場合、InnoDBのバージョンは5.7以降にしてください。 ssl_mode=SSL +charset=文字セット path=パス sqlite_helper=SQLite3のデータベースファイルパス。
    Giteaをサービスとして実行する場合は絶対パスを入力します。 err_empty_db_path=SQLite3のデータベースパスを空にすることはできません。 @@ -1311,6 +1313,7 @@ settings.unarchive.error=リポジトリのアーカイブ解除でエラーが diff.browse_source=ソースを参照 diff.parent=親 diff.commit=コミット +diff.git-notes=Notes diff.data_not_available=差分はありません diff.show_diff_stats=差分情報を表示 diff.show_split_view=分割表示 diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index bcd7ee4dba..782d3a9bb9 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -86,7 +86,9 @@ host=Servidor user=Nome de usuário password=Senha db_name=Nome do banco de dados +db_helper=Informação para os usuários do MySQL: por favor use o mecanismo de armazenamento InnoDB e se você usar "utf8mb4", sua versão do InnoDB deve ser maior que 5.6. ssl_mode=SSL +charset=Charset path=Caminho sqlite_helper=Caminho do arquivo do banco de dados SQLite3.
    Informe um caminho absoluto se você executar o Gitea como um serviço. err_empty_db_path=O caminho do banco de dados SQLite3 não pode ser em branco. @@ -1311,6 +1313,7 @@ settings.unarchive.error=Um erro ocorreu enquanto estava sendo desarquivado o re diff.browse_source=Ver código fonte diff.parent=pai diff.commit=commit +diff.git-notes=Notas diff.data_not_available=Conteúdo de diff não disponível diff.show_diff_stats=Mostrar estatísticas do Diff diff.show_split_view=Visão dividida From 844f9a4bd8c5c35a9dab598442b4b3d58153f026 Mon Sep 17 00:00:00 2001 From: Marat Radchenko Date: Sat, 25 May 2019 00:21:00 +0300 Subject: [PATCH 042/220] Fix /verify LFS handler expecting wrong content-type (#7015) Fixes #6960 According to [spec][1], /verify requests must have `Accept: application/vnd.git-lfs+json` Previous code works because `git-lfs` also [violates spec and doesn't send any Accept header at all][2] For other clients that DO set `Accept: application/vnd.git-lfs+json`, addition of `Accept: application/vnd.git-lfs` either forces them to violate the spec or is ignored, depending on order in what they create header list. [1]: https://github.com/git-lfs/git-lfs/blob/master/docs/api/basic-transfers.md#verification [2]: https://github.com/git-lfs/git-lfs/issues/3662 --- modules/lfs/server.go | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/modules/lfs/server.go b/modules/lfs/server.go index 8ae6326842..7e20aa8515 100644 --- a/modules/lfs/server.go +++ b/modules/lfs/server.go @@ -22,8 +22,7 @@ import ( ) const ( - contentMediaType = "application/vnd.git-lfs" - metaMediaType = contentMediaType + "+json" + metaMediaType = "application/vnd.git-lfs+json" ) // RequestVars contain variables from the HTTP request. Variables from routing, json body decoding, and @@ -101,11 +100,10 @@ func ObjectOidHandler(ctx *context.Context) { getMetaHandler(ctx) return } - if ContentMatcher(ctx.Req) || len(ctx.Params("filename")) > 0 { - getContentHandler(ctx) - return - } - } else if ctx.Req.Method == "PUT" && ContentMatcher(ctx.Req) { + + getContentHandler(ctx) + return + } else if ctx.Req.Method == "PUT" { PutHandler(ctx) return } @@ -348,7 +346,7 @@ func VerifyHandler(ctx *context.Context) { return } - if !ContentMatcher(ctx.Req) { + if !MetaMatcher(ctx.Req) { writeStatus(ctx, 400) return } @@ -385,7 +383,6 @@ func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload boo } header := make(map[string]string) - header["Accept"] = contentMediaType if rv.Authorization == "" { //https://github.com/github/git-lfs/issues/1088 @@ -404,20 +401,20 @@ func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload boo if upload && !download { // Force client side verify action while gitea lacks proper server side verification - rep.Actions["verify"] = &link{Href: rv.VerifyLink(), Header: header} + verifyHeader := make(map[string]string) + for k, v := range header { + verifyHeader[k] = v + } + + // This is only needed to workaround https://github.com/git-lfs/git-lfs/issues/3662 + verifyHeader["Accept"] = metaMediaType + + rep.Actions["verify"] = &link{Href: rv.VerifyLink(), Header: verifyHeader} } return rep } -// ContentMatcher provides a mux.MatcherFunc that only allows requests that contain -// an Accept header with the contentMediaType -func ContentMatcher(r macaron.Request) bool { - mediaParts := strings.Split(r.Header.Get("Accept"), ";") - mt := mediaParts[0] - return mt == contentMediaType -} - // MetaMatcher provides a mux.MatcherFunc that only allows requests that contain // an Accept header with the metaMediaType func MetaMatcher(r macaron.Request) bool { From a83c80a00032093034d20cf79116f02fd72419e0 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 25 May 2019 04:38:15 -0400 Subject: [PATCH 043/220] Disable arm7 builds (#7037) * Disable arm7 builds As arm6 works on arm7 platforms with no noticeable performance difference * 386 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 718836be65..cf1a645805 100644 --- a/Makefile +++ b/Makefile @@ -335,7 +335,7 @@ release-linux: @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GO) get -u src.techknowlogick.com/xgo; \ fi - xgo -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/*' -out gitea-$(VERSION) . + xgo -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) . ifeq ($(CI),drone) cp /build/* $(DIST)/binaries endif From 5f05aa13e00eb9f8098066c81d2cd916d91e9874 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 25 May 2019 08:41:06 +0000 Subject: [PATCH 044/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 4df3f16825..2e4222c200 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -86,7 +86,9 @@ host=Host user=Benutzername password=Passwort db_name=Datenbankname +db_helper=Hinweis für MySQL-Nutzer: Es sollte die InnoDB Storage Engine verwendet werden. Wird der "utf8mb4" Zeichensatz verwendet, so sollte die InnoDB Version neuer sein als 5.6 . ssl_mode=SSL +charset=Zeichensatz path=Pfad sqlite_helper=Dateipfad zur SQLite3 Datenbank.
    Gebe einen absoluten Pfad an, wenn Gitea als Service gestartet wird. err_empty_db_path=Der SQLite3 Datenbankpfad darf nicht leer sein. @@ -595,6 +597,8 @@ form.name_pattern_not_allowed='%s' ist nicht erlaubt für Repository-Namen. need_auth=Authentifizierung zum Klonen benötigt migrate_type=Migrationstyp migrate_type_helper=Dieses Repository wird ein Mirror sein +migrate_items_wiki=Wiki +migrate_items_milestones=Meilensteine migrate_repo=Repository migrieren migrate.clone_address=Migrations- / Klon-URL migrate.clone_address_desc=Die HTTP(S)- oder „git clone“-URL eines bereits existierenden Repositorys From df2557835b2235b48d1ed979abb1a1d42607e96a Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Sat, 25 May 2019 13:46:14 +0200 Subject: [PATCH 045/220] Improve handling of non-square avatars (#7025) * Crop avatar before resizing (#1268) Signed-off-by: Rob Watson * Fix spelling error Signed-off-by: Rob Watson --- go.mod | 1 + go.sum | 2 + models/user.go | 22 +-- modules/avatar/avatar.go | 50 +++++ modules/avatar/avatar_test.go | 49 +++++ modules/avatar/testdata/avatar.jpeg | Bin 0 -> 521 bytes modules/avatar/testdata/avatar.png | Bin 0 -> 159 bytes vendor/github.com/oliamb/cutter/.gitignore | 22 +++ vendor/github.com/oliamb/cutter/.travis.yml | 6 + vendor/github.com/oliamb/cutter/LICENSE | 20 ++ vendor/github.com/oliamb/cutter/README.md | 107 +++++++++++ vendor/github.com/oliamb/cutter/cutter.go | 192 ++++++++++++++++++++ vendor/modules.txt | 2 + 13 files changed, 454 insertions(+), 19 deletions(-) create mode 100644 modules/avatar/testdata/avatar.jpeg create mode 100644 modules/avatar/testdata/avatar.png create mode 100644 vendor/github.com/oliamb/cutter/.gitignore create mode 100644 vendor/github.com/oliamb/cutter/.travis.yml create mode 100644 vendor/github.com/oliamb/cutter/LICENSE create mode 100644 vendor/github.com/oliamb/cutter/README.md create mode 100644 vendor/github.com/oliamb/cutter/cutter.go diff --git a/go.mod b/go.mod index d02765fb10..299a4b29f9 100644 --- a/go.mod +++ b/go.mod @@ -90,6 +90,7 @@ require ( github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 + github.com/oliamb/cutter v0.2.2 github.com/philhofer/fwd v1.0.0 // indirect github.com/pkg/errors v0.8.1 // indirect github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e diff --git a/go.sum b/go.sum index 6b0a59d5b5..94d332cbc9 100644 --- a/go.sum +++ b/go.sum @@ -244,6 +244,8 @@ github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc h1:z1PgdCCmYYVL0BoJT github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= +github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/models/user.go b/models/user.go index 7c7e81830e..f57c5a615d 100644 --- a/models/user.go +++ b/models/user.go @@ -6,7 +6,6 @@ package models import ( - "bytes" "container/list" "crypto/md5" "crypto/sha256" @@ -14,7 +13,6 @@ import ( "encoding/hex" "errors" "fmt" - "image" // Needed for jpeg support _ "image/jpeg" @@ -39,7 +37,6 @@ import ( "github.com/go-xorm/builder" "github.com/go-xorm/core" "github.com/go-xorm/xorm" - "github.com/nfnt/resize" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/ssh" ) @@ -457,23 +454,10 @@ func (u *User) IsPasswordSet() bool { // UploadAvatar saves custom avatar for user. // FIXME: split uploads to different subdirs in case we have massive users. func (u *User) UploadAvatar(data []byte) error { - imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data)) + m, err := avatar.Prepare(data) if err != nil { - return fmt.Errorf("DecodeConfig: %v", err) + return err } - if imgCfg.Width > setting.AvatarMaxWidth { - return fmt.Errorf("Image width is to large: %d > %d", imgCfg.Width, setting.AvatarMaxWidth) - } - if imgCfg.Height > setting.AvatarMaxHeight { - return fmt.Errorf("Image height is to large: %d > %d", imgCfg.Height, setting.AvatarMaxHeight) - } - - img, _, err := image.Decode(bytes.NewReader(data)) - if err != nil { - return fmt.Errorf("Decode: %v", err) - } - - m := resize.Resize(avatar.AvatarSize, avatar.AvatarSize, img, resize.NearestNeighbor) sess := x.NewSession() defer sess.Close() @@ -497,7 +481,7 @@ func (u *User) UploadAvatar(data []byte) error { } defer fw.Close() - if err = png.Encode(fw, m); err != nil { + if err = png.Encode(fw, *m); err != nil { return fmt.Errorf("Encode: %v", err) } diff --git a/modules/avatar/avatar.go b/modules/avatar/avatar.go index f426978b32..cf3da6df5e 100644 --- a/modules/avatar/avatar.go +++ b/modules/avatar/avatar.go @@ -5,13 +5,20 @@ package avatar import ( + "bytes" "fmt" "image" "image/color/palette" + // Enable PNG support: + _ "image/png" "math/rand" "time" + "code.gitea.io/gitea/modules/setting" + "github.com/issue9/identicon" + "github.com/nfnt/resize" + "github.com/oliamb/cutter" ) // AvatarSize returns avatar's size @@ -42,3 +49,46 @@ func RandomImageSize(size int, data []byte) (image.Image, error) { func RandomImage(data []byte) (image.Image, error) { return RandomImageSize(AvatarSize, data) } + +// Prepare accepts a byte slice as input, validates it contains an image of an +// acceptable format, and crops and resizes it appropriately. +func Prepare(data []byte) (*image.Image, error) { + imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("DecodeConfig: %v", err) + } + if imgCfg.Width > setting.AvatarMaxWidth { + return nil, fmt.Errorf("Image width is too large: %d > %d", imgCfg.Width, setting.AvatarMaxWidth) + } + if imgCfg.Height > setting.AvatarMaxHeight { + return nil, fmt.Errorf("Image height is too large: %d > %d", imgCfg.Height, setting.AvatarMaxHeight) + } + + img, _, err := image.Decode(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("Decode: %v", err) + } + + if imgCfg.Width != imgCfg.Height { + var newSize, ax, ay int + if imgCfg.Width > imgCfg.Height { + newSize = imgCfg.Height + ax = (imgCfg.Width - imgCfg.Height) / 2 + } else { + newSize = imgCfg.Width + ay = (imgCfg.Height - imgCfg.Width) / 2 + } + + img, err = cutter.Crop(img, cutter.Config{ + Width: newSize, + Height: newSize, + Anchor: image.Point{ax, ay}, + }) + if err != nil { + return nil, err + } + } + + img = resize.Resize(AvatarSize, AvatarSize, img, resize.NearestNeighbor) + return &img, nil +} diff --git a/modules/avatar/avatar_test.go b/modules/avatar/avatar_test.go index 9eff5bc2be..662d50fadd 100644 --- a/modules/avatar/avatar_test.go +++ b/modules/avatar/avatar_test.go @@ -5,8 +5,11 @@ package avatar import ( + "io/ioutil" "testing" + "code.gitea.io/gitea/modules/setting" + "github.com/stretchr/testify/assert" ) @@ -17,3 +20,49 @@ func Test_RandomImage(t *testing.T) { _, err = RandomImageSize(0, []byte("gogs@local")) assert.Error(t, err) } + +func Test_PrepareWithPNG(t *testing.T) { + setting.AvatarMaxWidth = 4096 + setting.AvatarMaxHeight = 4096 + + data, err := ioutil.ReadFile("testdata/avatar.png") + assert.NoError(t, err) + + imgPtr, err := Prepare(data) + assert.NoError(t, err) + + assert.Equal(t, 290, (*imgPtr).Bounds().Max.X) + assert.Equal(t, 290, (*imgPtr).Bounds().Max.Y) +} + +func Test_PrepareWithJPEG(t *testing.T) { + setting.AvatarMaxWidth = 4096 + setting.AvatarMaxHeight = 4096 + + data, err := ioutil.ReadFile("testdata/avatar.jpeg") + assert.NoError(t, err) + + imgPtr, err := Prepare(data) + assert.NoError(t, err) + + assert.Equal(t, 290, (*imgPtr).Bounds().Max.X) + assert.Equal(t, 290, (*imgPtr).Bounds().Max.Y) +} + +func Test_PrepareWithInvalidImage(t *testing.T) { + setting.AvatarMaxWidth = 5 + setting.AvatarMaxHeight = 5 + + _, err := Prepare([]byte{}) + assert.EqualError(t, err, "DecodeConfig: image: unknown format") +} +func Test_PrepareWithInvalidImageSize(t *testing.T) { + setting.AvatarMaxWidth = 5 + setting.AvatarMaxHeight = 5 + + data, err := ioutil.ReadFile("testdata/avatar.png") + assert.NoError(t, err) + + _, err = Prepare(data) + assert.EqualError(t, err, "Image width is too large: 10 > 5") +} diff --git a/modules/avatar/testdata/avatar.jpeg b/modules/avatar/testdata/avatar.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..892b7baf78e4f8e8066f26b9b0042bcfefab1c8a GIT binary patch literal 521 zcmb7Am$Yia{;v?mD?Qbha0-8e>%QS}i0dEq8zBLos{0d>4jt8YBB z<)iGuFa2{5BEm)<$~V@~N)02bWQ;YYs*J1akqs^c@4Ro?DK~9wz2_Onhm>;;llfwn z7Soi|@Cj-0RAy|uWX BK?nc< literal 0 HcmV?d00001 diff --git a/modules/avatar/testdata/avatar.png b/modules/avatar/testdata/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..c0f7922961601b6c812ac62b382d34574c14a4d4 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V6Od#Ih`sfV^(nyK@)?F|CfP6vY8S|xv6<2KrRD=b5UwyNotBhd1gt5g1e`0K#E=} wJ5XHI)5S4F;&Sqz|Nrfo^9~$o5bp`eWLWx`S@8b_%bg&dp00i_>zopr04tR#0RR91 literal 0 HcmV?d00001 diff --git a/vendor/github.com/oliamb/cutter/.gitignore b/vendor/github.com/oliamb/cutter/.gitignore new file mode 100644 index 0000000000..00268614f0 --- /dev/null +++ b/vendor/github.com/oliamb/cutter/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/oliamb/cutter/.travis.yml b/vendor/github.com/oliamb/cutter/.travis.yml new file mode 100644 index 0000000000..70e012b81e --- /dev/null +++ b/vendor/github.com/oliamb/cutter/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - 1.0 + - 1.1 + - tip diff --git a/vendor/github.com/oliamb/cutter/LICENSE b/vendor/github.com/oliamb/cutter/LICENSE new file mode 100644 index 0000000000..5412782c6e --- /dev/null +++ b/vendor/github.com/oliamb/cutter/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Olivier Amblet + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/oliamb/cutter/README.md b/vendor/github.com/oliamb/cutter/README.md new file mode 100644 index 0000000000..b54f9e3616 --- /dev/null +++ b/vendor/github.com/oliamb/cutter/README.md @@ -0,0 +1,107 @@ +Cutter +====== + +A Go library to crop images. + +[![Build Status](https://travis-ci.org/oliamb/cutter.png?branch=master)](https://travis-ci.org/oliamb/cutter) +[![GoDoc](https://godoc.org/github.com/oliamb/cutter?status.png)](https://godoc.org/github.com/oliamb/cutter) + +Cutter was initially developped to be able +to crop image resized using github.com/nfnt/resize. + +Usage +----- + +Read the doc on https://godoc.org/github.com/oliamb/cutter + +Import package with + +```go +import "github.com/oliamb/cutter" +``` + +Package cutter provides a function to crop image. + +By default, the original image will be cropped at the +given size from the top left corner. + +```go +croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, +}) +``` + +Most of the time, the cropped image will share some memory +with the original, so it should be used read only. You must +ask explicitely for a copy if nedded. + +```go +croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, + Options: cutter.Copy, +}) +``` + +It is possible to specify the top left position: + +```go +croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, + Anchor: image.Point{100, 100}, + Mode: cutter.TopLeft, // optional, default value +}) +``` + +The Anchor property can represents the center of the cropped image +instead of the top left corner: + +```go +croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, + Mode: cutter.Centered, +}) +``` + +The default crop use the specified dimension, but it is possible +to use Width and Heigth as a ratio instead. In this case, +the resulting image will be as big as possible to fit the asked ratio +from the anchor position. + +```go +croppedImg, err := cutter.Crop(baseImage, cutter.Config{ + Width: 4, + Height: 3, + Mode: cutter.Centered, + Options: cutter.Ratio&cutter.Copy, // Copy is useless here +}) +``` + +About resize +------------ +This lib only manage crop and won't resize image, but it works great in combination with [github.com/nfnt/resize](https://github.com/nfnt/resize) + +Contributing +------------ +I'd love to see your contributions to Cutter. If you'd like to hack on it: + +- fork the project, +- hack on it, +- ensure tests pass, +- make a pull request + +If you plan to modify the API, let's disscuss it first. + +Licensing +--------- +MIT License, Please see the file called LICENSE. + +Credits +------- +Test Picture: Gopher picture from Heidi Schuyt, http://www.flickr.com/photos/hschuyt/7674222278/, +© copyright Creative Commons(http://creativecommons.org/licenses/by-nc-sa/2.0/) + +Thanks to Urturn(http://www.urturn.com) for the time allocated to develop the library. diff --git a/vendor/github.com/oliamb/cutter/cutter.go b/vendor/github.com/oliamb/cutter/cutter.go new file mode 100644 index 0000000000..29d9d2f758 --- /dev/null +++ b/vendor/github.com/oliamb/cutter/cutter.go @@ -0,0 +1,192 @@ +/* +Package cutter provides a function to crop image. + +By default, the original image will be cropped at the +given size from the top left corner. + + croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, + }) + +Most of the time, the cropped image will share some memory +with the original, so it should be used read only. You must +ask explicitely for a copy if nedded. + + croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, + Options: Copy, + }) + +It is possible to specify the top left position: + + croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, + Anchor: image.Point{100, 100}, + Mode: TopLeft, // optional, default value + }) + +The Anchor property can represents the center of the cropped image +instead of the top left corner: + + + croppedImg, err := cutter.Crop(img, cutter.Config{ + Width: 250, + Height: 500, + Mode: Centered, + }) + +The default crop use the specified dimension, but it is possible +to use Width and Heigth as a ratio instead. In this case, +the resulting image will be as big as possible to fit the asked ratio +from the anchor position. + + croppedImg, err := cutter.Crop(baseImage, cutter.Config{ + Width: 4, + Height: 3, + Mode: Centered, + Options: Ratio, + }) +*/ +package cutter + +import ( + "image" + "image/draw" +) + +// Config is used to defined +// the way the crop should be realized. +type Config struct { + Width, Height int + Anchor image.Point // The Anchor Point in the source image + Mode AnchorMode // Which point in the resulting image the Anchor Point is referring to + Options Option +} + +// AnchorMode is an enumeration of the position an anchor can represent. +type AnchorMode int + +const ( + // TopLeft defines the Anchor Point + // as the top left of the cropped picture. + TopLeft AnchorMode = iota + // Centered defines the Anchor Point + // as the center of the cropped picture. + Centered = iota +) + +// Option flags to modify the way the crop is done. +type Option int + +const ( + // Ratio flag is use when Width and Height + // must be used to compute a ratio rather + // than absolute size in pixels. + Ratio Option = 1 << iota + // Copy flag is used to enforce the function + // to retrieve a copy of the selected pixels. + // This disable the use of SubImage method + // to compute the result. + Copy = 1 << iota +) + +// An interface that is +// image.Image + SubImage method. +type subImageSupported interface { + SubImage(r image.Rectangle) image.Image +} + +// Crop retrieves an image that is a +// cropped copy of the original img. +// +// The crop is made given the informations provided in config. +func Crop(img image.Image, c Config) (image.Image, error) { + maxBounds := c.maxBounds(img.Bounds()) + size := c.computeSize(maxBounds, image.Point{c.Width, c.Height}) + cr := c.computedCropArea(img.Bounds(), size) + cr = img.Bounds().Intersect(cr) + + if c.Options&Copy == Copy { + return cropWithCopy(img, cr) + } + if dImg, ok := img.(subImageSupported); ok { + return dImg.SubImage(cr), nil + } + return cropWithCopy(img, cr) +} + +func cropWithCopy(img image.Image, cr image.Rectangle) (image.Image, error) { + result := image.NewRGBA(cr) + draw.Draw(result, cr, img, cr.Min, draw.Src) + return result, nil +} + +func (c Config) maxBounds(bounds image.Rectangle) (r image.Rectangle) { + if c.Mode == Centered { + anchor := c.centeredMin(bounds) + w := min(anchor.X-bounds.Min.X, bounds.Max.X-anchor.X) + h := min(anchor.Y-bounds.Min.Y, bounds.Max.Y-anchor.Y) + r = image.Rect(anchor.X-w, anchor.Y-h, anchor.X+w, anchor.Y+h) + } else { + r = image.Rect(c.Anchor.X, c.Anchor.Y, bounds.Max.X, bounds.Max.Y) + } + return +} + +// computeSize retrieve the effective size of the cropped image. +// It is defined by Height, Width, and Ratio option. +func (c Config) computeSize(bounds image.Rectangle, ratio image.Point) (p image.Point) { + if c.Options&Ratio == Ratio { + // Ratio option is on, so we take the biggest size available that fit the given ratio. + if float64(ratio.X)/float64(bounds.Dx()) > float64(ratio.Y)/float64(bounds.Dy()) { + p = image.Point{bounds.Dx(), (bounds.Dx() / ratio.X) * ratio.Y} + } else { + p = image.Point{(bounds.Dy() / ratio.Y) * ratio.X, bounds.Dy()} + } + } else { + p = image.Point{ratio.X, ratio.Y} + } + return +} + +// computedCropArea retrieve the theorical crop area. +// It is defined by Height, Width, Mode and +func (c Config) computedCropArea(bounds image.Rectangle, size image.Point) (r image.Rectangle) { + min := bounds.Min + switch c.Mode { + case Centered: + rMin := c.centeredMin(bounds) + r = image.Rect(rMin.X-size.X/2, rMin.Y-size.Y/2, rMin.X-size.X/2+size.X, rMin.Y-size.Y/2+size.Y) + default: // TopLeft + rMin := image.Point{min.X + c.Anchor.X, min.Y + c.Anchor.Y} + r = image.Rect(rMin.X, rMin.Y, rMin.X+size.X, rMin.Y+size.Y) + } + return +} + +func (c *Config) centeredMin(bounds image.Rectangle) (rMin image.Point) { + if c.Anchor.X == 0 && c.Anchor.Y == 0 { + rMin = image.Point{ + X: bounds.Dx() / 2, + Y: bounds.Dy() / 2, + } + } else { + rMin = image.Point{ + X: c.Anchor.X, + Y: c.Anchor.Y, + } + } + return +} + +func min(a, b int) (r int) { + if a < b { + r = a + } else { + r = b + } + return +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 0013ea356f..0085f7bbda 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -261,6 +261,8 @@ github.com/mschoch/smat github.com/msteinert/pam # github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 github.com/nfnt/resize +# github.com/oliamb/cutter v0.2.2 +github.com/oliamb/cutter # github.com/pelletier/go-buffruneio v0.2.0 github.com/pelletier/go-buffruneio # github.com/philhofer/fwd v1.0.0 From 0c432d26fe20d3e50da566cf75fa483376ed8bef Mon Sep 17 00:00:00 2001 From: Mario Lubenka Date: Sat, 25 May 2019 15:37:44 +0200 Subject: [PATCH 046/220] Bugfix: Align comment label and actions to the right (#7024) * Bugfix: Align comment label and actions to the right Signed-off-by: Mario Lubenka * Restores relative position * CSS autofixer --- public/css/index.css | 4 ++-- public/less/_repository.less | 4 ++-- templates/repo/diff/comments.tmpl | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 8cea4e2c1d..20b4836909 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -531,11 +531,11 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px} .repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px} .repository.view.issue .comment-list .comment .content{margin-left:4em} -.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px} +.repository.view.issue .comment-list .comment .content>.header{font-weight:400;position:relative;padding:0 15px;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px;justify-content:space-between} .repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} .repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} -.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px} +.repository.view.issue .comment-list .comment .content>.header .text{padding-top:10px;padding-bottom:10px} .repository.view.issue .comment-list .comment .content .markdown{font-size:14px} .repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic} .repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5} diff --git a/public/less/_repository.less b/public/less/_repository.less index 9956bbce74..3b02b1691b 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -798,16 +798,16 @@ > .header { #avatar-arrow; font-weight: normal; - padding: auto 15px; position: relative; + padding: 0 15px; color: #767676; background-color: #f7f7f7; border-bottom: 1px solid #eeeeee; border-top-left-radius: 3px; border-top-right-radius: 3px; + justify-content: space-between; .text { - max-width: 78%; padding-top: 10px; padding-bottom: 10px; } diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index 1288886a61..08fa1d6f52 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -8,7 +8,7 @@
    {{.Poster.GetDisplayName}} {{$.root.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} -
    +
    {{if and .Review}} {{if eq .Review.Type 0}}
    From 355ab0c62c1d58200d68e30d112db398ea00297a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 26 May 2019 01:15:39 +0800 Subject: [PATCH 047/220] Fix wrong init dependency on markup extensions (#7038) * fix wrong init dependency on markup extensions --- cmd/web.go | 3 --- contrib/pr/checkout.go | 2 ++ modules/markup/markup.go | 8 ++++++++ routers/init.go | 2 ++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cmd/web.go b/cmd/web.go index 6da6ec942e..e6d0300a15 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -15,7 +15,6 @@ import ( "strings" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/routes" @@ -111,8 +110,6 @@ func runWeb(ctx *cli.Context) error { routers.GlobalInit() - external.RegisterParsers() - m := routes.NewMacaron() routes.RegisterRoutes(m) diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 7af27c2a9e..880c029510 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -20,6 +20,7 @@ import ( "strconv" "time" + "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/routes" @@ -113,6 +114,7 @@ func runPR() { log.Printf("[PR] Setting up router\n") //routers.GlobalInit() external.RegisterParsers() + markup.Init() m := routes.NewMacaron() routes.RegisterRoutes(m) diff --git a/modules/markup/markup.go b/modules/markup/markup.go index 0ea4099600..dc43b533c0 100644 --- a/modules/markup/markup.go +++ b/modules/markup/markup.go @@ -15,6 +15,14 @@ import ( func Init() { getIssueFullPattern() NewSanitizer() + + // since setting maybe changed extensions, this will reload all parser extensions mapping + extParsers = make(map[string]Parser) + for _, parser := range parsers { + for _, ext := range parser.Extensions() { + extParsers[strings.ToLower(ext)] = parser + } + } } // Parser defines an interface for parsering markup file to HTML diff --git a/routers/init.go b/routers/init.go index 88422cc6ed..cfeb928819 100644 --- a/routers/init.go +++ b/routers/init.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mailer" "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" @@ -75,6 +76,7 @@ func GlobalInit() { if setting.InstallLock { highlight.NewContext() + external.RegisterParsers() markup.Init() if err := initDBEngine(); err == nil { log.Info("ORM engine initialization successful!") From daaae2aad5b63f916826ef602c8347b6fd1e2372 Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Sat, 25 May 2019 23:18:27 +0200 Subject: [PATCH 048/220] migrations: ensure rollback on error (#7039) (#7040) --- modules/migrations/gitea.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index dcffb360e3..4e930fa831 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -68,10 +68,10 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, includeWiki bool) IsPrivate: repo.IsPrivate, Wiki: includeWiki, }) + g.repo = r if err != nil { return err } - g.repo = r g.gitRepo, err = git.OpenRepository(r.RepoPath()) return err } From 5a722ae81228bd8f169fdc4f684f89578c48b185 Mon Sep 17 00:00:00 2001 From: Mura Li Date: Sun, 26 May 2019 07:13:01 +0800 Subject: [PATCH 049/220] Timeout test commands without complicated tricks (#7020) --- .drone.yml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/.drone.yml b/.drone.yml index 662529bf2e..6d9cde5ca9 100644 --- a/.drone.yml +++ b/.drone.yml @@ -126,9 +126,8 @@ pipeline: commands: - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash - apt-get install -y git-lfs - - (sleep 1200 && (echo 'kill -ABRT $(pidof gitea) $(pidof integrations.sqlite.test)' | sh)) & - - make test-sqlite-migration - - make test-sqlite + - timeout -s ABRT 20m make test-sqlite-migration + - timeout -s ABRT 20m make test-sqlite when: event: [ push, tag, pull_request ] @@ -158,9 +157,8 @@ pipeline: commands: - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash - apt-get install -y git-lfs - - (sleep 1200 && (echo 'kill -ABRT $(pidof gitea) $(pidof integrations.test)' | sh)) & - - make test-mysql-migration - - make test-mysql + - timeout -s ABRT 20m make test-mysql-migration + - timeout -s ABRT 20m make test-mysql when: event: [ tag ] @@ -174,9 +172,8 @@ pipeline: commands: - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash - apt-get install -y git-lfs - - (sleep 1200 && (echo 'kill -ABRT $(pidof gitea) $(pidof integrations.test)' | sh)) & - - make test-mysql8-migration - - make test-mysql8 + - timeout -s ABRT 20m make test-mysql8-migration + - timeout -s ABRT 20m make test-mysql8 when: event: [ push, tag, pull_request ] @@ -190,9 +187,8 @@ pipeline: commands: - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash - apt-get install -y git-lfs - - (sleep 1200 && (echo 'kill -ABRT $(pidof gitea) $(pidof integrations.test)' | sh)) & - - make test-pgsql-migration - - make test-pgsql + - timeout -s ABRT 20m make test-pgsql-migration + - timeout -s ABRT 20m make test-pgsql when: event: [ push, tag, pull_request ] From 6c16febe4d0e66592cdf1af0c38101f463e230b7 Mon Sep 17 00:00:00 2001 From: Tekaoh <45337851+Tekaoh@users.noreply.github.com> Date: Sun, 26 May 2019 00:23:30 -0500 Subject: [PATCH 050/220] Update config-cheat-sheet.en-us.md (#7046) --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 9b9578ca48..2b94aa8da3 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -15,8 +15,8 @@ menu: # Configuration Cheat Sheet -This is a cheat sheet for the Gitea configuration file. It contains most settings -that can configured as well as their default values. +This is a cheat sheet for the Gitea configuration file. It contains most of the settings +that can be configured as well as their default values. Any changes to the Gitea configuration file should be made in `custom/conf/app.ini` or any corresponding location. When installing from a distribution, this will From 063fa9915958215fe028f1bc97afdf9f6ca2aca2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 26 May 2019 17:50:06 +0800 Subject: [PATCH 051/220] when git version >= 2.18, git command could run with git wire protocol version 2 param if enabled (#7047) --- custom/conf/app.ini.sample | 2 + .../doc/advanced/config-cheat-sheet.en-us.md | 1 + .../doc/advanced/config-cheat-sheet.zh-cn.md | 1 + modules/setting/git.go | 37 ++++++++++++------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 547bc9e935..e13f5aeeda 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -671,6 +671,8 @@ MAX_GIT_DIFF_FILES = 100 ; Arguments for command 'git gc', e.g. "--aggressive --auto" ; see more on http://git-scm.com/docs/git-gc/ GC_ARGS = +; If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1 +EnableAutoGitWireProtocol = true ; Operation timeout in seconds [git.timeout] diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 2b94aa8da3..140eb6ffb7 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -396,6 +396,7 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` - `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view. - `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view. - `GC_ARGS`: **\**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/ +- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1 ## Git - Timeout settings (`git.timeout`) - `DEFAUlT`: **360**: Git operations default timeout seconds. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 4f34e0b905..b9a16dd844 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -210,6 +210,7 @@ menu: - `CLONE`: **300**: 内部仓库间克隆的超时时间,单位秒 - `PULL`: **300**: 内部仓库间拉取的超时时间,单位秒 - `GC`: **60**: git仓库GC的超时时间,单位秒 +- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: 是否根据 Git Wire Protocol协议支持情况自动切换版本,当 git 版本在 2.18 及以上时会自动切换到版本2。为 `false` 则不切换。 ## API (`api`) diff --git a/modules/setting/git.go b/modules/setting/git.go index 8625c0e780..673bff207e 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -16,12 +16,13 @@ import ( var ( // Git settings Git = struct { - DisableDiffHighlight bool - MaxGitDiffLines int - MaxGitDiffLineCharacters int - MaxGitDiffFiles int - GCArgs []string `delim:" "` - Timeout struct { + DisableDiffHighlight bool + MaxGitDiffLines int + MaxGitDiffLineCharacters int + MaxGitDiffFiles int + GCArgs []string `delim:" "` + EnableAutoGitWireProtocol bool + Timeout struct { Default int Migrate int Mirror int @@ -30,11 +31,12 @@ var ( GC int `ini:"GC"` } `ini:"git.timeout"` }{ - DisableDiffHighlight: false, - MaxGitDiffLines: 1000, - MaxGitDiffLineCharacters: 5000, - MaxGitDiffFiles: 100, - GCArgs: []string{}, + DisableDiffHighlight: false, + MaxGitDiffLines: 1000, + MaxGitDiffLineCharacters: 5000, + MaxGitDiffFiles: 100, + GCArgs: []string{}, + EnableAutoGitWireProtocol: true, Timeout: struct { Default int Migrate int @@ -64,10 +66,19 @@ func newGit() { log.Fatal("Error retrieving git version: %v", err) } - log.Info("Git Version: %s", binVersion) - if version.Compare(binVersion, "2.9", ">=") { // Explicitly disable credential helper, otherwise Git credentials might leak git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=") } + + var format = "Git Version: %s" + var args = []interface{}{binVersion} + // Since git wire protocol has been released from git v2.18 + if Git.EnableAutoGitWireProtocol && version.Compare(binVersion, "2.18", ">=") { + git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "protocol.version=2") + format += ", Wire Protocol %s Enabled" + args = append(args, "Version 2") // for focus color + } + + log.Info(format, args...) } From c2f3938a58aaff18b51224f05a0808d70e111d81 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 26 May 2019 21:28:33 +0800 Subject: [PATCH 052/220] fix possbile mysql invalid connnection error (#7051) --- models/models.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/models/models.go b/models/models.go index 85318af870..c1d4c100d0 100644 --- a/models/models.go +++ b/models/models.go @@ -14,6 +14,7 @@ import ( "path" "path/filepath" "strings" + "time" "code.gitea.io/gitea/modules/setting" @@ -278,6 +279,11 @@ func SetEngine() (err error) { // so use log file to instead print to stdout. x.SetLogger(NewXORMLogger(setting.LogSQL)) x.ShowSQL(setting.LogSQL) + if DbCfg.Type == "mysql" { + x.SetMaxIdleConns(0) + x.SetConnMaxLifetime(3 * time.Second) + } + return nil } From f3d87da3e24606b770c84d95afeb0789f37a89bd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 27 May 2019 00:55:53 +0800 Subject: [PATCH 053/220] Revert "Bugfix: Align comment label and actions to the right (#7024)" (#7055) This reverts commit 0c432d26fe20d3e50da566cf75fa483376ed8bef. --- public/css/index.css | 4 ++-- public/less/_repository.less | 4 ++-- templates/repo/diff/comments.tmpl | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 20b4836909..8cea4e2c1d 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -531,11 +531,11 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px} .repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px} .repository.view.issue .comment-list .comment .content{margin-left:4em} -.repository.view.issue .comment-list .comment .content>.header{font-weight:400;position:relative;padding:0 15px;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px;justify-content:space-between} +.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px} .repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} .repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} -.repository.view.issue .comment-list .comment .content>.header .text{padding-top:10px;padding-bottom:10px} +.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px} .repository.view.issue .comment-list .comment .content .markdown{font-size:14px} .repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic} .repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5} diff --git a/public/less/_repository.less b/public/less/_repository.less index 3b02b1691b..9956bbce74 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -798,16 +798,16 @@ > .header { #avatar-arrow; font-weight: normal; + padding: auto 15px; position: relative; - padding: 0 15px; color: #767676; background-color: #f7f7f7; border-bottom: 1px solid #eeeeee; border-top-left-radius: 3px; border-top-right-radius: 3px; - justify-content: space-between; .text { + max-width: 78%; padding-top: 10px; padding-bottom: 10px; } diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index 08fa1d6f52..1288886a61 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -8,7 +8,7 @@
    {{.Poster.GetDisplayName}} {{$.root.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} -
    +
    {{if and .Review}} {{if eq .Review.Type 0}}
    From d67fd69474d2a67e47cbc8106c15c6d217ae8a0d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 27 May 2019 01:36:33 +0800 Subject: [PATCH 054/220] fix charset was not saved after installation finished (#7048) --- routers/install.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/routers/install.go b/routers/install.go index a404e96b51..cc8be065a8 100644 --- a/routers/install.go +++ b/routers/install.go @@ -57,6 +57,7 @@ func Install(ctx *context.Context) { form.DbPasswd = models.DbCfg.Passwd form.DbName = models.DbCfg.Name form.DbPath = models.DbCfg.Path + form.Charset = models.DbCfg.Charset ctx.Data["CurDbOption"] = "MySQL" switch models.DbCfg.Type { @@ -246,6 +247,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) { cfg.Section("database").Key("USER").SetValue(models.DbCfg.User) cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd) cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode) + cfg.Section("database").Key("CHARSET").SetValue(models.DbCfg.Charset) cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path) cfg.Section("").Key("APP_NAME").SetValue(form.AppName) From 2c412f517ae94859b1e42beb24d4bff790484f81 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 26 May 2019 22:49:54 +0100 Subject: [PATCH 055/220] Add FHS-compliant-script (#6923) --- contrib/fhs-compliant-script/gitea | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100755 contrib/fhs-compliant-script/gitea diff --git a/contrib/fhs-compliant-script/gitea b/contrib/fhs-compliant-script/gitea new file mode 100755 index 0000000000..28ce651aab --- /dev/null +++ b/contrib/fhs-compliant-script/gitea @@ -0,0 +1,42 @@ +#!/bin/bash + +######################################################################## +# This script some defaults for gitea to run in a FHS compliant manner # +######################################################################## + +# It assumes that you place this script as gitea in /usr/bin +# +# And place the original in /usr/lib/gitea with working files in /var/lib/gitea +# and main configuration in /etc/gitea/app.ini +GITEA="/usr/lib/gitea/gitea" +WORK_DIR="/var/lib/gitea" +APP_INI="/etc/gitea/app.ini" + +APP_INI_SET="" +for i in "$@"; do + case "$i" in + "-c") + APP_INI_SET=1 + ;; + "-c="*) + APP_INI_SET=1 + ;; + "--config") + APP_INI_SET=1 + ;; + "--config="*) + APP_INI_SET=1 + ;; + *) + ;; + esac +done + +if [ -z "$APP_INI_SET" ]; then + CONF_ARG="-c \"$APP_INI\"" +fi + +# Provide FHS compliant defaults to +GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" "$GITEA" $CONF_ARG "$@" + + From cf3ffebfde3eb6d76aa898a0b55249d5c3bf649e Mon Sep 17 00:00:00 2001 From: Hui Hui <0w0@loli.pet> Date: Tue, 28 May 2019 01:00:32 +0800 Subject: [PATCH 056/220] fix issuer of OTP URI should be URI-encoded. (#6634) * fix: Issuer of OTP URI should be URI-encoded. follow this link https://github.com/google/google-authenticator/wiki/Key-Uri-Format . * filter unsafe character ':' in issuer * Use Replace rather than ReplaceAll --- routers/user/setting/security_twofa.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/routers/user/setting/security_twofa.go b/routers/user/setting/security_twofa.go index 3a590f0b08..fca1151a04 100644 --- a/routers/user/setting/security_twofa.go +++ b/routers/user/setting/security_twofa.go @@ -74,11 +74,13 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool { if uri != nil { otpKey, err = otp.NewKeyFromURL(uri.(string)) } + // Filter unsafe character ':' in issuer + issuer := strings.Replace(setting.AppName+" ("+setting.Domain+")", ":", "", -1) if otpKey == nil { err = nil // clear the error, in case the URL was invalid otpKey, err = totp.Generate(totp.GenerateOpts{ SecretSize: 40, - Issuer: setting.AppName + " (" + strings.TrimRight(setting.AppURL, "/") + ")", + Issuer: issuer, AccountName: ctx.User.Name, }) if err != nil { From 9ca7fcddbb4c9aba7a3f8e84f6c63b7504837bee Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Mon, 27 May 2019 19:43:37 +0200 Subject: [PATCH 057/220] "It's all in GitHub" isn't true anymore, update the home template (#7059) NOTE: this commit only updates the english section --- templates/home.tmpl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/templates/home.tmpl b/templates/home.tmpl index 3ab8fc44e9..fa48cdc1b6 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -382,7 +382,10 @@ Open Source

    - It's all on GitHub! Join us by contributing to make this project even better. Don't be shy to be a contributor! +Go get code.gitea.io/gitea! +Join us by contributing +to make this project even better. +Don't be shy to be a contributor!

    From 69d81b656978a03ff277a611f5c3d9ef1814d001 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 27 May 2019 22:08:38 +0100 Subject: [PATCH 058/220] Handle insecure and ports in go get (#7041) * Handle insecure and ports in go get * Fix IsExternalURL for non-standard ports --- modules/context/context.go | 10 +++++++++- modules/context/repo.go | 5 ++++- modules/util/url.go | 3 ++- modules/util/util_test.go | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/modules/context/context.go b/modules/context/context.go index c7534a16cd..1699d7aecc 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -257,6 +257,13 @@ func Contexter() macaron.Handler { branchName = repo.DefaultBranch } prefix := setting.AppURL + path.Join(url.PathEscape(ownerName), url.PathEscape(repoName), "src", "branch", util.PathEscapeSegments(branchName)) + + appURL, _ := url.Parse(setting.AppURL) + + insecure := "" + if appURL.Scheme == string(setting.HTTP) { + insecure = "--insecure " + } c.Header().Set("Content-Type", "text/html") c.WriteHeader(http.StatusOK) c.Write([]byte(com.Expand(` @@ -266,7 +273,7 @@ func Contexter() macaron.Handler { - go get {GoGetImport} + go get {Insecure}{GoGetImport} `, map[string]string{ @@ -274,6 +281,7 @@ func Contexter() macaron.Handler { "CloneLink": models.ComposeHTTPSCloneURL(ownerName, repoName), "GoDocDirectory": prefix + "{/dir}", "GoDocFile": prefix + "{/dir}/{file}#L{line}", + "Insecure": insecure, }))) return } diff --git a/modules/context/repo.go b/modules/context/repo.go index f9ed9327ff..0908340879 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -188,7 +188,10 @@ func RetrieveBaseRepo(ctx *Context, repo *models.Repository) { // ComposeGoGetImport returns go-get-import meta content. func ComposeGoGetImport(owner, repo string) string { - return path.Join(setting.Domain, setting.AppSubURL, url.PathEscape(owner), url.PathEscape(repo)) + /// setting.AppUrl is guaranteed to be parse as url + appURL, _ := url.Parse(setting.AppURL) + + return path.Join(appURL.Host, setting.AppSubURL, url.PathEscape(owner), url.PathEscape(repo)) } // EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200 diff --git a/modules/util/url.go b/modules/util/url.go index 537e4c9b52..263255fcd3 100644 --- a/modules/util/url.go +++ b/modules/util/url.go @@ -52,7 +52,8 @@ func IsExternalURL(rawURL string) bool { if err != nil { return true } - if len(parsed.Host) != 0 && strings.Replace(parsed.Host, "www.", "", 1) != strings.Replace(setting.Domain, "www.", "", 1) { + appURL, _ := url.Parse(setting.AppURL) + if len(parsed.Host) != 0 && strings.Replace(parsed.Host, "www.", "", 1) != strings.Replace(appURL.Host, "www.", "", 1) { return true } return false diff --git a/modules/util/util_test.go b/modules/util/util_test.go index 3a2b4b71ff..2475065059 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -46,7 +46,7 @@ func TestURLJoin(t *testing.T) { } func TestIsExternalURL(t *testing.T) { - setting.Domain = "try.gitea.io" + setting.AppURL = "https://try.gitea.io" type test struct { Expected bool RawURL string From bd9ed96da50de283485a4e274b414b7dd1d22ba6 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 28 May 2019 07:18:40 +0100 Subject: [PATCH 059/220] Install page - Handle invalid administrator username better (#7060) * Install page - detect invalid admin username before installing * Also fix #6954 --- options/locale/locale_en-US.ini | 4 +++ routers/install.go | 48 ++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d2079415d0..a691232cff 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -94,6 +94,10 @@ sqlite_helper = File path for the SQLite3 database.
    Enter an absolute path if err_empty_db_path = The SQLite3 database path cannot be empty. no_admin_and_disable_registration = You cannot disable user self-registration without creating an administrator account. err_empty_admin_password = The administrator password cannot be empty. +err_empty_admin_email = The administrator email cannot be empty. +err_admin_name_is_reserved = Administrator Username is invalid, username is reserved +err_admin_name_pattern_not_allowed = Administrator Username is invalid, username is pattern is not allowed +err_admin_name_is_invalid = Administrator Username is invalid general_title = General Settings app_name = Site Title diff --git a/routers/install.go b/routers/install.go index cc8be065a8..c95abebea7 100644 --- a/routers/install.go +++ b/routers/install.go @@ -215,18 +215,42 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) { return } - // Check admin password. - if len(form.AdminName) > 0 && len(form.AdminPasswd) == 0 { - ctx.Data["Err_Admin"] = true - ctx.Data["Err_AdminPasswd"] = true - ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), tplInstall, form) - return - } - if form.AdminPasswd != form.AdminConfirmPasswd { - ctx.Data["Err_Admin"] = true - ctx.Data["Err_AdminPasswd"] = true - ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form) - return + // Check admin user creation + if len(form.AdminName) > 0 { + // Ensure AdminName is valid + if err := models.IsUsableUsername(form.AdminName); err != nil { + ctx.Data["Err_Admin"] = true + ctx.Data["Err_AdminName"] = true + if models.IsErrNameReserved(err) { + ctx.RenderWithErr(ctx.Tr("install.err_admin_name_is_reserved"), tplInstall, form) + return + } else if models.IsErrNamePatternNotAllowed(err) { + ctx.RenderWithErr(ctx.Tr("install.err_admin_name_pattern_not_allowed"), tplInstall, form) + return + } + ctx.RenderWithErr(ctx.Tr("install.err_admin_name_is_invalid"), tplInstall, form) + return + } + // Check Admin email + if len(form.AdminEmail) == 0 { + ctx.Data["Err_Admin"] = true + ctx.Data["Err_AdminEmail"] = true + ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_email"), tplInstall, form) + return + } + // Check admin password. + if len(form.AdminPasswd) == 0 { + ctx.Data["Err_Admin"] = true + ctx.Data["Err_AdminPasswd"] = true + ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), tplInstall, form) + return + } + if form.AdminPasswd != form.AdminConfirmPasswd { + ctx.Data["Err_Admin"] = true + ctx.Data["Err_AdminPasswd"] = true + ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form) + return + } } if form.AppURL[len(form.AppURL)-1] != '/' { From 66863ab7704c96efbbc19059d037c63e37fcd2fa Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 28 May 2019 17:41:48 +0800 Subject: [PATCH 060/220] chore: change issue mail title. (#7064) * chore: change issue mail title. Signed-off-by: Bo-Yi Wu * change to fullname method Signed-off-by: Bo-Yi Wu --- models/issue_mail.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issue_mail.go b/models/issue_mail.go index 033c094c75..16f85ba378 100644 --- a/models/issue_mail.go +++ b/models/issue_mail.go @@ -16,7 +16,7 @@ import ( ) func (issue *Issue) mailSubject() string { - return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.Name, issue.Title, issue.Index) + return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.FullName(), issue.Title, issue.Index) } // mailIssueCommentToParticipants can be used for both new issue creation and comment. From 27b271d457f875ed76fae9660338f7df1013318a Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 28 May 2019 09:44:31 +0000 Subject: [PATCH 061/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index f7c2bcd31e..beeeb848a2 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -94,6 +94,10 @@ sqlite_helper=SQLite3のデータベースファイルパス。
    Giteaをサ err_empty_db_path=SQLite3のデータベースパスを空にすることはできません。 no_admin_and_disable_registration=管理者アカウントを作成せずに、セルフ登録を無効にすることはできません。 err_empty_admin_password=管理者パスワードは空にできません。 +err_empty_admin_email=管理者のメールアドレスは空にできません。 +err_admin_name_is_reserved=管理者のユーザー名が不正です。予約済みのユーザー名です。 +err_admin_name_pattern_not_allowed=管理者のユーザー名が不正です。使用できない形式のユーザー名です。 +err_admin_name_is_invalid=管理者のユーザー名が不正です general_title=基本設定 app_name=サイトタイトル From 31557b12744410633ceb6fc12b53fb09038cee35 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 28 May 2019 11:32:41 +0100 Subject: [PATCH 062/220] Fix LFS Locks over SSH (#6999) * Fix LFS Locks over SSH * Mark test as skipped --- integrations/git_test.go | 102 ++++++++++++++++++++++------------ modules/lfs/locks.go | 115 ++++++++++++++++++++++++++++----------- routers/routes/routes.go | 2 +- 3 files changed, 150 insertions(+), 69 deletions(-) diff --git a/integrations/git_test.go b/integrations/git_test.go index ebbf04f9d0..0554f9a5ae 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -65,6 +65,10 @@ func testGit(t *testing.T, u *url.URL) { little = commitAndPush(t, littleSize, dstPath) }) t.Run("Big", func(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + return + } PrintCurrentTest(t) big = commitAndPush(t, bigSize, dstPath) }) @@ -85,10 +89,16 @@ func testGit(t *testing.T, u *url.URL) { t.Run("Little", func(t *testing.T) { PrintCurrentTest(t) littleLFS = commitAndPush(t, littleSize, dstPath) + lockFileTest(t, littleLFS, dstPath) }) t.Run("Big", func(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + return + } PrintCurrentTest(t) bigLFS = commitAndPush(t, bigSize, dstPath) + lockFileTest(t, bigLFS, dstPath) }) }) t.Run("Locks", func(t *testing.T) { @@ -105,19 +115,21 @@ func testGit(t *testing.T, u *url.URL) { resp := session.MakeRequest(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", big)) - nilResp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, bigSize, nilResp.Length) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", littleLFS)) resp = session.MakeRequest(t, req, http.StatusOK) assert.NotEqual(t, littleSize, resp.Body.Len()) assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", bigLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, bigSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + if !testing.Short() { + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", big)) + nilResp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, bigSize, nilResp.Length) + + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", bigLFS)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotEqual(t, bigSize, resp.Body.Len()) + assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + } }) t.Run("Media", func(t *testing.T) { @@ -129,17 +141,19 @@ func testGit(t *testing.T, u *url.URL) { resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", big)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Length) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", littleLFS)) resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", bigLFS)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Length) + if !testing.Short() { + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", big)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Length) + + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", bigLFS)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Length) + } }) }) @@ -177,6 +191,10 @@ func testGit(t *testing.T, u *url.URL) { little = commitAndPush(t, littleSize, dstPath) }) t.Run("Big", func(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + return + } PrintCurrentTest(t) big = commitAndPush(t, bigSize, dstPath) }) @@ -197,10 +215,17 @@ func testGit(t *testing.T, u *url.URL) { t.Run("Little", func(t *testing.T) { PrintCurrentTest(t) littleLFS = commitAndPush(t, littleSize, dstPath) + lockFileTest(t, littleLFS, dstPath) + }) t.Run("Big", func(t *testing.T) { + if testing.Short() { + return + } PrintCurrentTest(t) bigLFS = commitAndPush(t, bigSize, dstPath) + lockFileTest(t, bigLFS, dstPath) + }) }) t.Run("Locks", func(t *testing.T) { @@ -217,20 +242,21 @@ func testGit(t *testing.T, u *url.URL) { resp := session.MakeRequest(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", big)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", littleLFS)) resp = session.MakeRequest(t, req, http.StatusOK) assert.NotEqual(t, littleSize, resp.Body.Len()) assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", bigLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, bigSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + if !testing.Short() { + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", big)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Body.Len()) + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", bigLFS)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotEqual(t, bigSize, resp.Body.Len()) + assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + } }) t.Run("Media", func(t *testing.T) { PrintCurrentTest(t) @@ -241,17 +267,19 @@ func testGit(t *testing.T, u *url.URL) { resp := session.MakeRequest(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", big)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", littleLFS)) resp = session.MakeRequest(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", bigLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Body.Len()) + if !testing.Short() { + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", big)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Body.Len()) + + req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", bigLFS)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Body.Len()) + } }) }) @@ -268,15 +296,17 @@ func ensureAnonymousClone(t *testing.T, u *url.URL) { } func lockTest(t *testing.T, remote, repoPath string) { - _, err := git.NewCommand("remote").AddArguments("set-url", "origin", remote).RunInDir(repoPath) //TODO add test ssh git-lfs-creds + lockFileTest(t, "README.md", repoPath) +} + +func lockFileTest(t *testing.T, filename, repoPath string) { + _, err := git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath) + assert.NoError(t, err) + _, err = git.NewCommand("lfs").AddArguments("lock", filename).RunInDir(repoPath) assert.NoError(t, err) _, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath) assert.NoError(t, err) - _, err = git.NewCommand("lfs").AddArguments("lock", "README.md").RunInDir(repoPath) - assert.NoError(t, err) - _, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath) - assert.NoError(t, err) - _, err = git.NewCommand("lfs").AddArguments("unlock", "README.md").RunInDir(repoPath) + _, err = git.NewCommand("lfs").AddArguments("unlock", filename).RunInDir(repoPath) assert.NoError(t, err) } diff --git a/modules/lfs/locks.go b/modules/lfs/locks.go index 525a93645f..b1ca2f094a 100644 --- a/modules/lfs/locks.go +++ b/modules/lfs/locks.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" ) @@ -44,7 +45,7 @@ func checkIsValidRequest(ctx *context.Context, post bool) bool { return true } -func handleLockListOut(ctx *context.Context, lock *models.LFSLock, err error) { +func handleLockListOut(ctx *context.Context, repo *models.Repository, lock *models.LFSLock, err error) { if err != nil { if models.IsErrLFSLockNotExist(err) { ctx.JSON(200, api.LFSLockList{ @@ -57,7 +58,7 @@ func handleLockListOut(ctx *context.Context, lock *models.LFSLock, err error) { }) return } - if ctx.Repo.Repository.ID != lock.RepoID { + if repo.ID != lock.RepoID { ctx.JSON(200, api.LFSLockList{ Locks: []*api.LFSLock{}, }) @@ -75,17 +76,21 @@ func GetListLockHandler(ctx *context.Context) { } ctx.Resp.Header().Set("Content-Type", metaMediaType) - err := models.CheckLFSAccessForRepo(ctx.User, ctx.Repo.Repository, models.AccessModeRead) + rv := unpack(ctx) + + repository, err := models.GetRepositoryByOwnerAndName(rv.User, rv.Repo) if err != nil { - if models.IsErrLFSUnauthorizedAction(err) { - ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") - ctx.JSON(401, api.LFSLockError{ - Message: "You must have pull access to list locks : " + err.Error(), - }) - return - } - ctx.JSON(500, api.LFSLockError{ - Message: "unable to list lock : " + err.Error(), + log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err) + writeStatus(ctx, 404) + return + } + repository.MustOwner() + + authenticated := authenticate(ctx, repository, rv.Authorization, false) + if !authenticated { + ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") + ctx.JSON(401, api.LFSLockError{ + Message: "You must have pull access to list locks", }) return } @@ -100,19 +105,19 @@ func GetListLockHandler(ctx *context.Context) { return } lock, err := models.GetLFSLockByID(int64(v)) - handleLockListOut(ctx, lock, err) + handleLockListOut(ctx, repository, lock, err) return } path := ctx.Query("path") if path != "" { //Case where we request a specific id - lock, err := models.GetLFSLock(ctx.Repo.Repository, path) - handleLockListOut(ctx, lock, err) + lock, err := models.GetLFSLock(repository, path) + handleLockListOut(ctx, repository, lock, err) return } //If no query params path or id - lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID) + lockList, err := models.GetLFSLockByRepoID(repository.ID) if err != nil { ctx.JSON(500, api.LFSLockError{ Message: "unable to list locks : " + err.Error(), @@ -135,16 +140,36 @@ func PostLockHandler(ctx *context.Context) { } ctx.Resp.Header().Set("Content-Type", metaMediaType) + userName := ctx.Params("username") + repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git") + authorization := ctx.Req.Header.Get("Authorization") + + repository, err := models.GetRepositoryByOwnerAndName(userName, repoName) + if err != nil { + log.Debug("Could not find repository: %s/%s - %s", userName, repoName, err) + writeStatus(ctx, 404) + return + } + repository.MustOwner() + + authenticated := authenticate(ctx, repository, authorization, true) + if !authenticated { + ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") + ctx.JSON(401, api.LFSLockError{ + Message: "You must have push access to create locks", + }) + return + } + var req api.LFSLockRequest dec := json.NewDecoder(ctx.Req.Body().ReadCloser()) - err := dec.Decode(&req) - if err != nil { + if err := dec.Decode(&req); err != nil { writeStatus(ctx, 400) return } lock, err := models.CreateLFSLock(&models.LFSLock{ - Repo: ctx.Repo.Repository, + Repo: repository, Path: req.Path, Owner: ctx.User, }) @@ -178,23 +203,29 @@ func VerifyLockHandler(ctx *context.Context) { } ctx.Resp.Header().Set("Content-Type", metaMediaType) - err := models.CheckLFSAccessForRepo(ctx.User, ctx.Repo.Repository, models.AccessModeWrite) + userName := ctx.Params("username") + repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git") + authorization := ctx.Req.Header.Get("Authorization") + + repository, err := models.GetRepositoryByOwnerAndName(userName, repoName) if err != nil { - if models.IsErrLFSUnauthorizedAction(err) { - ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") - ctx.JSON(401, api.LFSLockError{ - Message: "You must have push access to verify locks : " + err.Error(), - }) - return - } - ctx.JSON(500, api.LFSLockError{ - Message: "unable to verify lock : " + err.Error(), + log.Debug("Could not find repository: %s/%s - %s", userName, repoName, err) + writeStatus(ctx, 404) + return + } + repository.MustOwner() + + authenticated := authenticate(ctx, repository, authorization, true) + if !authenticated { + ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") + ctx.JSON(401, api.LFSLockError{ + Message: "You must have push access to verify locks", }) return } //TODO handle body json cursor and limit - lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID) + lockList, err := models.GetLFSLockByRepoID(repository.ID) if err != nil { ctx.JSON(500, api.LFSLockError{ Message: "unable to list locks : " + err.Error(), @@ -223,10 +254,30 @@ func UnLockHandler(ctx *context.Context) { } ctx.Resp.Header().Set("Content-Type", metaMediaType) + userName := ctx.Params("username") + repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git") + authorization := ctx.Req.Header.Get("Authorization") + + repository, err := models.GetRepositoryByOwnerAndName(userName, repoName) + if err != nil { + log.Debug("Could not find repository: %s/%s - %s", userName, repoName, err) + writeStatus(ctx, 404) + return + } + repository.MustOwner() + + authenticated := authenticate(ctx, repository, authorization, true) + if !authenticated { + ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") + ctx.JSON(401, api.LFSLockError{ + Message: "You must have push access to delete locks", + }) + return + } + var req api.LFSLockDeleteRequest dec := json.NewDecoder(ctx.Req.Body().ReadCloser()) - err := dec.Decode(&req) - if err != nil { + if err := dec.Decode(&req); err != nil { writeStatus(ctx, 400) return } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 5a5fc518b9..d19823714b 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -923,7 +923,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/", lfs.PostLockHandler) m.Post("/verify", lfs.VerifyLockHandler) m.Post("/:lid/unlock", lfs.UnLockHandler) - }, context.RepoAssignment()) + }) m.Any("/*", func(ctx *context.Context) { ctx.NotFound("", nil) }) From 743697a549bda16508ab961ac79a8bc5bdca3bbd Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 28 May 2019 23:45:54 +0800 Subject: [PATCH 063/220] refactor: append, build variable and type switch (#4940) * refactor: append, build variable and type switch * fix: remove redundant space. --- integrations/links_test.go | 2 +- models/issue_assignees_test.go | 3 +-- models/migrations/v64.go | 4 ++-- models/user.go | 10 ++++------ modules/base/tool.go | 32 ++++++++++++++++---------------- modules/base/tool_test.go | 16 ++++++++-------- modules/templates/helper.go | 13 ++++++------- routers/user/auth_openid.go | 8 ++++---- 8 files changed, 42 insertions(+), 46 deletions(-) diff --git a/integrations/links_test.go b/integrations/links_test.go index 84be7e0591..468c8a0f21 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -110,7 +110,7 @@ func testLinksAsUser(userName string, t *testing.T) { reqAPI := NewRequestf(t, "GET", "/api/v1/users/%s/repos", userName) respAPI := MakeRequest(t, reqAPI, http.StatusOK) - var apiRepos []api.Repository + var apiRepos []*api.Repository DecodeJSON(t, respAPI, &apiRepos) var repoLinks = []string{ diff --git a/models/issue_assignees_test.go b/models/issue_assignees_test.go index 029c211a4b..d32f41737a 100644 --- a/models/issue_assignees_test.go +++ b/models/issue_assignees_test.go @@ -43,8 +43,7 @@ func TestUpdateAssignee(t *testing.T) { assert.NoError(t, err) var expectedAssignees []*User - expectedAssignees = append(expectedAssignees, user2) - expectedAssignees = append(expectedAssignees, user3) + expectedAssignees = append(expectedAssignees, user2, user3) for in, assignee := range assignees { assert.Equal(t, assignee.ID, expectedAssignees[in].ID) diff --git a/models/migrations/v64.go b/models/migrations/v64.go index 5bc7e36b51..e4a360f578 100644 --- a/models/migrations/v64.go +++ b/models/migrations/v64.go @@ -83,7 +83,7 @@ func addMultipleAssignees(x *xorm.Engine) error { return err } - allIssues := []Issue{} + allIssues := []*Issue{} if err := sess.Find(&allIssues); err != nil { return err } @@ -104,7 +104,7 @@ func addMultipleAssignees(x *xorm.Engine) error { return err } - allAssignementComments := []Comment{} + allAssignementComments := []*Comment{} if err := sess.Where("type = ?", 9).Find(&allAssignementComments); err != nil { return err } diff --git a/models/user.go b/models/user.go index f57c5a615d..9ee27ddfbd 100644 --- a/models/user.go +++ b/models/user.go @@ -13,9 +13,7 @@ import ( "encoding/hex" "errors" "fmt" - - // Needed for jpeg support - _ "image/jpeg" + _ "image/jpeg" // Needed for jpeg support "image/png" "os" "path/filepath" @@ -1622,7 +1620,7 @@ func SyncExternalUsers() { var sshKeysNeedUpdate bool // Find all users with this login type - var users []User + var users []*User x.Where("login_type = ?", LoginLDAP). And("login_source = ?", s.ID). Find(&users) @@ -1641,7 +1639,7 @@ func SyncExternalUsers() { // Search for existing user for _, du := range users { if du.LowerName == strings.ToLower(su.Username) { - usr = &du + usr = du break } } @@ -1724,7 +1722,7 @@ func SyncExternalUsers() { log.Trace("SyncExternalUsers[%s]: Deactivating user %s", s.Name, usr.Name) usr.IsActive = false - err = UpdateUserCols(&usr, "is_active") + err = UpdateUserCols(usr, "is_active") if err != nil { log.Error("SyncExternalUsers[%s]: Error deactivating user %s: %v", s.Name, usr.Name, err) } diff --git a/modules/base/tool.go b/modules/base/tool.go index 3a6e28a885..dcf9155a07 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -465,41 +465,41 @@ func Subtract(left interface{}, right interface{}) interface{} { var rleft, rright int64 var fleft, fright float64 var isInt = true - switch left := left.(type) { + switch v := left.(type) { case int: - rleft = int64(left) + rleft = int64(v) case int8: - rleft = int64(left) + rleft = int64(v) case int16: - rleft = int64(left) + rleft = int64(v) case int32: - rleft = int64(left) + rleft = int64(v) case int64: - rleft = left + rleft = v case float32: - fleft = float64(left) + fleft = float64(v) isInt = false case float64: - fleft = left + fleft = v isInt = false } - switch right := right.(type) { + switch v := right.(type) { case int: - rright = int64(right) + rright = int64(v) case int8: - rright = int64(right) + rright = int64(v) case int16: - rright = int64(right) + rright = int64(v) case int32: - rright = int64(right) + rright = int64(v) case int64: - rright = right + rright = v case float32: - fright = float64(right) + fright = float64(v) isInt = false case float64: - fright = right + fright = v isInt = false } diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go index dcaf2fcbb0..ec9bc1eb52 100644 --- a/modules/base/tool_test.go +++ b/modules/base/tool_test.go @@ -306,21 +306,21 @@ func TestFileSize(t *testing.T) { func TestSubtract(t *testing.T) { toFloat64 := func(n interface{}) float64 { - switch n := n.(type) { + switch v := n.(type) { case int: - return float64(n) + return float64(v) case int8: - return float64(n) + return float64(v) case int16: - return float64(n) + return float64(v) case int32: - return float64(n) + return float64(v) case int64: - return float64(n) + return float64(v) case float32: - return float64(n) + return float64(v) case float64: - return n + return v default: return 0.0 } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 098a642556..ef4a68add0 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -156,8 +156,7 @@ func NewFuncMap() []template.FuncMap { var path []string index := strings.LastIndex(str, "/") if index != -1 && index != len(str) { - path = append(path, str[0:index+1]) - path = append(path, str[index+1:]) + path = append(path, str[0:index+1], str[index+1:]) } else { path = append(path, str) } @@ -330,10 +329,10 @@ func ToUTF8(content string) string { return res } -// ReplaceLeft replaces all prefixes 'old' in 's' with 'new'. -func ReplaceLeft(s, old, new string) string { - oldLen, newLen, i, n := len(old), len(new), 0, 0 - for ; i < len(s) && strings.HasPrefix(s[i:], old); n++ { +// ReplaceLeft replaces all prefixes 'oldS' in 's' with 'newS'. +func ReplaceLeft(s, oldS, newS string) string { + oldLen, newLen, i, n := len(oldS), len(newS), 0, 0 + for ; i < len(s) && strings.HasPrefix(s[i:], oldS); n++ { i += oldLen } @@ -348,7 +347,7 @@ func ReplaceLeft(s, old, new string) string { j := 0 for ; j < n*newLen; j += newLen { - copy(replacement[j:j+newLen], new) + copy(replacement[j:j+newLen], newS) } copy(replacement[j:], s[i:]) diff --git a/routers/user/auth_openid.go b/routers/user/auth_openid.go index 2612f70a67..1351ca040b 100644 --- a/routers/user/auth_openid.go +++ b/routers/user/auth_openid.go @@ -359,11 +359,11 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si } } - len := setting.MinPasswordLength - if len < 256 { - len = 256 + length := setting.MinPasswordLength + if length < 256 { + length = 256 } - password, err := generate.GetRandomString(len) + password, err := generate.GetRandomString(length) if err != nil { ctx.RenderWithErr(err.Error(), tplSignUpOID, form) return From d01e728090c72ea7f8949107958aa0aa085b6f23 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 28 May 2019 16:02:55 +0000 Subject: [PATCH 064/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 2e4222c200..7082e9e8a2 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -94,6 +94,10 @@ sqlite_helper=Dateipfad zur SQLite3 Datenbank.
    Gebe einen absoluten Pfad an, err_empty_db_path=Der SQLite3 Datenbankpfad darf nicht leer sein. no_admin_and_disable_registration=Du kannst Selbst-Registrierungen nicht deaktivieren, ohne ein Administratorkonto zu erstellen. err_empty_admin_password=Das Administrator-Passwort darf nicht leer sein. +err_empty_admin_email=Die Administrator-E-Mail darf nicht leer sein. +err_admin_name_is_reserved=Administratornutzername ist ungültig, der Nutzername ist reserviert +err_admin_name_pattern_not_allowed=Administratornutzername ist ungültig, der Nutzername entspricht einem verbotenem Muster +err_admin_name_is_invalid=Administratornutzername ist ungültig general_title=Allgemeine Einstellungen app_name=Seitentitel @@ -597,8 +601,12 @@ form.name_pattern_not_allowed='%s' ist nicht erlaubt für Repository-Namen. need_auth=Authentifizierung zum Klonen benötigt migrate_type=Migrationstyp migrate_type_helper=Dieses Repository wird ein Mirror sein +migrate_items=Migrationselemente migrate_items_wiki=Wiki migrate_items_milestones=Meilensteine +migrate_items_labels=Labels +migrate_items_issues=Issues +migrate_items_pullrequests=Pull-Requests migrate_repo=Repository migrieren migrate.clone_address=Migrations- / Klon-URL migrate.clone_address_desc=Die HTTP(S)- oder „git clone“-URL eines bereits existierenden Repositorys @@ -1303,6 +1311,7 @@ settings.unarchive.error=Beim Rückgängig machen dieses Repo-Archivs trat ein F diff.browse_source=Quellcode durchsuchen diff.parent=Ursprung diff.commit=Commit +diff.git-notes=Hinweise diff.data_not_available=Keine Diff-Daten verfügbar diff.show_diff_stats=Diff-Statistik anzeigen diff.show_split_view=Geteilte Ansicht @@ -1712,7 +1721,7 @@ config.db_path=Verzeichnis config.service_config=Service-Konfiguration config.register_email_confirm=E-Mail-Bestätigung benötigt zum Registrieren -config.disable_register=Selbstegistrierung deaktivieren +config.disable_register=Selbstregistrierung deaktivieren config.allow_only_external_registration=Registrierung nur über externe Services erlauben config.enable_openid_signup=OpenID-Selbstregistrierung aktivieren config.enable_openid_signin=OpenID-Anmeldung aktivieren From 57b2ce03d5081bdf7996879be2da300e8f4c6f58 Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 29 May 2019 06:49:08 +0100 Subject: [PATCH 065/220] Handle early git version's lack of get-url (#7065) --- models/repo_mirror.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/models/repo_mirror.go b/models/repo_mirror.go index b58fa05dfe..7579231d8c 100644 --- a/models/repo_mirror.go +++ b/models/repo_mirror.go @@ -20,6 +20,7 @@ import ( "github.com/Unknwon/com" "github.com/go-xorm/xorm" + "github.com/mcuadros/go-version" ) // MirrorQueue holds an UniqueQueue object of the mirror @@ -70,7 +71,17 @@ func (m *Mirror) ScheduleNextUpdate() { } func remoteAddress(repoPath string) (string, error) { - cmd := git.NewCommand("remote", "get-url", "origin") + var cmd *git.Command + binVersion, err := git.BinVersion() + if err != nil { + return "", err + } + if version.Compare(binVersion, "2.7", ">=") { + cmd = git.NewCommand("remote", "get-url", "origin") + } else { + cmd = git.NewCommand("config", "--get", "remote.origin.url") + } + result, err := cmd.RunInDir(repoPath) if err != nil { if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { From d7494046ac8aaf3b01f0eae0039e38c6c4f9c246 Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Wed, 29 May 2019 17:16:13 +0200 Subject: [PATCH 066/220] bug fix: add single comment in split diff mode (#4745) (#7052) Signed-off-by: Rob Watson --- public/js/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/js/index.js b/public/js/index.js index 745a631435..96a56a4241 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1048,6 +1048,10 @@ function initPullRequestReview() { $(this).closest('tr').removeClass('focus-lines-new focus-lines-old'); }); $('.add-code-comment').on('click', function(e) { + // https://github.com/go-gitea/gitea/issues/4745 + if ($(e.target).hasClass('btn-add-single')) { + return; + } e.preventDefault(); var isSplit = $(this).closest('.code-diff').hasClass('code-diff-split'); var side = $(this).data('side'); From 3fd18838aa5c549842e88b770b8718f693614c75 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Thu, 30 May 2019 05:22:26 +0300 Subject: [PATCH 067/220] Repository avatars (#6986) * Repository avatars - first variant of code from old work for gogs - add migration 87 - add new option in app.ini - add en-US locale string - add new class in repository.less * Add changed index.css, remove unused template name * Update en-us doc about configuration options * Add comments to new functions, add new option to docker app.ini * Add comment for lint * Remove variable, not needed * Fix formatting * Update swagger api template * Check if avatar exists * Fix avatar link/path checks * Typo * TEXT column can't have a default value * Fixes: - remove old avatar file on upload - use ID in name of avatar file - users may upload same files - add simple tests * Fix fmt check * Generate PNG instead of "static" GIF * More informative comment * Fix error message * Update avatar upload checks: - add file size check - add new option - update config docs - add new string to en-us locale * Fixes: - use FileHEader field for check file size - add new test - upload big image * Fix formatting * Update comments * Update log message * Removed wrong style - not needed * Use Sync2 to migrate * Update repos list view - bigger avatar - fix html blocks alignment * A little adjust avatar size * Use small icons for explore/repo list * Use new cool avatar preparation func by @lafriks * Missing changes for new function * Remove unused import, move imports * Missed new option definition in app.ini Add file size check in user/profile avatar upload * Use smaller field length for Avatar * Use session to update repo DB data, update DeleteAvatar - use session too * Fix err variable definition * As suggested @lafriks - return as soon as possible, code readability --- custom/conf/app.ini.sample | 8 +- docker/root/etc/templates/app.ini | 1 + .../doc/advanced/config-cheat-sheet.en-us.md | 6 +- models/migrations/migrations.go | 2 + models/migrations/v87.go | 18 +++ models/repo.go | 134 ++++++++++++++++++ models/repo_test.go | 53 +++++++ modules/setting/setting.go | 24 ++-- modules/structs/repo.go | 1 + options/locale/locale_en-US.ini | 2 + public/css/index.css | 1 + public/less/_explore.less | 5 + routers/repo/setting.go | 59 ++++++++ routers/routes/routes.go | 11 ++ routers/user/setting/profile.go | 4 + templates/explore/repo_list.tmpl | 21 +-- templates/repo/header.tmpl | 4 + templates/repo/settings/options.tmpl | 16 +++ templates/swagger/v1_json.tmpl | 4 + 19 files changed, 354 insertions(+), 20 deletions(-) create mode 100644 models/migrations/v87.go diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index e13f5aeeda..e8e3ffada6 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -504,10 +504,14 @@ SESSION_LIFE_TIME = 86400 [picture] AVATAR_UPLOAD_PATH = data/avatars -; Max Width and Height of uploaded avatars. This is to limit the amount of RAM -; used when resizing the image. +REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars +; Max Width and Height of uploaded avatars. +; This is to limit the amount of RAM used when resizing the image. AVATAR_MAX_WIDTH = 4096 AVATAR_MAX_HEIGHT = 3072 +; Maximum alloved file size for uploaded avatars. +; This is to limit the amount of RAM used when resizing the image. +AVATAR_MAX_FILE_SIZE = 1048576 ; Chinese users can choose "duoshuo" ; or a custom avatar source, like: http://cn.gravatar.com/avatar/ GRAVATAR_SOURCE = gravatar diff --git a/docker/root/etc/templates/app.ini b/docker/root/etc/templates/app.ini index 589271b4a0..20cbb9053c 100644 --- a/docker/root/etc/templates/app.ini +++ b/docker/root/etc/templates/app.ini @@ -35,6 +35,7 @@ PROVIDER_CONFIG = /data/gitea/sessions [picture] AVATAR_UPLOAD_PATH = /data/gitea/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars [attachment] PATH = /data/gitea/attachments diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 140eb6ffb7..052ced6e2a 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -290,7 +290,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only. - `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see [http://www.libravatar.org](http://www.libravatar.org)). -- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store local and cached files. +- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files. +- `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: Path to store repository avatar image files. +- `AVATAR_MAX_WIDTH`: **4096**: Maximum avatar image width in pixels. +- `AVATAR_MAX_HEIGHT`: **3072**: Maximum avatar image height in pixels. +- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): Maximum avatar image file size in bytes. ## Attachment (`attachment`) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index f3a090e41c..b95a74c362 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -227,6 +227,8 @@ var migrations = []Migration{ NewMigration("hash application token", hashAppToken), // v86 -> v87 NewMigration("add http method to webhook", addHTTPMethodToWebhook), + // v87 -> v88 + NewMigration("add avatar field to repository", addAvatarFieldToRepository), } // Migrate database to current version diff --git a/models/migrations/v87.go b/models/migrations/v87.go new file mode 100644 index 0000000000..94711ac669 --- /dev/null +++ b/models/migrations/v87.go @@ -0,0 +1,18 @@ +// Copyright 2019 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "github.com/go-xorm/xorm" +) + +func addAvatarFieldToRepository(x *xorm.Engine) error { + type Repository struct { + // ID(10-20)-md5(32) - must fit into 64 symbols + Avatar string `xorm:"VARCHAR(64)"` + } + + return x.Sync2(new(Repository)) +} diff --git a/models/repo.go b/models/repo.go index 3283223d5b..b8a3714abf 100644 --- a/models/repo.go +++ b/models/repo.go @@ -7,9 +7,14 @@ package models import ( "bytes" + "crypto/md5" "errors" "fmt" "html/template" + + // Needed for jpeg support + _ "image/jpeg" + "image/png" "io/ioutil" "net/url" "os" @@ -21,6 +26,7 @@ import ( "strings" "time" + "code.gitea.io/gitea/modules/avatar" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" @@ -166,6 +172,9 @@ type Repository struct { CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"` Topics []string `xorm:"TEXT JSON"` + // Avatar: ID(10-20)-md5(32) - must fit into 64 symbols + Avatar string `xorm:"VARCHAR(64)"` + CreatedUnix util.TimeStamp `xorm:"INDEX created"` UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` } @@ -290,6 +299,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) Created: repo.CreatedUnix.AsTime(), Updated: repo.UpdatedUnix.AsTime(), Permissions: permission, + AvatarURL: repo.AvatarLink(), } } @@ -1869,6 +1879,15 @@ func DeleteRepository(doer *User, uid, repoID int64) error { go HookQueue.Add(repo.ID) } + if len(repo.Avatar) > 0 { + avatarPath := repo.CustomAvatarPath() + if com.IsExist(avatarPath) { + if err := os.Remove(avatarPath); err != nil { + return fmt.Errorf("Failed to remove %s: %v", avatarPath, err) + } + } + } + DeleteRepoFromIndexer(repo) return nil } @@ -2452,3 +2471,118 @@ func (repo *Repository) GetUserFork(userID int64) (*Repository, error) { } return &forkedRepo, nil } + +// CustomAvatarPath returns repository custom avatar file path. +func (repo *Repository) CustomAvatarPath() string { + // Avatar empty by default + if len(repo.Avatar) <= 0 { + return "" + } + return filepath.Join(setting.RepositoryAvatarUploadPath, repo.Avatar) +} + +// RelAvatarLink returns a relative link to the user's avatar. +// The link a sub-URL to this site +// Since Gravatar support not needed here - just check for image path. +func (repo *Repository) RelAvatarLink() string { + // If no avatar - path is empty + avatarPath := repo.CustomAvatarPath() + if len(avatarPath) <= 0 { + return "" + } + if !com.IsFile(avatarPath) { + return "" + } + return setting.AppSubURL + "/repo-avatars/" + repo.Avatar +} + +// AvatarLink returns user avatar absolute link. +func (repo *Repository) AvatarLink() string { + link := repo.RelAvatarLink() + // link may be empty! + if len(link) > 0 { + if link[0] == '/' && link[1] != '/' { + return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:] + } + } + return link +} + +// UploadAvatar saves custom avatar for repository. +// FIXME: split uploads to different subdirs in case we have massive number of repos. +func (repo *Repository) UploadAvatar(data []byte) error { + m, err := avatar.Prepare(data) + if err != nil { + return err + } + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + oldAvatarPath := repo.CustomAvatarPath() + + // Users can upload the same image to other repo - prefix it with ID + // Then repo will be removed - only it avatar file will be removed + repo.Avatar = fmt.Sprintf("%d-%x", repo.ID, md5.Sum(data)) + if _, err := sess.ID(repo.ID).Cols("avatar").Update(repo); err != nil { + return fmt.Errorf("UploadAvatar: Update repository avatar: %v", err) + } + + if err := os.MkdirAll(setting.RepositoryAvatarUploadPath, os.ModePerm); err != nil { + return fmt.Errorf("UploadAvatar: Failed to create dir %s: %v", setting.RepositoryAvatarUploadPath, err) + } + + fw, err := os.Create(repo.CustomAvatarPath()) + if err != nil { + return fmt.Errorf("UploadAvatar: Create file: %v", err) + } + defer fw.Close() + + if err = png.Encode(fw, *m); err != nil { + return fmt.Errorf("UploadAvatar: Encode png: %v", err) + } + + if len(oldAvatarPath) > 0 && oldAvatarPath != repo.CustomAvatarPath() { + if err := os.Remove(oldAvatarPath); err != nil { + return fmt.Errorf("UploadAvatar: Failed to remove old repo avatar %s: %v", oldAvatarPath, err) + } + } + + return sess.Commit() +} + +// DeleteAvatar deletes the repos's custom avatar. +func (repo *Repository) DeleteAvatar() error { + + // Avatar not exists + if len(repo.Avatar) == 0 { + return nil + } + + avatarPath := repo.CustomAvatarPath() + log.Trace("DeleteAvatar[%d]: %s", repo.ID, avatarPath) + + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + + repo.Avatar = "" + if _, err := sess.ID(repo.ID).Cols("avatar").Update(repo); err != nil { + return fmt.Errorf("DeleteAvatar: Update repository avatar: %v", err) + } + + if _, err := os.Stat(avatarPath); err == nil { + if err := os.Remove(avatarPath); err != nil { + return fmt.Errorf("DeleteAvatar: Failed to remove %s: %v", avatarPath, err) + } + } else { + // // Schrodinger: file may or may not exist. See err for details. + log.Trace("DeleteAvatar[%d]: %v", err) + } + return sess.Commit() +} diff --git a/models/repo_test.go b/models/repo_test.go index eee3997868..8411536d70 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -5,6 +5,11 @@ package models import ( + "bytes" + "crypto/md5" + "fmt" + "image" + "image/png" "testing" "code.gitea.io/gitea/modules/markup" @@ -158,3 +163,51 @@ func TestTransferOwnership(t *testing.T) { CheckConsistencyFor(t, &Repository{}, &User{}, &Team{}) } + +func TestUploadAvatar(t *testing.T) { + + // Generate image + myImage := image.NewRGBA(image.Rect(0, 0, 1, 1)) + var buff bytes.Buffer + png.Encode(&buff, myImage) + + assert.NoError(t, PrepareTestDatabase()) + repo := AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + + err := repo.UploadAvatar(buff.Bytes()) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf("%d-%x", 10, md5.Sum(buff.Bytes())), repo.Avatar) +} + +func TestUploadBigAvatar(t *testing.T) { + + // Generate BIG image + myImage := image.NewRGBA(image.Rect(0, 0, 5000, 1)) + var buff bytes.Buffer + png.Encode(&buff, myImage) + + assert.NoError(t, PrepareTestDatabase()) + repo := AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + + err := repo.UploadAvatar(buff.Bytes()) + assert.Error(t, err) +} + +func TestDeleteAvatar(t *testing.T) { + + // Generate image + myImage := image.NewRGBA(image.Rect(0, 0, 1, 1)) + var buff bytes.Buffer + png.Encode(&buff, myImage) + + assert.NoError(t, PrepareTestDatabase()) + repo := AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + + err := repo.UploadAvatar(buff.Bytes()) + assert.NoError(t, err) + + err = repo.DeleteAvatar() + assert.NoError(t, err) + + assert.Equal(t, "", repo.Avatar) +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index de89c67d04..9e96105788 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -250,14 +250,16 @@ var ( } // Picture settings - AvatarUploadPath string - AvatarMaxWidth int - AvatarMaxHeight int - GravatarSource string - GravatarSourceURL *url.URL - DisableGravatar bool - EnableFederatedAvatar bool - LibravatarService *libravatar.Libravatar + AvatarUploadPath string + AvatarMaxWidth int + AvatarMaxHeight int + GravatarSource string + GravatarSourceURL *url.URL + DisableGravatar bool + EnableFederatedAvatar bool + LibravatarService *libravatar.Libravatar + AvatarMaxFileSize int64 + RepositoryAvatarUploadPath string // Log settings LogLevel string @@ -835,8 +837,14 @@ func NewContext() { if !filepath.IsAbs(AvatarUploadPath) { AvatarUploadPath = path.Join(AppWorkPath, AvatarUploadPath) } + RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "repo-avatars")) + forcePathSeparator(RepositoryAvatarUploadPath) + if !filepath.IsAbs(RepositoryAvatarUploadPath) { + RepositoryAvatarUploadPath = path.Join(AppWorkPath, RepositoryAvatarUploadPath) + } AvatarMaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096) AvatarMaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072) + AvatarMaxFileSize = sec.Key("AVATAR_MAX_FILE_SIZE").MustInt64(1048576) switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source { case "duoshuo": GravatarSource = "http://gravatar.duoshuo.com/avatar/" diff --git a/modules/structs/repo.go b/modules/structs/repo.go index b5283beeaa..19f5ff8afe 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -43,6 +43,7 @@ type Repository struct { // swagger:strfmt date-time Updated time.Time `json:"updated_at"` Permissions *Permission `json:"permissions,omitempty"` + AvatarURL string `json:"avatar_url"` } // CreateRepoOption options when creating repository diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a691232cff..645c9770a4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -389,6 +389,7 @@ choose_new_avatar = Choose new avatar update_avatar = Update Avatar delete_current_avatar = Delete Current Avatar uploaded_avatar_not_a_image = The uploaded file is not an image. +uploaded_avatar_is_too_big = The uploaded file has exceeded the maximum size. update_avatar_success = Your avatar has been updated. change_password = Update Password @@ -1314,6 +1315,7 @@ settings.unarchive.header = Un-Archive This Repo settings.unarchive.text = Un-Archiving the repo will restore its ability to recieve commits and pushes, as well as new issues and pull-requests. settings.unarchive.success = The repo was successfully un-archived. settings.unarchive.error = An error occured while trying to un-archive the repo. See the log for more details. +settings.update_avatar_success = The repository avatar has been updated. diff.browse_source = Browse Source diff.parent = parent diff --git a/public/css/index.css b/public/css/index.css index 8cea4e2c1d..8950cc7038 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -956,6 +956,7 @@ tbody.commit-list{vertical-align:baseline} .ui.repository.list .item .ui.header .metas span:not(:last-child){margin-right:5px} .ui.repository.list .item .time{font-size:12px;color:grey} .ui.repository.list .item .ui.tags{margin-bottom:1em} +.ui.repository.list .item .ui.avatar.image{width:24px;height:24px} .ui.repository.branches .time{font-size:12px;color:grey} .ui.user.list .item{padding-bottom:25px} .ui.user.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px} diff --git a/public/less/_explore.less b/public/less/_explore.less index 809a138a6c..c5065a35bc 100644 --- a/public/less/_explore.less +++ b/public/less/_explore.less @@ -53,6 +53,11 @@ .ui.tags { margin-bottom: 1em; } + + .ui.avatar.image { + width: 24px; + height: 24px; + } } } diff --git a/routers/repo/setting.go b/routers/repo/setting.go index f58601633a..07649982d2 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -7,11 +7,14 @@ package repo import ( "errors" + "fmt" + "io/ioutil" "net/url" "regexp" "strings" "time" + "github.com/Unknwon/com" "mvdan.cc/xurls/v2" "code.gitea.io/gitea/models" @@ -727,3 +730,59 @@ func init() { panic(err) } } + +// UpdateAvatarSetting update repo's avatar +func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm) error { + ctxRepo := ctx.Repo.Repository + + if form.Avatar == nil { + // No avatar is uploaded and we not removing it here. + // No random avatar generated here. + // Just exit, no action. + if !com.IsFile(ctxRepo.CustomAvatarPath()) { + log.Trace("No avatar was uploaded for repo: %d. Default icon will appear instead.", ctxRepo.ID) + } + return nil + } + + r, err := form.Avatar.Open() + if err != nil { + return fmt.Errorf("Avatar.Open: %v", err) + } + defer r.Close() + + if form.Avatar.Size > setting.AvatarMaxFileSize { + return errors.New(ctx.Tr("settings.uploaded_avatar_is_too_big")) + } + + data, err := ioutil.ReadAll(r) + if err != nil { + return fmt.Errorf("ioutil.ReadAll: %v", err) + } + if !base.IsImageFile(data) { + return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image")) + } + if err = ctxRepo.UploadAvatar(data); err != nil { + return fmt.Errorf("UploadAvatar: %v", err) + } + return nil +} + +// SettingsAvatar save new POSTed repository avatar +func SettingsAvatar(ctx *context.Context, form auth.AvatarForm) { + form.Source = auth.AvatarLocal + if err := UpdateAvatarSetting(ctx, form); err != nil { + ctx.Flash.Error(err.Error()) + } else { + ctx.Flash.Success(ctx.Tr("repo.settings.update_avatar_success")) + } + ctx.Redirect(ctx.Repo.RepoLink + "/settings") +} + +// SettingsDeleteAvatar delete repository avatar +func SettingsDeleteAvatar(ctx *context.Context) { + if err := ctx.Repo.Repository.DeleteAvatar(); err != nil { + ctx.Flash.Error(fmt.Sprintf("DeleteAvatar: %v", err)) + } + ctx.Redirect(ctx.Repo.RepoLink + "/settings") +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index d19823714b..eb5f73768e 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -159,6 +159,14 @@ func NewMacaron() *macaron.Macaron { ExpiresAfter: time.Hour * 6, }, )) + m.Use(public.StaticHandler( + setting.RepositoryAvatarUploadPath, + &public.Options{ + Prefix: "repo-avatars", + SkipLogging: setting.DisableRouterLog, + ExpiresAfter: time.Hour * 6, + }, + )) m.Use(templates.HTMLRenderer()) models.InitMailRender(templates.Mailer()) @@ -613,6 +621,9 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/settings", func() { m.Combo("").Get(repo.Settings). Post(bindIgnErr(auth.RepoSettingForm{}), repo.SettingsPost) + m.Post("/avatar", binding.MultipartForm(auth.AvatarForm{}), repo.SettingsAvatar) + m.Post("/avatar/delete", repo.SettingsDeleteAvatar) + m.Group("/collaboration", func() { m.Combo("").Get(repo.Collaboration).Post(repo.CollaborationPost) m.Post("/access_mode", repo.ChangeCollaborationAccessMode) diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index 85c9c83fd1..ac5c4c97fb 100644 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -127,6 +127,10 @@ func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm, ctxUser *mo } defer fr.Close() + if form.Avatar.Size > setting.AvatarMaxFileSize { + return errors.New(ctx.Tr("settings.uploaded_avatar_is_too_big")) + } + data, err := ioutil.ReadAll(fr) if err != nil { return fmt.Errorf("ioutil.ReadAll: %v", err) diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl index b176817001..34aab6477a 100644 --- a/templates/explore/repo_list.tmpl +++ b/templates/explore/repo_list.tmpl @@ -2,6 +2,7 @@ {{range .Repos}}
    - {{if .DescriptionHTML}}

    {{.DescriptionHTML}}

    {{end}} - {{if .Topics }} -
    - {{range .Topics}} - {{if ne . "" }}
    {{.}}
    {{end}} +
    + {{if .DescriptionHTML}}

    {{.DescriptionHTML}}

    {{end}} + {{if .Topics }} +
    + {{range .Topics}} + {{if ne . "" }}
    {{.}}
    {{end}} + {{end}} +
    {{end}} -
    - {{end}} -

    {{$.i18n.Tr "org.repo_updated"}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}

    +

    {{$.i18n.Tr "org.repo_updated"}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}

    +
    {{else}}
    diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index d340575353..f4eefd3fde 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -3,7 +3,11 @@
    + +
    + +
    + {{.CsrfTokenHtml}} +
    + + +
    + +
    + + {{$.i18n.Tr "settings.delete_current_avatar"}} +
    +
    +
    {{if .Repository.IsMirror}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index c0790ac23e..7307d1284b 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -9066,6 +9066,10 @@ "type": "boolean", "x-go-name": "Archived" }, + "avatar_url": { + "type": "string", + "x-go-name": "AvatarURL" + }, "clone_url": { "type": "string", "x-go-name": "CloneURL" From cdd10f145be0b5e9b94c19f1303dc01c6e9c8c29 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 30 May 2019 02:25:01 +0000 Subject: [PATCH 068/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-BR.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 782d3a9bb9..26ff625df2 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -94,6 +94,10 @@ sqlite_helper=Caminho do arquivo do banco de dados SQLite3.
    Informe um caminh err_empty_db_path=O caminho do banco de dados SQLite3 não pode ser em branco. no_admin_and_disable_registration=Você não pode desabilitar o auto-cadastro do usuário sem criar uma conta de administrador. err_empty_admin_password=A senha do administrador não pode ser em branco. +err_empty_admin_email=O e-mail do administrador não pode ser em branco. +err_admin_name_is_reserved=Nome de usuário do administrador é inválido, nome de usuário está reservado +err_admin_name_pattern_not_allowed=Nome de usuário do administrador é inválido, nome de usuário não é permitido +err_admin_name_is_invalid=Nome de usuário do administrador inválido general_title=Configurações gerais app_name=Nome do servidor From 1831b3b57144e87ccfc4f6322eefc88a49b2300e Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Thu, 30 May 2019 11:09:05 -0400 Subject: [PATCH 069/220] Fixes #5960 - Adds API Endpoint for Repo Edit (#7006) * Feature - #5960 - API Endpoint for Repo Editing * Revert from merge * Adds integration testing * Updates to integration tests * Revert changes * Update year in file header * Misspell fix * XORM = test * XORM = test * revert XORM = file * Makes RepoUnit.ID be pk and autoincr * Fix to units * revert header * Remove print statement * Adds other responses * Improves swagger for creating repo * Fixes import order * Better Unit Type does not exist error * Adds editable repo properties to the response repo structure * Fix to api_repo_edit_test.go * Fixes repo test * Changes per review * Fixes typo and standardizes comments in the EditRepoOption struct for swagger * Fixes typo and standardizes comments in the EditRepoOption struct for swagger * Actually can unarchive through the API * Unlike delete, user doesn't have to be the owner of the org, just admin to the repo * Fix to swagger comments for field name change * Update to swagger docs * Update swagger * Changes allow_pull_requests to has_pull_requests --- integrations/api_repo_edit_test.go | 225 +++++++++++++++++ integrations/api_repo_file_delete_test.go | 2 +- models/org.go | 4 +- models/repo.go | 111 ++++++--- models/unit.go | 8 +- modules/structs/repo.go | 58 +++-- routers/api/v1/api.go | 3 +- routers/api/v1/repo/repo.go | 278 ++++++++++++++++++++++ routers/api/v1/repo/repo_test.go | 82 +++++++ routers/api/v1/swagger/options.go | 2 + templates/swagger/v1_json.tmpl | 161 +++++++++++++ 11 files changed, 868 insertions(+), 66 deletions(-) create mode 100644 integrations/api_repo_edit_test.go create mode 100644 routers/api/v1/repo/repo_test.go diff --git a/integrations/api_repo_edit_test.go b/integrations/api_repo_edit_test.go new file mode 100644 index 0000000000..3b2c916ab0 --- /dev/null +++ b/integrations/api_repo_edit_test.go @@ -0,0 +1,225 @@ +// Copyright 2019 The Gitea 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 integrations + +import ( + "fmt" + "net/http" + "net/url" + "testing" + + "code.gitea.io/gitea/models" + api "code.gitea.io/gitea/modules/structs" + + "github.com/stretchr/testify/assert" +) + +// getRepoEditOptionFromRepo gets the options for an existing repo exactly as is +func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption { + name := repo.Name + description := repo.Description + website := repo.Website + private := repo.IsPrivate + hasIssues := false + if _, err := repo.GetUnit(models.UnitTypeIssues); err == nil { + hasIssues = true + } + hasWiki := false + if _, err := repo.GetUnit(models.UnitTypeWiki); err == nil { + hasWiki = true + } + defaultBranch := repo.DefaultBranch + hasPullRequests := false + ignoreWhitespaceConflicts := false + allowMerge := false + allowRebase := false + allowRebaseMerge := false + allowSquash := false + if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil { + config := unit.PullRequestsConfig() + hasPullRequests = true + ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts + allowMerge = config.AllowMerge + allowRebase = config.AllowRebase + allowRebaseMerge = config.AllowRebaseMerge + allowSquash = config.AllowSquash + } + archived := repo.IsArchived + return &api.EditRepoOption{ + Name: &name, + Description: &description, + Website: &website, + Private: &private, + HasIssues: &hasIssues, + HasWiki: &hasWiki, + DefaultBranch: &defaultBranch, + HasPullRequests: &hasPullRequests, + IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts, + AllowMerge: &allowMerge, + AllowRebase: &allowRebase, + AllowRebaseMerge: &allowRebaseMerge, + AllowSquash: &allowSquash, + Archived: &archived, + } +} + +// getNewRepoEditOption Gets the options to change everything about an existing repo by adding to strings or changing +// the boolean +func getNewRepoEditOption(opts *api.EditRepoOption) *api.EditRepoOption { + // Gives a new property to everything + name := *opts.Name + "renamed" + description := "new description" + website := "http://wwww.newwebsite.com" + private := !*opts.Private + hasIssues := !*opts.HasIssues + hasWiki := !*opts.HasWiki + defaultBranch := "master" + hasPullRequests := !*opts.HasPullRequests + ignoreWhitespaceConflicts := !*opts.IgnoreWhitespaceConflicts + allowMerge := !*opts.AllowMerge + allowRebase := !*opts.AllowRebase + allowRebaseMerge := !*opts.AllowRebaseMerge + allowSquash := !*opts.AllowSquash + archived := !*opts.Archived + + return &api.EditRepoOption{ + Name: &name, + Description: &description, + Website: &website, + Private: &private, + DefaultBranch: &defaultBranch, + HasIssues: &hasIssues, + HasWiki: &hasWiki, + HasPullRequests: &hasPullRequests, + IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts, + AllowMerge: &allowMerge, + AllowRebase: &allowRebase, + AllowRebaseMerge: &allowRebaseMerge, + AllowSquash: &allowSquash, + Archived: &archived, + } +} + +func TestAPIRepoEdit(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) // owner of the repo1 & repo16 + user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User) // owner of the repo3, is an org + user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User) // owner of neither repos + repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) // public repo + repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo + repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo + + // Get user2's token + session := loginUser(t, user2.Name) + token2 := getTokenForLoggedInUser(t, session) + session = emptyTestSession(t) + // Get user4's token + session = loginUser(t, user4.Name) + token4 := getTokenForLoggedInUser(t, session) + session = emptyTestSession(t) + + // Test editing a repo1 which user2 owns, changing name and many properties + origRepoEditOption := getRepoEditOptionFromRepo(repo1) + repoEditOption := getNewRepoEditOption(origRepoEditOption) + url := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo1.Name, token2) + req := NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp := session.MakeRequest(t, req, http.StatusOK) + var repo api.Repository + DecodeJSON(t, resp, &repo) + assert.NotNil(t, repo) + // check response + assert.Equal(t, *repoEditOption.Name, repo.Name) + assert.Equal(t, *repoEditOption.Description, repo.Description) + assert.Equal(t, *repoEditOption.Website, repo.Website) + assert.Equal(t, *repoEditOption.Archived, repo.Archived) + // check repo1 from database + repo1edited := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + repo1editedOption := getRepoEditOptionFromRepo(repo1edited) + assert.Equal(t, *repoEditOption.Name, *repo1editedOption.Name) + assert.Equal(t, *repoEditOption.Description, *repo1editedOption.Description) + assert.Equal(t, *repoEditOption.Website, *repo1editedOption.Website) + assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived) + assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private) + assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki) + // reset repo in db + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + + // Test editing a non-existing repo + name := "repodoesnotexist" + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{Name: &name}) + resp = session.MakeRequest(t, req, http.StatusNotFound) + + // Test editing repo16 by user4 who does not have write access + origRepoEditOption = getRepoEditOptionFromRepo(repo16) + repoEditOption = getNewRepoEditOption(origRepoEditOption) + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token4) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + session.MakeRequest(t, req, http.StatusNotFound) + + // Tests a repo with no token given so will fail + origRepoEditOption = getRepoEditOptionFromRepo(repo16) + repoEditOption = getNewRepoEditOption(origRepoEditOption) + url = fmt.Sprintf("/api/v1/repos/%s/%s", user2.Name, repo16.Name) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusNotFound) + + // Test using access token for a private repo that the user of the token owns + origRepoEditOption = getRepoEditOptionFromRepo(repo16) + repoEditOption = getNewRepoEditOption(origRepoEditOption) + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + // reset repo in db + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + + // Test making a repo public that is private + repo16 = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) + assert.True(t, repo16.IsPrivate) + private := false + repoEditOption = &api.EditRepoOption{ + Private: &private, + } + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + repo16 = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) + assert.False(t, repo16.IsPrivate) + // Make it private again + private = true + repoEditOption.Private = &private + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + + // Test using org repo "user3/repo3" where user2 is a collaborator + origRepoEditOption = getRepoEditOptionFromRepo(repo3) + repoEditOption = getNewRepoEditOption(origRepoEditOption) + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user3.Name, repo3.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + session.MakeRequest(t, req, http.StatusOK) + // reset repo in db + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user3.Name, *repoEditOption.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + + // Test using org repo "user3/repo3" with no user token + origRepoEditOption = getRepoEditOptionFromRepo(repo3) + repoEditOption = getNewRepoEditOption(origRepoEditOption) + url = fmt.Sprintf("/api/v1/repos/%s/%s", user3.Name, repo3.Name) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + session.MakeRequest(t, req, http.StatusNotFound) + + // Test using repo "user2/repo1" where user4 is a NOT collaborator + origRepoEditOption = getRepoEditOptionFromRepo(repo1) + repoEditOption = getNewRepoEditOption(origRepoEditOption) + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo1.Name, token4) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + session.MakeRequest(t, req, http.StatusForbidden) + }) +} diff --git a/integrations/api_repo_file_delete_test.go b/integrations/api_repo_file_delete_test.go index 57e2539e19..e9029a669b 100644 --- a/integrations/api_repo_file_delete_test.go +++ b/integrations/api_repo_file_delete_test.go @@ -108,7 +108,7 @@ func TestAPIDeleteFile(t *testing.T) { DecodeJSON(t, resp, &apiError) assert.Equal(t, expectedAPIError, apiError) - // Test creating a file in repo1 by user4 who does not have write access + // Test creating a file in repo16 by user4 who does not have write access fileID++ treePath = fmt.Sprintf("delete/file%d.txt", fileID) createFile(user2, repo16, treePath) diff --git a/models/org.go b/models/org.go index b7db32ef16..6511072e2b 100644 --- a/models/org.go +++ b/models/org.go @@ -162,8 +162,8 @@ func CreateOrganization(org, owner *User) (err error) { } // insert units for team - var units = make([]TeamUnit, 0, len(allRepUnitTypes)) - for _, tp := range allRepUnitTypes { + var units = make([]TeamUnit, 0, len(AllRepoUnitTypes)) + for _, tp := range AllRepoUnitTypes { units = append(units, TeamUnit{ OrgID: org.ID, TeamID: t.ID, diff --git a/models/repo.go b/models/repo.go index b8a3714abf..16684bdeef 100644 --- a/models/repo.go +++ b/models/repo.go @@ -274,32 +274,64 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) parent = repo.BaseRepo.innerAPIFormat(e, mode, true) } } + hasIssues := false + if _, err := repo.getUnit(e, UnitTypeIssues); err == nil { + hasIssues = true + } + hasWiki := false + if _, err := repo.getUnit(e, UnitTypeWiki); err == nil { + hasWiki = true + } + hasPullRequests := false + ignoreWhitespaceConflicts := false + allowMerge := false + allowRebase := false + allowRebaseMerge := false + allowSquash := false + if unit, err := repo.getUnit(e, UnitTypePullRequests); err == nil { + config := unit.PullRequestsConfig() + hasPullRequests = true + ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts + allowMerge = config.AllowMerge + allowRebase = config.AllowRebase + allowRebaseMerge = config.AllowRebaseMerge + allowSquash = config.AllowSquash + } + return &api.Repository{ - ID: repo.ID, - Owner: repo.Owner.APIFormat(), - Name: repo.Name, - FullName: repo.FullName(), - Description: repo.Description, - Private: repo.IsPrivate, - Empty: repo.IsEmpty, - Archived: repo.IsArchived, - Size: int(repo.Size / 1024), - Fork: repo.IsFork, - Parent: parent, - Mirror: repo.IsMirror, - HTMLURL: repo.HTMLURL(), - SSHURL: cloneLink.SSH, - CloneURL: cloneLink.HTTPS, - Website: repo.Website, - Stars: repo.NumStars, - Forks: repo.NumForks, - Watchers: repo.NumWatches, - OpenIssues: repo.NumOpenIssues, - DefaultBranch: repo.DefaultBranch, - Created: repo.CreatedUnix.AsTime(), - Updated: repo.UpdatedUnix.AsTime(), - Permissions: permission, - AvatarURL: repo.AvatarLink(), + ID: repo.ID, + Owner: repo.Owner.APIFormat(), + Name: repo.Name, + FullName: repo.FullName(), + Description: repo.Description, + Private: repo.IsPrivate, + Empty: repo.IsEmpty, + Archived: repo.IsArchived, + Size: int(repo.Size / 1024), + Fork: repo.IsFork, + Parent: parent, + Mirror: repo.IsMirror, + HTMLURL: repo.HTMLURL(), + SSHURL: cloneLink.SSH, + CloneURL: cloneLink.HTTPS, + Website: repo.Website, + Stars: repo.NumStars, + Forks: repo.NumForks, + Watchers: repo.NumWatches, + OpenIssues: repo.NumOpenIssues, + DefaultBranch: repo.DefaultBranch, + Created: repo.CreatedUnix.AsTime(), + Updated: repo.UpdatedUnix.AsTime(), + Permissions: permission, + HasIssues: hasIssues, + HasWiki: hasWiki, + HasPullRequests: hasPullRequests, + IgnoreWhitespaceConflicts: ignoreWhitespaceConflicts, + AllowMerge: allowMerge, + AllowRebase: allowRebase, + AllowRebaseMerge: allowRebaseMerge, + AllowSquash: allowSquash, + AvatarURL: repo.AvatarLink(), } } @@ -346,10 +378,20 @@ func (repo *Repository) UnitEnabled(tp UnitType) bool { return false } -var ( - // ErrUnitNotExist organization does not exist - ErrUnitNotExist = errors.New("Unit does not exist") -) +// ErrUnitTypeNotExist represents a "UnitTypeNotExist" kind of error. +type ErrUnitTypeNotExist struct { + UT UnitType +} + +// IsErrUnitTypeNotExist checks if an error is a ErrUnitNotExist. +func IsErrUnitTypeNotExist(err error) bool { + _, ok := err.(ErrUnitTypeNotExist) + return ok +} + +func (err ErrUnitTypeNotExist) Error() string { + return fmt.Sprintf("Unit type does not exist: %s", err.UT.String()) +} // MustGetUnit always returns a RepoUnit object func (repo *Repository) MustGetUnit(tp UnitType) *RepoUnit { @@ -373,6 +415,11 @@ func (repo *Repository) MustGetUnit(tp UnitType) *RepoUnit { Type: tp, Config: new(PullRequestsConfig), } + } else if tp == UnitTypeIssues { + return &RepoUnit{ + Type: tp, + Config: new(IssuesConfig), + } } return &RepoUnit{ Type: tp, @@ -394,7 +441,7 @@ func (repo *Repository) getUnit(e Engine, tp UnitType) (*RepoUnit, error) { return unit, nil } } - return nil, ErrUnitNotExist + return nil, ErrUnitTypeNotExist{tp} } func (repo *Repository) getOwner(e Engine) (err error) { @@ -1232,8 +1279,8 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err } // insert units for repo - var units = make([]RepoUnit, 0, len(defaultRepoUnits)) - for _, tp := range defaultRepoUnits { + var units = make([]RepoUnit, 0, len(DefaultRepoUnits)) + for _, tp := range DefaultRepoUnits { if tp == UnitTypeIssues { units = append(units, RepoUnit{ RepoID: repo.ID, diff --git a/models/unit.go b/models/unit.go index 697df696bc..9f5c8d3cbb 100644 --- a/models/unit.go +++ b/models/unit.go @@ -58,8 +58,8 @@ func (u UnitType) ColorFormat(s fmt.State) { } var ( - // allRepUnitTypes contains all the unit types - allRepUnitTypes = []UnitType{ + // AllRepoUnitTypes contains all the unit types + AllRepoUnitTypes = []UnitType{ UnitTypeCode, UnitTypeIssues, UnitTypePullRequests, @@ -69,8 +69,8 @@ var ( UnitTypeExternalTracker, } - // defaultRepoUnits contains the default unit types - defaultRepoUnits = []UnitType{ + // DefaultRepoUnits contains the default unit types + DefaultRepoUnits = []UnitType{ UnitTypeCode, UnitTypeIssues, UnitTypePullRequests, diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 19f5ff8afe..b4d162b776 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -41,9 +41,17 @@ type Repository struct { // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time - Updated time.Time `json:"updated_at"` - Permissions *Permission `json:"permissions,omitempty"` - AvatarURL string `json:"avatar_url"` + Updated time.Time `json:"updated_at"` + Permissions *Permission `json:"permissions,omitempty"` + HasIssues bool `json:"has_issues"` + HasWiki bool `json:"has_wiki"` + HasPullRequests bool `json:"has_pull_requests"` + IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"` + AllowMerge bool `json:"allow_merge_commits"` + AllowRebase bool `json:"allow_rebase"` + AllowRebaseMerge bool `json:"allow_rebase_explicit"` + AllowSquash bool `json:"allow_squash_merge"` + AvatarURL string `json:"avatar_url"` } // CreateRepoOption options when creating repository @@ -71,38 +79,36 @@ type CreateRepoOption struct { // EditRepoOption options when editing a repository's properties // swagger:model type EditRepoOption struct { - // Name of the repository - // - // required: true + // name of the repository // unique: true - Name *string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"` - // A short description of the repository. + Name *string `json:"name,omitempty" binding:"OmitEmpty;AlphaDashDot;MaxSize(100);"` + // a short description of the repository. Description *string `json:"description,omitempty" binding:"MaxSize(255)"` - // A URL with more information about the repository. + // a URL with more information about the repository. Website *string `json:"website,omitempty" binding:"MaxSize(255)"` - // Either `true` to make the repository private or `false` to make it public. - // Note: You will get a 422 error if the organization restricts changing repository visibility to organization + // either `true` to make the repository private or `false` to make it public. + // Note: you will get a 422 error if the organization restricts changing repository visibility to organization // owners and a non-owner tries to change the value of private. Private *bool `json:"private,omitempty"` - // Either `true` to enable issues for this repository or `false` to disable them. - EnableIssues *bool `json:"enable_issues,omitempty"` - // Either `true` to enable the wiki for this repository or `false` to disable it. - EnableWiki *bool `json:"enable_wiki,omitempty"` - // Updates the default branch for this repository. + // either `true` to enable issues for this repository or `false` to disable them. + HasIssues *bool `json:"has_issues,omitempty"` + // either `true` to enable the wiki for this repository or `false` to disable it. + HasWiki *bool `json:"has_wiki,omitempty"` + // sets the default branch for this repository. DefaultBranch *string `json:"default_branch,omitempty"` - // Either `true` to allow pull requests, or `false` to prevent pull request. - EnablePullRequests *bool `json:"enable_pull_requests,omitempty"` - // Either `true` to ignore whitepace for conflicts, or `false` to not ignore whitespace. `enabled_pull_requests` must be `true`. - IgnoreWhitespaceConflicts *bool `json:"ignore_whitespace,omitempty"` - // Either `true` to allow merging pull requests with a merge commit, or `false` to prevent merging pull requests with merge commits. `enabled_pull_requests` must be `true`. + // either `true` to allow pull requests, or `false` to prevent pull request. + HasPullRequests *bool `json:"has_pull_requests,omitempty"` + // either `true` to ignore whitespace for conflicts, or `false` to not ignore whitespace. `has_pull_requests` must be `true`. + IgnoreWhitespaceConflicts *bool `json:"ignore_whitespace_conflicts,omitempty"` + // either `true` to allow merging pull requests with a merge commit, or `false` to prevent merging pull requests with merge commits. `has_pull_requests` must be `true`. AllowMerge *bool `json:"allow_merge_commits,omitempty"` - // Either `true` to allow rebase-merging pull requests, or `false` to prevent rebase-merging. `enabled_pull_requests` must be `true`. + // either `true` to allow rebase-merging pull requests, or `false` to prevent rebase-merging. `has_pull_requests` must be `true`. AllowRebase *bool `json:"allow_rebase,omitempty"` - // Either `true` to allow rebase with explicit merge commits (--no-ff), or `false` to prevent rebase with explicit merge commits. `enabled_pull_requests` must be `true`. + // either `true` to allow rebase with explicit merge commits (--no-ff), or `false` to prevent rebase with explicit merge commits. `has_pull_requests` must be `true`. AllowRebaseMerge *bool `json:"allow_rebase_explicit,omitempty"` - // Either `true` to allow squash-merging pull requests, or `false` to prevent squash-merging. `enabled_pull_requests` must be `true`. - AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"` - // `true` to archive this repository. Note: You cannot unarchive repositories through the API. + // either `true` to allow squash-merging pull requests, or `false` to prevent squash-merging. `has_pull_requests` must be `true`. + AllowSquash *bool `json:"allow_squash_merge,omitempty"` + // set to `true` to archive this repository. Archived *bool `json:"archived,omitempty"` } diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index ae64e887ca..c1561200cd 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -608,7 +608,8 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/:username/:reponame", func() { m.Combo("").Get(reqAnyRepoReader(), repo.Get). - Delete(reqToken(), reqOwner(), repo.Delete) + Delete(reqToken(), reqOwner(), repo.Delete). + Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit) m.Group("/hooks", func() { m.Combo("").Get(repo.ListHooks). Post(bind(api.CreateHookOption{}), repo.CreateHook) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 62153893a6..f8df3e9fa1 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -240,6 +240,10 @@ func Create(ctx *context.APIContext, opt api.CreateRepoOption) { // responses: // "201": // "$ref": "#/responses/Repository" + // "409": + // description: The repository with the same name already exists. + // "422": + // "$ref": "#/responses/validationError" if ctx.User.IsOrganization() { // Shouldn't reach this condition, but just in case. ctx.Error(422, "", "not allowed creating repository for organization") @@ -500,6 +504,280 @@ func GetByID(ctx *context.APIContext) { ctx.JSON(200, repo.APIFormat(perm.AccessMode)) } +// Edit edit repository properties +func Edit(ctx *context.APIContext, opts api.EditRepoOption) { + // swagger:operation PATCH /repos/{owner}/{repo} repository repoEdit + // --- + // summary: Edit a repository's properties. Only fields that are set will be changed. + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo to edit + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo to edit + // type: string + // required: true + // required: true + // - name: body + // in: body + // description: "Properties of a repo that you can edit" + // schema: + // "$ref": "#/definitions/EditRepoOption" + // responses: + // "200": + // "$ref": "#/responses/Repository" + // "403": + // "$ref": "#/responses/forbidden" + // "422": + // "$ref": "#/responses/validationError" + if err := updateBasicProperties(ctx, opts); err != nil { + return + } + + if err := updateRepoUnits(ctx, opts); err != nil { + return + } + + if opts.Archived != nil { + if err := updateRepoArchivedState(ctx, opts); err != nil { + return + } + } + + ctx.JSON(http.StatusOK, ctx.Repo.Repository.APIFormat(ctx.Repo.AccessMode)) +} + +// updateBasicProperties updates the basic properties of a repo: Name, Description, Website and Visibility +func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) error { + owner := ctx.Repo.Owner + repo := ctx.Repo.Repository + + oldRepoName := repo.Name + newRepoName := repo.Name + if opts.Name != nil { + newRepoName = *opts.Name + } + // Check if repository name has been changed and not just a case change + if repo.LowerName != strings.ToLower(newRepoName) { + if err := models.ChangeRepositoryName(ctx.Repo.Owner, repo.Name, newRepoName); err != nil { + switch { + case models.IsErrRepoAlreadyExist(err): + ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is already taken [name: %s]", newRepoName), err) + case models.IsErrNameReserved(err): + ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is reserved [name: %s]", newRepoName), err) + case models.IsErrNamePatternNotAllowed(err): + ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name's pattern is not allowed [name: %s, pattern: %s]", newRepoName, err.(models.ErrNamePatternNotAllowed).Pattern), err) + default: + ctx.Error(http.StatusUnprocessableEntity, "ChangeRepositoryName", err) + } + return err + } + + err := models.NewRepoRedirect(ctx.Repo.Owner.ID, repo.ID, repo.Name, newRepoName) + if err != nil { + ctx.Error(http.StatusUnprocessableEntity, "NewRepoRedirect", err) + return err + } + + if err := models.RenameRepoAction(ctx.User, oldRepoName, repo); err != nil { + log.Error("RenameRepoAction: %v", err) + ctx.Error(http.StatusInternalServerError, "RenameRepoActions", err) + return err + } + + log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName) + } + // Update the name in the repo object for the response + repo.Name = newRepoName + repo.LowerName = strings.ToLower(newRepoName) + + if opts.Description != nil { + repo.Description = *opts.Description + } + + if opts.Website != nil { + repo.Website = *opts.Website + } + + visibilityChanged := false + if opts.Private != nil { + // Visibility of forked repository is forced sync with base repository. + if repo.IsFork { + *opts.Private = repo.BaseRepo.IsPrivate + } + + visibilityChanged = repo.IsPrivate != *opts.Private + // when ForcePrivate enabled, you could change public repo to private, but only admin users can change private to public + if visibilityChanged && setting.Repository.ForcePrivate && !*opts.Private && !ctx.User.IsAdmin { + err := fmt.Errorf("cannot change private repository to public") + ctx.Error(http.StatusUnprocessableEntity, "Force Private enabled", err) + return err + } + + repo.IsPrivate = *opts.Private + } + + if err := models.UpdateRepository(repo, visibilityChanged); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateRepository", err) + return err + } + + log.Trace("Repository basic settings updated: %s/%s", owner.Name, repo.Name) + return nil +} + +func unitTypeInTypes(unitType models.UnitType, unitTypes []models.UnitType) bool { + for _, tp := range unitTypes { + if unitType == tp { + return true + } + } + return false +} + +// updateRepoUnits updates repo units: Issue settings, Wiki settings, PR settings +func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { + owner := ctx.Repo.Owner + repo := ctx.Repo.Repository + + var units []models.RepoUnit + + for _, tp := range models.MustRepoUnits { + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: tp, + Config: new(models.UnitConfig), + }) + } + + if opts.HasIssues != nil { + if *opts.HasIssues { + // We don't currently allow setting individual issue settings through the API, + // only can enable/disable issues, so when enabling issues, + // we either get the existing config which means it was already enabled, + // or create a new config since it doesn't exist. + unit, err := repo.GetUnit(models.UnitTypeIssues) + var config *models.IssuesConfig + if err != nil { + // Unit type doesn't exist so we make a new config file with default values + config = &models.IssuesConfig{ + EnableTimetracker: true, + AllowOnlyContributorsToTrackTime: true, + EnableDependencies: true, + } + } else { + config = unit.IssuesConfig() + } + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeIssues, + Config: config, + }) + } + } + + if opts.HasWiki != nil { + if *opts.HasWiki { + // We don't currently allow setting individual wiki settings through the API, + // only can enable/disable the wiki, so when enabling the wiki, + // we either get the existing config which means it was already enabled, + // or create a new config since it doesn't exist. + config := &models.UnitConfig{} + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeWiki, + Config: config, + }) + } + } + + if opts.HasPullRequests != nil { + if *opts.HasPullRequests { + // We do allow setting individual PR settings through the API, so + // we get the config settings and then set them + // if those settings were provided in the opts. + unit, err := repo.GetUnit(models.UnitTypePullRequests) + var config *models.PullRequestsConfig + if err != nil { + // Unit type doesn't exist so we make a new config file with default values + config = &models.PullRequestsConfig{ + IgnoreWhitespaceConflicts: false, + AllowMerge: true, + AllowRebase: true, + AllowRebaseMerge: true, + AllowSquash: true, + } + } else { + config = unit.PullRequestsConfig() + } + + if opts.IgnoreWhitespaceConflicts != nil { + config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts + } + if opts.AllowMerge != nil { + config.AllowMerge = *opts.AllowMerge + } + if opts.AllowRebase != nil { + config.AllowRebase = *opts.AllowRebase + } + if opts.AllowRebaseMerge != nil { + config.AllowRebaseMerge = *opts.AllowRebaseMerge + } + if opts.AllowSquash != nil { + config.AllowSquash = *opts.AllowSquash + } + + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypePullRequests, + Config: config, + }) + } + } + + if err := models.UpdateRepositoryUnits(repo, units); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err) + return err + } + + log.Trace("Repository advanced settings updated: %s/%s", owner.Name, repo.Name) + return nil +} + +// updateRepoArchivedState updates repo's archive state +func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) error { + repo := ctx.Repo.Repository + // archive / un-archive + if opts.Archived != nil { + if repo.IsMirror { + err := fmt.Errorf("repo is a mirror, cannot archive/un-archive") + ctx.Error(http.StatusUnprocessableEntity, err.Error(), err) + return err + } + if *opts.Archived { + if err := repo.SetArchiveRepoState(*opts.Archived); err != nil { + log.Error("Tried to archive a repo: %s", err) + ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) + return err + } + log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) + } else { + if err := repo.SetArchiveRepoState(*opts.Archived); err != nil { + log.Error("Tried to un-archive a repo: %s", err) + ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) + return err + } + log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) + } + } + return nil +} + // Delete one repository func Delete(ctx *context.APIContext) { // swagger:operation DELETE /repos/{owner}/{repo} repository repoDelete diff --git a/routers/api/v1/repo/repo_test.go b/routers/api/v1/repo/repo_test.go new file mode 100644 index 0000000000..053134ec61 --- /dev/null +++ b/routers/api/v1/repo/repo_test.go @@ -0,0 +1,82 @@ +// Copyright 2019 The Gitea 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 repo + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/test" + + "github.com/stretchr/testify/assert" +) + +func TestRepoEdit(t *testing.T) { + models.PrepareTestEnv(t) + + ctx := test.MockContext(t, "user2/repo1") + test.LoadRepo(t, ctx, 1) + test.LoadUser(t, ctx, 2) + ctx.Repo.Owner = ctx.User + description := "new description" + website := "http://wwww.newwebsite.com" + private := true + hasIssues := false + hasWiki := false + defaultBranch := "master" + hasPullRequests := true + ignoreWhitespaceConflicts := true + allowMerge := false + allowRebase := false + allowRebaseMerge := false + allowSquashMerge := false + archived := true + opts := api.EditRepoOption{ + Name: &ctx.Repo.Repository.Name, + Description: &description, + Website: &website, + Private: &private, + HasIssues: &hasIssues, + HasWiki: &hasWiki, + DefaultBranch: &defaultBranch, + HasPullRequests: &hasPullRequests, + IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts, + AllowMerge: &allowMerge, + AllowRebase: &allowRebase, + AllowRebaseMerge: &allowRebaseMerge, + AllowSquash: &allowSquashMerge, + Archived: &archived, + } + + Edit(&context.APIContext{Context: ctx, Org: nil}, opts) + + assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) + models.AssertExistsAndLoadBean(t, &models.Repository{ + ID: 1, + }, models.Cond("name = ? AND is_archived = 1", *opts.Name)) +} + +func TestRepoEditNameChange(t *testing.T) { + models.PrepareTestEnv(t) + + ctx := test.MockContext(t, "user2/repo1") + test.LoadRepo(t, ctx, 1) + test.LoadUser(t, ctx, 2) + ctx.Repo.Owner = ctx.User + name := "newname" + opts := api.EditRepoOption{ + Name: &name, + } + + Edit(&context.APIContext{Context: ctx, Org: nil}, opts) + assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) + + models.AssertExistsAndLoadBean(t, &models.Repository{ + ID: 1, + }, models.Cond("name = ?", opts.Name)) +} diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index 2df97304aa..c1196eeb71 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -82,6 +82,8 @@ type swaggerParameterBodies struct { // in:body CreateRepoOption api.CreateRepoOption // in:body + EditRepoOption api.EditRepoOption + // in:body CreateForkOption api.CreateForkOption // in:body diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 7307d1284b..a3090d1d52 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -1210,6 +1210,51 @@ "$ref": "#/responses/forbidden" } } + }, + "patch": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Edit a repository's properties. Only fields that are set will be changed.", + "operationId": "repoEdit", + "parameters": [ + { + "type": "string", + "description": "owner of the repo to edit", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo to edit", + "name": "repo", + "in": "path", + "required": true + }, + { + "description": "Properties of a repo that you can edit", + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/EditRepoOption" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/Repository" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "422": { + "$ref": "#/responses/validationError" + } + } } }, "/repos/{owner}/{repo}/archive/{archive}": { @@ -6037,6 +6082,12 @@ "responses": { "201": { "$ref": "#/responses/Repository" + }, + "409": { + "description": "The repository with the same name already exists." + }, + "422": { + "$ref": "#/responses/validationError" } } } @@ -7738,6 +7789,84 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "EditRepoOption": { + "description": "EditRepoOption options when editing a repository's properties", + "type": "object", + "properties": { + "allow_merge_commits": { + "description": "either `true` to allow merging pull requests with a merge commit, or `false` to prevent merging pull requests with merge commits. `has_pull_requests` must be `true`.", + "type": "boolean", + "x-go-name": "AllowMerge" + }, + "allow_rebase": { + "description": "either `true` to allow rebase-merging pull requests, or `false` to prevent rebase-merging. `has_pull_requests` must be `true`.", + "type": "boolean", + "x-go-name": "AllowRebase" + }, + "allow_rebase_explicit": { + "description": "either `true` to allow rebase with explicit merge commits (--no-ff), or `false` to prevent rebase with explicit merge commits. `has_pull_requests` must be `true`.", + "type": "boolean", + "x-go-name": "AllowRebaseMerge" + }, + "allow_squash_merge": { + "description": "either `true` to allow squash-merging pull requests, or `false` to prevent squash-merging. `has_pull_requests` must be `true`.", + "type": "boolean", + "x-go-name": "AllowSquash" + }, + "archived": { + "description": "set to `true` to archive this repository.", + "type": "boolean", + "x-go-name": "Archived" + }, + "default_branch": { + "description": "sets the default branch for this repository.", + "type": "string", + "x-go-name": "DefaultBranch" + }, + "description": { + "description": "a short description of the repository.", + "type": "string", + "x-go-name": "Description" + }, + "has_issues": { + "description": "either `true` to enable issues for this repository or `false` to disable them.", + "type": "boolean", + "x-go-name": "HasIssues" + }, + "has_pull_requests": { + "description": "either `true` to allow pull requests, or `false` to prevent pull request.", + "type": "boolean", + "x-go-name": "HasPullRequests" + }, + "has_wiki": { + "description": "either `true` to enable the wiki for this repository or `false` to disable it.", + "type": "boolean", + "x-go-name": "HasWiki" + }, + "ignore_whitespace_conflicts": { + "description": "either `true` to ignore whitespace for conflicts, or `false` to not ignore whitespace. `has_pull_requests` must be `true`.", + "type": "boolean", + "x-go-name": "IgnoreWhitespaceConflicts" + }, + "name": { + "description": "name of the repository", + "type": "string", + "uniqueItems": true, + "x-go-name": "Name" + }, + "private": { + "description": "either `true` to make the repository private or `false` to make it public.\nNote: you will get a 422 error if the organization restricts changing repository visibility to organization\nowners and a non-owner tries to change the value of private.", + "type": "boolean", + "x-go-name": "Private" + }, + "website": { + "description": "a URL with more information about the repository.", + "type": "string", + "x-go-name": "Website" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "EditTeamOption": { "description": "EditTeamOption options for editing a team", "type": "object", @@ -9062,6 +9191,22 @@ "description": "Repository represents a repository", "type": "object", "properties": { + "allow_merge_commits": { + "type": "boolean", + "x-go-name": "AllowMerge" + }, + "allow_rebase": { + "type": "boolean", + "x-go-name": "AllowRebase" + }, + "allow_rebase_explicit": { + "type": "boolean", + "x-go-name": "AllowRebaseMerge" + }, + "allow_squash_merge": { + "type": "boolean", + "x-go-name": "AllowSquash" + }, "archived": { "type": "boolean", "x-go-name": "Archived" @@ -9104,6 +9249,18 @@ "type": "string", "x-go-name": "FullName" }, + "has_issues": { + "type": "boolean", + "x-go-name": "HasIssues" + }, + "has_pull_requests": { + "type": "boolean", + "x-go-name": "HasPullRequests" + }, + "has_wiki": { + "type": "boolean", + "x-go-name": "HasWiki" + }, "html_url": { "type": "string", "x-go-name": "HTMLURL" @@ -9113,6 +9270,10 @@ "format": "int64", "x-go-name": "ID" }, + "ignore_whitespace_conflicts": { + "type": "boolean", + "x-go-name": "IgnoreWhitespaceConflicts" + }, "mirror": { "type": "boolean", "x-go-name": "Mirror" From 97b6368b7d1a5709d12495ba84636c3003c5d4c3 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Thu, 30 May 2019 11:46:31 -0500 Subject: [PATCH 070/220] 1.8.2 changelog (#7079) (#7088) * 1.8.2 changelog --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 361ec20546..3b7547e1ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,21 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.8.2](https://github.com/go-gitea/gitea/releases/tag/v1.8.2) - 2019-05-29 +* BUGFIXES + * Fix possbile mysql invalid connnection error (#7051) (#7071) + * Handle invalid administrator username on install page (#7060) (#7063) + * Disable arm7 builds (#7037) (#7042) + * Fix default for allowing new organization creation for new users (#7017) (#7034) + * SearchRepositoryByName improvements and unification (#6897) (#7002) + * Fix u2f registrationlist ToRegistrations() method (#6980) (#6982) + * Allow collaborators to view repo owned by private org (#6965) (#6968) + * Use AppURL for Oauth user link (#6894) (#6925) + * Escape the commit message on issues update (#6901) (#6902) + * Fix regression for API users search (#6882) (#6885) + * Handle early git version's lack of get-url (#7065) (#7076) + * Fix wrong init dependency on markup extensions (#7038) (#7074) + ## [1.8.1](https://github.com/go-gitea/gitea/releases/tag/v1.8.1) - 2019-05-08 * BUGFIXES * Fix 404 when sending pull requests in some situations (#6871) (#6873) From d95caf50ec9e34a652a0e51baf5037c8cf424a01 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 30 May 2019 16:49:44 +0000 Subject: [PATCH 071/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 5 +++++ options/locale/locale_fr-FR.ini | 22 ++++++++++++++++++++++ options/locale/locale_ja-JP.ini | 2 ++ options/locale/locale_pt-BR.ini | 2 ++ 4 files changed, 31 insertions(+) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 7082e9e8a2..3a3e970d77 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -386,6 +386,7 @@ choose_new_avatar=Neues Profilbild auswählen update_avatar=Profilbild aktualisieren delete_current_avatar=Aktuelles Profilbild löschen uploaded_avatar_not_a_image=Die hochgeladene Datei ist kein Bild. +uploaded_avatar_is_too_big=Die hochgeladene Datei hat die maximale Größe überschritten. update_avatar_success=Dein Profilbild wurde geändert. change_password=Passwort aktualisieren @@ -615,6 +616,7 @@ migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Rep migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner. migrate.failed=Fehler bei der Migration: %v migrate.lfs_mirror_unsupported=Spiegeln von LFS-Objekten wird nicht unterstützt - nutze stattdessen 'git lfs fetch --all' und 'git lfs push --all'. +migrate.migrate_items_options=Wenn du von GitHub migrierst und einen Benutzernamen eingegeben hast, werden die Migrationsoptionen angezeigt. mirror_from=Mirror von forked_from=geforkt von @@ -1269,7 +1271,9 @@ settings.protected_branch_can_push_yes=Du kannst pushen settings.protected_branch_can_push_no=Du kannst nicht pushen settings.branch_protection=Branch-Schutz für Branch „%s“ settings.protect_this_branch=Branch-Schutz aktivieren +settings.protect_this_branch_desc=Löschen verhindern und „force pushing” von Git auf dieser Branch deaktivieren. settings.protect_whitelist_committers=Push-Whitelist aktivieren +settings.protect_whitelist_committers_desc=Erlaube, dass Benutzer oder Teams, die auf der Whitelist stehen, auf diese Branch "pushen" dürfen (aber nicht "force pushen"). settings.protect_whitelist_users=Nutzer, die pushen dürfen: settings.protect_whitelist_search_users=Benutzer suchen… settings.protect_whitelist_teams=Teams, die pushen dürfen: @@ -1307,6 +1311,7 @@ settings.unarchive.header=Archivieren dieses Repos rückgängig machen settings.unarchive.text=Das Rückgängig machen dieses Repo-Archivs stellt seine Fähigkeit wieder her, Commits und Pushes anzunehmen, sowie neue Issues und Pull-Requests zu erstellen. settings.unarchive.success=Die Archivierung des Repos wurde erfolgreich wieder rückgängig gemacht. settings.unarchive.error=Beim Rückgängig machen dieses Repo-Archivs trat ein Fehler auf. In den Logs befinden sich mehr Details. +settings.update_avatar_success=Der Repository-Avatar wurde aktualisiert. diff.browse_source=Quellcode durchsuchen diff.parent=Ursprung diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index c8dbfd9839..e6755f8cb5 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -86,12 +86,18 @@ host=Hôte user=Nom d'utilisateur password=Mot de passe db_name=Nom de base de données +db_helper=Note aux utilisateurs de MySQL : utilisez le moteur de stockage InnoDB et si vous utilisez "utf8mb4", votre version InnoDB doit être supérieure à 5.6 . ssl_mode=SSL +charset=Jeu de caractères path=Emplacement sqlite_helper=Chemin d'accès pour la base de données SQLite3.
    Entrer un chemin absolu si vous exécutez Gitea en tant que service. err_empty_db_path=Le chemin de la base de donnée SQLite3 ne peut être vide. no_admin_and_disable_registration=Vous ne pouvez pas désactiver la création de nouveaux utilisateurs avant d'avoir créé un compte administrateur. err_empty_admin_password=Le mot de passe administrateur ne peut pas être vide. +err_empty_admin_email=L'adresse e-mail de l'administrateur ne peut pas être vide. +err_admin_name_is_reserved=Le nom d'utilisateur de l'administrateur est invalide, le nom d'utilisateur est réservé +err_admin_name_pattern_not_allowed=Le nom d'utilisateur de l'administrateur est invalide, le nom d'utilisateur est interdit +err_admin_name_is_invalid=Le nom d'utilisateur de l'administrateur est invalide general_title=Configuration générale app_name=Titre du site @@ -299,6 +305,8 @@ password_not_match=Les mots de passe ne correspondent pas. username_been_taken=Le nom d'utilisateur est déjà pris. repo_name_been_taken=Ce nom de dépôt est déjà utilisé. +visit_rate_limit=Le taux d'appel à distance autorisé a été dépassé. +2fa_auth_required=L'accès à distance requiert une authentification à deux facteurs. org_name_been_taken=Ce nom d'organisation est déjà pris. team_name_been_taken=Le nom d'équipe est déjà pris. team_no_units_error=Autoriser l’accès à au moins une section du dépôt. @@ -380,6 +388,7 @@ choose_new_avatar=Sélectionner un nouvel avatar update_avatar=Mise à jour de l'avatar delete_current_avatar=Supprimer l'avatar actuel uploaded_avatar_not_a_image=Le fichier téléversé n'est pas une image. +uploaded_avatar_is_too_big=Le fichier téléversé dépasse la taille maximale. update_avatar_success=Votre avatar a été mis à jour. change_password=Modifier le mot de passe @@ -595,6 +604,13 @@ form.name_pattern_not_allowed=%s" n'est pas autorisé dans un nom de dépôt. need_auth=Autorisations de clonage migrate_type=Type de migration migrate_type_helper=Ce dépôt sera un miroir +migrate_items=Éléments à migrer +migrate_items_wiki=Wiki +migrate_items_milestones=Jalons +migrate_items_labels=Étiquettes +migrate_items_issues=Tickets +migrate_items_pullrequests=Demandes d'ajout +migrate_items_releases=Versions migrate_repo=Migrer le dépôt migrate.clone_address=Migrer/Cloner depuis une URL migrate.clone_address_desc=L'URL HTTP(S) ou Git "clone" d'un dépôt existant @@ -603,6 +619,7 @@ migrate.permission_denied=Vous n'êtes pas autorisé à importer des dépôts lo migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas un dossier. migrate.failed=Echec de migration: %v migrate.lfs_mirror_unsupported=La synchronisation des objets LFS n'est pas supportée - veuillez utiliser 'git lfs fetch --all' et 'git lfs push --all' à la place. +migrate.migrate_items_options=Quand vous migrez depuis github, une fois le nom d'utilisateur saisi, des options de migration supplémentaires seront affichées. mirror_from=miroir de forked_from=bifurqué depuis @@ -1257,7 +1274,9 @@ settings.protected_branch_can_push_yes=Vous pouvez pousser settings.protected_branch_can_push_no=Vous ne pouvez pas pousser settings.branch_protection=Protection de la branche "%s settings.protect_this_branch=Protection de la branche +settings.protect_this_branch_desc=Interdire de supprimer et de pousser sur la branche. settings.protect_whitelist_committers=Activer la liste blanche pour les mises à jour +settings.protect_whitelist_committers_desc=Autoriser les utilisateurs et les équipes sur liste blanche à supprimer et pousser sur la branche (mais pas de poussée forcée). settings.protect_whitelist_users=Utilisateurs en liste blanche : settings.protect_whitelist_search_users=Rechercher des utilisateurs… settings.protect_whitelist_teams=Équipes en liste blanche : @@ -1295,10 +1314,12 @@ settings.unarchive.header=Désarchiver ce dépôt settings.unarchive.text=Désarchiver le dépôt lui permettra de recevoir des révisions, ainsi que des nouveaux tickets ou demandes d'ajout. settings.unarchive.success=Ce dépôt a été désarchivé avec succès. settings.unarchive.error=Une erreur s'est produite durant le désarchivage. Referez-vous au journal pour plus de détails. +settings.update_avatar_success=L'avatar du dépôt a été mis à jour. diff.browse_source=Parcourir la source diff.parent=Parent diff.commit=révision +diff.git-notes=Notes diff.data_not_available=Contenu de la comparaison indisponible diff.show_diff_stats=Afficher les stats Diff diff.show_split_view=Vue séparée @@ -1753,6 +1774,7 @@ config.cache_config=Configuration du cache config.cache_adapter=Adaptateur du Cache config.cache_interval=Intervales du Cache config.cache_conn=Liaison du Cache +config.cache_item_ttl=Durée de vie des éléments dans le cache config.session_config=Configuration de session config.session_provider=Fournisseur de session diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index beeeb848a2..e65162dfe2 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -388,6 +388,7 @@ choose_new_avatar=新しいアバターを選択 update_avatar=アバターを更新 delete_current_avatar=現在のアバターを削除 uploaded_avatar_not_a_image=アップロードしたファイルは画像ファイルではありません。 +uploaded_avatar_is_too_big=アップロードしたファイルは最大サイズを超えています。 update_avatar_success=アバターを更新しました。 change_password=パスワードを更新 @@ -1313,6 +1314,7 @@ settings.unarchive.header=このリポジトリをアーカイブ解除 settings.unarchive.text=リポジトリのアーカイブを解除すると、コミット、プッシュ、新規の課題やプルリクエストを受け付けるよう元に戻されます。 settings.unarchive.success=リポジトリのアーカイブを解除しました。 settings.unarchive.error=リポジトリのアーカイブ解除でエラーが発生しました。 詳細はログを確認してください。 +settings.update_avatar_success=リポジトリのアバターを更新しました。 diff.browse_source=ソースを参照 diff.parent=親 diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 26ff625df2..65b26c6ee9 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -388,6 +388,7 @@ choose_new_avatar=Escolha um novo avatar update_avatar=Atualizar o avatar delete_current_avatar=Excluir o avatar atual uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem. +uploaded_avatar_is_too_big=O arquivo enviado excedeu o tamanho máximo. update_avatar_success=Seu avatar foi atualizado. change_password=Atualizar senha @@ -1313,6 +1314,7 @@ settings.unarchive.header=Desarquivar este repositório settings.unarchive.text=Desarquivando um repositório irá restaurar a capacidade do mesmo receber commits, pushs, assim como novas issues e pull requests. settings.unarchive.success=O repositório foi desarquivado com sucesso. settings.unarchive.error=Um erro ocorreu enquanto estava sendo desarquivado o repositório. Veja o log para mais detalhes. +settings.update_avatar_success=O avatar do repositório foi atualizado. diff.browse_source=Ver código fonte diff.parent=pai From 43cf2f3b55de4a69183966da2a6e0167592c733c Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Thu, 30 May 2019 13:57:55 -0400 Subject: [PATCH 072/220] Fixes #7023 - API Org Visibility (#7028) --- integrations/api_admin_org_test.go | 86 ++++++++++++++++++++++++++++++ integrations/api_org_test.go | 48 ++++++++++++++++- integrations/api_user_orgs_test.go | 2 + modules/structs/org.go | 33 +++++++----- modules/structs/org_type.go | 10 ++++ modules/structs/repo_file.go | 26 ++++++--- routers/api/v1/admin/org.go | 7 +++ routers/api/v1/convert/convert.go | 1 + routers/api/v1/org/org.go | 14 ++++- routers/api/v1/repo/file.go | 6 +-- templates/swagger/v1_json.tmpl | 65 +++++++++++++++++----- 11 files changed, 258 insertions(+), 40 deletions(-) create mode 100644 integrations/api_admin_org_test.go diff --git a/integrations/api_admin_org_test.go b/integrations/api_admin_org_test.go new file mode 100644 index 0000000000..546ed861c2 --- /dev/null +++ b/integrations/api_admin_org_test.go @@ -0,0 +1,86 @@ +// Copyright 2019 The Gitea 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 integrations + +import ( + "net/http" + "net/url" + "strings" + "testing" + + "code.gitea.io/gitea/models" + api "code.gitea.io/gitea/modules/structs" + + "github.com/stretchr/testify/assert" +) + +func TestAPIAdminOrgCreate(t *testing.T) { + onGiteaRun(t, func(*testing.T, *url.URL) { + session := loginUser(t, "user1") + token := getTokenForLoggedInUser(t, session) + + var org = api.CreateOrgOption{ + UserName: "user2_org", + FullName: "User2's organization", + Description: "This organization created by admin for user2", + Website: "https://try.gitea.io", + Location: "Shanghai", + Visibility: "private", + } + req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs?token="+token, &org) + resp := session.MakeRequest(t, req, http.StatusCreated) + + var apiOrg api.Organization + DecodeJSON(t, resp, &apiOrg) + + assert.Equal(t, org.UserName, apiOrg.UserName) + assert.Equal(t, org.FullName, apiOrg.FullName) + assert.Equal(t, org.Description, apiOrg.Description) + assert.Equal(t, org.Website, apiOrg.Website) + assert.Equal(t, org.Location, apiOrg.Location) + assert.Equal(t, org.Visibility, apiOrg.Visibility) + + models.AssertExistsAndLoadBean(t, &models.User{ + Name: org.UserName, + LowerName: strings.ToLower(org.UserName), + FullName: org.FullName, + }) + }) +} + +func TestAPIAdminOrgCreateBadVisibility(t *testing.T) { + onGiteaRun(t, func(*testing.T, *url.URL) { + session := loginUser(t, "user1") + token := getTokenForLoggedInUser(t, session) + + var org = api.CreateOrgOption{ + UserName: "user2_org", + FullName: "User2's organization", + Description: "This organization created by admin for user2", + Website: "https://try.gitea.io", + Location: "Shanghai", + Visibility: "notvalid", + } + req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs?token="+token, &org) + session.MakeRequest(t, req, http.StatusUnprocessableEntity) + }) +} + +func TestAPIAdminOrgCreateNotAdmin(t *testing.T) { + prepareTestEnv(t) + nonAdminUsername := "user2" + session := loginUser(t, nonAdminUsername) + token := getTokenForLoggedInUser(t, session) + var org = api.CreateOrgOption{ + UserName: "user2_org", + FullName: "User2's organization", + Description: "This organization created by admin for user2", + Website: "https://try.gitea.io", + Location: "Shanghai", + Visibility: "public", + } + req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs?token="+token, &org) + session.MakeRequest(t, req, http.StatusForbidden) +} diff --git a/integrations/api_org_test.go b/integrations/api_org_test.go index b36650f2e8..34579aa1ea 100644 --- a/integrations/api_org_test.go +++ b/integrations/api_org_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestAPIOrg(t *testing.T) { +func TestAPIOrgCreate(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { session := loginUser(t, "user1") @@ -28,6 +28,7 @@ func TestAPIOrg(t *testing.T) { Description: "This organization created by user1", Website: "https://try.gitea.io", Location: "Shanghai", + Visibility: "limited", } req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &org) resp := session.MakeRequest(t, req, http.StatusCreated) @@ -40,6 +41,7 @@ func TestAPIOrg(t *testing.T) { assert.Equal(t, org.Description, apiOrg.Description) assert.Equal(t, org.Website, apiOrg.Website) assert.Equal(t, org.Location, apiOrg.Location) + assert.Equal(t, org.Visibility, apiOrg.Visibility) models.AssertExistsAndLoadBean(t, &models.User{ Name: org.UserName, @@ -72,6 +74,50 @@ func TestAPIOrg(t *testing.T) { }) } +func TestAPIOrgEdit(t *testing.T) { + onGiteaRun(t, func(*testing.T, *url.URL) { + session := loginUser(t, "user1") + + token := getTokenForLoggedInUser(t, session) + var org = api.EditOrgOption{ + FullName: "User3 organization new full name", + Description: "A new description", + Website: "https://try.gitea.io/new", + Location: "Beijing", + Visibility: "private", + } + req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/user3?token="+token, &org) + resp := session.MakeRequest(t, req, http.StatusOK) + + var apiOrg api.Organization + DecodeJSON(t, resp, &apiOrg) + + assert.Equal(t, "user3", apiOrg.UserName) + assert.Equal(t, org.FullName, apiOrg.FullName) + assert.Equal(t, org.Description, apiOrg.Description) + assert.Equal(t, org.Website, apiOrg.Website) + assert.Equal(t, org.Location, apiOrg.Location) + assert.Equal(t, org.Visibility, apiOrg.Visibility) + }) +} + +func TestAPIOrgEditBadVisibility(t *testing.T) { + onGiteaRun(t, func(*testing.T, *url.URL) { + session := loginUser(t, "user1") + + token := getTokenForLoggedInUser(t, session) + var org = api.EditOrgOption{ + FullName: "User3 organization new full name", + Description: "A new description", + Website: "https://try.gitea.io/new", + Location: "Beijing", + Visibility: "badvisibility", + } + req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/user3?token="+token, &org) + session.MakeRequest(t, req, http.StatusUnprocessableEntity) + }) +} + func TestAPIOrgDeny(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { setting.Service.RequireSignInView = true diff --git a/integrations/api_user_orgs_test.go b/integrations/api_user_orgs_test.go index 63e67f4356..6611a429d1 100644 --- a/integrations/api_user_orgs_test.go +++ b/integrations/api_user_orgs_test.go @@ -38,6 +38,7 @@ func TestUserOrgs(t *testing.T) { Description: "", Website: "", Location: "", + Visibility: "public", }, }, orgs) } @@ -63,6 +64,7 @@ func TestMyOrgs(t *testing.T) { Description: "", Website: "", Location: "", + Visibility: "public", }, }, orgs) } diff --git a/modules/structs/org.go b/modules/structs/org.go index fd15da1ce9..08ab139975 100644 --- a/modules/structs/org.go +++ b/modules/structs/org.go @@ -6,25 +6,27 @@ package structs // Organization represents an organization type Organization struct { - ID int64 `json:"id"` - UserName string `json:"username"` - FullName string `json:"full_name"` - AvatarURL string `json:"avatar_url"` - Description string `json:"description"` - Website string `json:"website"` - Location string `json:"location"` - Visibility VisibleType `json:"visibility"` + ID int64 `json:"id"` + UserName string `json:"username"` + FullName string `json:"full_name"` + AvatarURL string `json:"avatar_url"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` + Visibility string `json:"visibility"` } // CreateOrgOption options for creating an organization type CreateOrgOption struct { // required: true - UserName string `json:"username" binding:"Required"` - FullName string `json:"full_name"` - Description string `json:"description"` - Website string `json:"website"` - Location string `json:"location"` - Visibility VisibleType `json:"visibility"` + UserName string `json:"username" binding:"Required"` + FullName string `json:"full_name"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` + // possible values are `public` (default), `limited` or `private` + // enum: public,limited,private + Visibility string `json:"visibility" binding:"In(,public,limited,private)"` } // EditOrgOption options for editing an organization @@ -33,4 +35,7 @@ type EditOrgOption struct { Description string `json:"description"` Website string `json:"website"` Location string `json:"location"` + // possible values are `public`, `limited` or `private` + // enum: public,limited,private + Visibility string `json:"visibility" binding:"In(,public,limited,private)"` } diff --git a/modules/structs/org_type.go b/modules/structs/org_type.go index 86dc5c81cd..4fb9b6fc0f 100644 --- a/modules/structs/org_type.go +++ b/modules/structs/org_type.go @@ -40,6 +40,16 @@ func (vt VisibleType) IsPrivate() bool { return vt == VisibleTypePrivate } +// VisibilityString provides the mode string of the visibility type (public, limited, private) +func (vt VisibleType) String() string { + for k, v := range VisibilityModes { + if vt == v { + return k + } + } + return "" +} + // ExtractKeysFromMapString provides a slice of keys from map func ExtractKeysFromMapString(in map[string]VisibleType) (keys []string) { for k := range in { diff --git a/modules/structs/repo_file.go b/modules/structs/repo_file.go index ac8b9333fe..c447d26724 100644 --- a/modules/structs/repo_file.go +++ b/modules/structs/repo_file.go @@ -7,29 +7,43 @@ package structs // FileOptions options for all file APIs type FileOptions struct { - Message string `json:"message" binding:"Required"` - BranchName string `json:"branch"` - NewBranchName string `json:"new_branch"` - Author Identity `json:"author"` - Committer Identity `json:"committer"` + // message (optional) for the commit of this file. if not supplied, a default message will be used + Message string `json:"message" binding:"Required"` + // branch (optional) to base this file from. if not given, the default branch is used + BranchName string `json:"branch"` + // new_branch (optional) will make a new branch from `branch` before creating the file + NewBranchName string `json:"new_branch"` + // `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used) + Author Identity `json:"author"` + Committer Identity `json:"committer"` } // CreateFileOptions options for creating files +// Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used) type CreateFileOptions struct { FileOptions + // content must be base64 encoded + // required: true Content string `json:"content"` } // DeleteFileOptions options for deleting files (used for other File structs below) +// Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used) type DeleteFileOptions struct { FileOptions + // sha is the SHA for the file that already exists + // required: true SHA string `json:"sha" binding:"Required"` } // UpdateFileOptions options for updating files +// Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used) type UpdateFileOptions struct { DeleteFileOptions - Content string `json:"content"` + // content must be base64 encoded + // required: true + Content string `json:"content"` + // from_path (optional) is the path of the original file which will be moved/renamed to the path in the URL FromPath string `json:"from_path" binding:"MaxSize(500)"` } diff --git a/routers/api/v1/admin/org.go b/routers/api/v1/admin/org.go index fba41a8cfe..d740647cd4 100644 --- a/routers/api/v1/admin/org.go +++ b/routers/api/v1/admin/org.go @@ -45,6 +45,11 @@ func CreateOrg(ctx *context.APIContext, form api.CreateOrgOption) { return } + visibility := api.VisibleTypePublic + if form.Visibility != "" { + visibility = api.VisibilityModes[form.Visibility] + } + org := &models.User{ Name: form.UserName, FullName: form.FullName, @@ -53,7 +58,9 @@ func CreateOrg(ctx *context.APIContext, form api.CreateOrgOption) { Location: form.Location, IsActive: true, Type: models.UserTypeOrganization, + Visibility: visibility, } + if err := models.CreateOrganization(org, u); err != nil { if models.IsErrUserAlreadyExist(err) || models.IsErrNameReserved(err) || diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index 74fd9b3afd..ba61c7e46c 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -213,6 +213,7 @@ func ToOrganization(org *models.User) *api.Organization { Description: org.Description, Website: org.Website, Location: org.Location, + Visibility: org.Visibility.String(), } } diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index e1d0663f05..2893887a4b 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -90,6 +90,11 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) { return } + visibility := api.VisibleTypePublic + if form.Visibility != "" { + visibility = api.VisibilityModes[form.Visibility] + } + org := &models.User{ Name: form.UserName, FullName: form.FullName, @@ -98,6 +103,7 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) { Location: form.Location, IsActive: true, Type: models.UserTypeOrganization, + Visibility: visibility, } if err := models.CreateOrganization(org, ctx.User); err != nil { if models.IsErrUserAlreadyExist(err) || @@ -153,6 +159,7 @@ func Edit(ctx *context.APIContext, form api.EditOrgOption) { // required: true // - name: body // in: body + // required: true // schema: // "$ref": "#/definitions/EditOrgOption" // responses: @@ -163,8 +170,11 @@ func Edit(ctx *context.APIContext, form api.EditOrgOption) { org.Description = form.Description org.Website = form.Website org.Location = form.Location - if err := models.UpdateUserCols(org, "full_name", "description", "website", "location"); err != nil { - ctx.Error(500, "UpdateUser", err) + if form.Visibility != "" { + org.Visibility = api.VisibilityModes[form.Visibility] + } + if err := models.UpdateUserCols(org, "full_name", "description", "website", "location", "visibility"); err != nil { + ctx.Error(500, "EditOrganization", err) return } diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index db952263e2..20f80f37f4 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -181,7 +181,7 @@ func CreateFile(ctx *context.APIContext, apiOpts api.CreateFileOptions) { // required: true // - name: body // in: body - // description: "'content' must be base64 encoded\n\n 'author' and 'committer' are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)\n\n If 'branch' is not given, default branch will be used\n\n 'sha' is the SHA for the file that already exists\n\n 'new_branch' (optional) will make a new branch from 'branch' before creating the file" + // required: true // schema: // "$ref": "#/definitions/CreateFileOptions" // responses: @@ -238,7 +238,7 @@ func UpdateFile(ctx *context.APIContext, apiOpts api.UpdateFileOptions) { // required: true // - name: body // in: body - // description: "'content' must be base64 encoded\n\n 'sha' is the SHA for the file that already exists\n\n 'author' and 'committer' are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)\n\n If 'branch' is not given, default branch will be used\n\n 'new_branch' (optional) will make a new branch from 'branch' before updating the file" + // required: true // schema: // "$ref": "#/definitions/UpdateFileOptions" // responses: @@ -316,7 +316,7 @@ func DeleteFile(ctx *context.APIContext, apiOpts api.DeleteFileOptions) { // required: true // - name: body // in: body - // description: "'sha' is the SHA for the file to be deleted\n\n 'author' and 'committer' are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)\n\n If 'branch' is not given, default branch will be used\n\n 'new_branch' (optional) will make a new branch from 'branch' before deleting the file" + // required: true // schema: // "$ref": "#/definitions/DeleteFileOptions" // responses: diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index a3090d1d52..77515bb139 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -552,6 +552,7 @@ { "name": "body", "in": "body", + "required": true, "schema": { "$ref": "#/definitions/EditOrgOption" } @@ -1649,9 +1650,9 @@ "required": true }, { - "description": "'content' must be base64 encoded\n\n 'sha' is the SHA for the file that already exists\n\n 'author' and 'committer' are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)\n\n If 'branch' is not given, default branch will be used\n\n 'new_branch' (optional) will make a new branch from 'branch' before updating the file", "name": "body", "in": "body", + "required": true, "schema": { "$ref": "#/definitions/UpdateFileOptions" } @@ -1698,9 +1699,9 @@ "required": true }, { - "description": "'content' must be base64 encoded\n\n 'author' and 'committer' are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)\n\n If 'branch' is not given, default branch will be used\n\n 'sha' is the SHA for the file that already exists\n\n 'new_branch' (optional) will make a new branch from 'branch' before creating the file", "name": "body", "in": "body", + "required": true, "schema": { "$ref": "#/definitions/CreateFileOptions" } @@ -1747,9 +1748,9 @@ "required": true }, { - "description": "'sha' is the SHA for the file to be deleted\n\n 'author' and 'committer' are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)\n\n If 'branch' is not given, default branch will be used\n\n 'new_branch' (optional) will make a new branch from 'branch' before deleting the file", "name": "body", "in": "body", + "required": true, "schema": { "$ref": "#/definitions/DeleteFileOptions" } @@ -6935,13 +6936,17 @@ "x-go-package": "code.gitea.io/gitea/modules/structs" }, "CreateFileOptions": { - "description": "CreateFileOptions options for creating files", + "description": "CreateFileOptions options for creating files\nNote: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)", "type": "object", + "required": [ + "content" + ], "properties": { "author": { "$ref": "#/definitions/Identity" }, "branch": { + "description": "branch (optional) to base this file from. if not given, the default branch is used", "type": "string", "x-go-name": "BranchName" }, @@ -6949,14 +6954,17 @@ "$ref": "#/definitions/Identity" }, "content": { + "description": "content must be base64 encoded", "type": "string", "x-go-name": "Content" }, "message": { + "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", "type": "string", "x-go-name": "Message" }, "new_branch": { + "description": "new_branch (optional) will make a new branch from `branch` before creating the file", "type": "string", "x-go-name": "NewBranchName" } @@ -7191,7 +7199,14 @@ "x-go-name": "UserName" }, "visibility": { - "$ref": "#/definitions/VisibleType" + "description": "possible values are `public` (default), `limited` or `private`", + "type": "string", + "enum": [ + "public", + "limited", + "private" + ], + "x-go-name": "Visibility" }, "website": { "type": "string", @@ -7459,13 +7474,17 @@ "x-go-package": "code.gitea.io/gitea/modules/structs" }, "DeleteFileOptions": { - "description": "DeleteFileOptions options for deleting files (used for other File structs below)", + "description": "DeleteFileOptions options for deleting files (used for other File structs below)\nNote: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)", "type": "object", + "required": [ + "sha" + ], "properties": { "author": { "$ref": "#/definitions/Identity" }, "branch": { + "description": "branch (optional) to base this file from. if not given, the default branch is used", "type": "string", "x-go-name": "BranchName" }, @@ -7473,14 +7492,17 @@ "$ref": "#/definitions/Identity" }, "message": { + "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", "type": "string", "x-go-name": "Message" }, "new_branch": { + "description": "new_branch (optional) will make a new branch from `branch` before creating the file", "type": "string", "x-go-name": "NewBranchName" }, "sha": { + "description": "sha is the SHA for the file that already exists", "type": "string", "x-go-name": "SHA" } @@ -7703,6 +7725,16 @@ "type": "string", "x-go-name": "Location" }, + "visibility": { + "description": "possible values are `public`, `limited` or `private`", + "type": "string", + "enum": [ + "public", + "limited", + "private" + ], + "x-go-name": "Visibility" + }, "website": { "type": "string", "x-go-name": "Website" @@ -8741,7 +8773,8 @@ "x-go-name": "UserName" }, "visibility": { - "$ref": "#/definitions/VisibleType" + "type": "string", + "x-go-name": "Visibility" }, "website": { "type": "string", @@ -9537,13 +9570,18 @@ "x-go-package": "code.gitea.io/gitea/modules/structs" }, "UpdateFileOptions": { - "description": "UpdateFileOptions options for updating files", + "description": "UpdateFileOptions options for updating files\nNote: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)", "type": "object", + "required": [ + "sha", + "content" + ], "properties": { "author": { "$ref": "#/definitions/Identity" }, "branch": { + "description": "branch (optional) to base this file from. if not given, the default branch is used", "type": "string", "x-go-name": "BranchName" }, @@ -9551,22 +9589,27 @@ "$ref": "#/definitions/Identity" }, "content": { + "description": "content must be base64 encoded", "type": "string", "x-go-name": "Content" }, "from_path": { + "description": "from_path (optional) is the path of the original file which will be moved/renamed to the path in the URL", "type": "string", "x-go-name": "FromPath" }, "message": { + "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", "type": "string", "x-go-name": "Message" }, "new_branch": { + "description": "new_branch (optional) will make a new branch from `branch` before creating the file", "type": "string", "x-go-name": "NewBranchName" }, "sha": { + "description": "sha is the SHA for the file that already exists", "type": "string", "x-go-name": "SHA" } @@ -9631,12 +9674,6 @@ }, "x-go-package": "code.gitea.io/gitea/models" }, - "VisibleType": { - "description": "VisibleType defines the visibility (Organization only)", - "type": "integer", - "format": "int64", - "x-go-package": "code.gitea.io/gitea/modules/structs" - }, "WatchInfo": { "description": "WatchInfo represents an API watch status of one repository", "type": "object", From 7d12ec2abd452c6a8a5981537ce2c50440979e25 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 31 May 2019 04:26:57 +0800 Subject: [PATCH 073/220] improve github downloader on migrations (#7049) * improve github downloader on migrations * fix tests * fix uppercase function parameters --- modules/migrations/base/downloader.go | 4 +- modules/migrations/git.go | 8 +- modules/migrations/github.go | 264 ++++++++++++-------------- modules/migrations/github_test.go | 6 +- modules/migrations/migrate.go | 10 +- 5 files changed, 141 insertions(+), 151 deletions(-) diff --git a/modules/migrations/base/downloader.go b/modules/migrations/base/downloader.go index 9a09fdac0a..f28d0b61e7 100644 --- a/modules/migrations/base/downloader.go +++ b/modules/migrations/base/downloader.go @@ -11,9 +11,9 @@ type Downloader interface { GetMilestones() ([]*Milestone, error) GetReleases() ([]*Release, error) GetLabels() ([]*Label, error) - GetIssues(start, limit int) ([]*Issue, error) + GetIssues(page, perPage int) ([]*Issue, bool, error) GetComments(issueNumber int64) ([]*Comment, error) - GetPullRequests(start, limit int) ([]*PullRequest, error) + GetPullRequests(page, perPage int) ([]*PullRequest, error) } // DownloaderFactory defines an interface to match a downloader implementation and create a downloader diff --git a/modules/migrations/git.go b/modules/migrations/git.go index cbaa372821..335d44ec9b 100644 --- a/modules/migrations/git.go +++ b/modules/migrations/git.go @@ -53,9 +53,9 @@ func (g *PlainGitDownloader) GetReleases() ([]*base.Release, error) { return nil, ErrNotSupported } -// GetIssues returns issues according start and limit -func (g *PlainGitDownloader) GetIssues(start, limit int) ([]*base.Issue, error) { - return nil, ErrNotSupported +// GetIssues returns issues according page and perPage +func (g *PlainGitDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { + return nil, false, ErrNotSupported } // GetComments returns comments according issueNumber @@ -63,7 +63,7 @@ func (g *PlainGitDownloader) GetComments(issueNumber int64) ([]*base.Comment, er return nil, ErrNotSupported } -// GetPullRequests returns pull requests according start and limit +// GetPullRequests returns pull requests according page and perPage func (g *PlainGitDownloader) GetPullRequests(start, limit int) ([]*base.PullRequest, error) { return nil, ErrNotSupported } diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 8e1cd67df8..21c1becedf 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -272,71 +272,65 @@ func convertGithubReactions(reactions *github.Reactions) *base.Reactions { } // GetIssues returns issues according start and limit -func (g *GithubDownloaderV3) GetIssues(start, limit int) ([]*base.Issue, error) { - var perPage = 100 +func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { opt := &github.IssueListByRepoOptions{ Sort: "created", Direction: "asc", State: "all", ListOptions: github.ListOptions{ PerPage: perPage, + Page: page, }, } - var allIssues = make([]*base.Issue, 0, limit) - for { - issues, resp, err := g.client.Issues.ListByRepo(g.ctx, g.repoOwner, g.repoName, opt) - if err != nil { - return nil, fmt.Errorf("error while listing repos: %v", err) - } - for _, issue := range issues { - if issue.IsPullRequest() { - continue - } - var body string - if issue.Body != nil { - body = *issue.Body - } - var milestone string - if issue.Milestone != nil { - milestone = *issue.Milestone.Title - } - var labels = make([]*base.Label, 0, len(issue.Labels)) - for _, l := range issue.Labels { - labels = append(labels, convertGithubLabel(&l)) - } - var reactions *base.Reactions - if issue.Reactions != nil { - reactions = convertGithubReactions(issue.Reactions) - } - var email string - if issue.User.Email != nil { - email = *issue.User.Email - } - allIssues = append(allIssues, &base.Issue{ - Title: *issue.Title, - Number: int64(*issue.Number), - PosterName: *issue.User.Login, - PosterEmail: email, - Content: body, - Milestone: milestone, - State: *issue.State, - Created: *issue.CreatedAt, - Labels: labels, - Reactions: reactions, - Closed: issue.ClosedAt, - IsLocked: *issue.Locked, - }) - if len(allIssues) >= limit { - return allIssues, nil - } - } - if resp.NextPage == 0 { - break - } - opt.Page = resp.NextPage + var allIssues = make([]*base.Issue, 0, perPage) + + issues, _, err := g.client.Issues.ListByRepo(g.ctx, g.repoOwner, g.repoName, opt) + if err != nil { + return nil, false, fmt.Errorf("error while listing repos: %v", err) } - return allIssues, nil + for _, issue := range issues { + if issue.IsPullRequest() { + continue + } + var body string + if issue.Body != nil { + body = *issue.Body + } + var milestone string + if issue.Milestone != nil { + milestone = *issue.Milestone.Title + } + var labels = make([]*base.Label, 0, len(issue.Labels)) + for _, l := range issue.Labels { + labels = append(labels, convertGithubLabel(&l)) + } + var reactions *base.Reactions + if issue.Reactions != nil { + reactions = convertGithubReactions(issue.Reactions) + } + + var email string + if issue.User.Email != nil { + email = *issue.User.Email + } + allIssues = append(allIssues, &base.Issue{ + Title: *issue.Title, + Number: int64(*issue.Number), + PosterName: *issue.User.Login, + PosterEmail: email, + Content: body, + Milestone: milestone, + State: *issue.State, + Created: *issue.CreatedAt, + Labels: labels, + Reactions: reactions, + Closed: issue.ClosedAt, + IsLocked: *issue.Locked, + }) + } + + return allIssues, len(issues) < perPage, nil } // GetComments returns comments according issueNumber @@ -379,97 +373,91 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er return allComments, nil } -// GetPullRequests returns pull requests according start and limit -func (g *GithubDownloaderV3) GetPullRequests(start, limit int) ([]*base.PullRequest, error) { +// GetPullRequests returns pull requests according page and perPage +func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullRequest, error) { opt := &github.PullRequestListOptions{ Sort: "created", Direction: "asc", State: "all", ListOptions: github.ListOptions{ - PerPage: 100, + PerPage: perPage, + Page: page, }, } - var allPRs = make([]*base.PullRequest, 0, 100) - for { - prs, resp, err := g.client.PullRequests.List(g.ctx, g.repoOwner, g.repoName, opt) - if err != nil { - return nil, fmt.Errorf("error while listing repos: %v", err) - } - for _, pr := range prs { - var body string - if pr.Body != nil { - body = *pr.Body - } - var milestone string - if pr.Milestone != nil { - milestone = *pr.Milestone.Title - } - var labels = make([]*base.Label, 0, len(pr.Labels)) - for _, l := range pr.Labels { - labels = append(labels, convertGithubLabel(l)) - } + var allPRs = make([]*base.PullRequest, 0, perPage) - // FIXME: This API missing reactions, we may need another extra request to get reactions - - var email string - if pr.User.Email != nil { - email = *pr.User.Email - } - var merged bool - // pr.Merged is not valid, so use MergedAt to test if it's merged - if pr.MergedAt != nil { - merged = true - } - - var headRepoName string - var cloneURL string - if pr.Head.Repo != nil { - headRepoName = *pr.Head.Repo.Name - cloneURL = *pr.Head.Repo.CloneURL - } - var mergeCommitSHA string - if pr.MergeCommitSHA != nil { - mergeCommitSHA = *pr.MergeCommitSHA - } - - allPRs = append(allPRs, &base.PullRequest{ - Title: *pr.Title, - Number: int64(*pr.Number), - PosterName: *pr.User.Login, - PosterEmail: email, - Content: body, - Milestone: milestone, - State: *pr.State, - Created: *pr.CreatedAt, - Closed: pr.ClosedAt, - Labels: labels, - Merged: merged, - MergeCommitSHA: mergeCommitSHA, - MergedTime: pr.MergedAt, - IsLocked: pr.ActiveLockReason != nil, - Head: base.PullRequestBranch{ - Ref: *pr.Head.Ref, - SHA: *pr.Head.SHA, - RepoName: headRepoName, - OwnerName: *pr.Head.User.Login, - CloneURL: cloneURL, - }, - Base: base.PullRequestBranch{ - Ref: *pr.Base.Ref, - SHA: *pr.Base.SHA, - RepoName: *pr.Base.Repo.Name, - OwnerName: *pr.Base.User.Login, - }, - PatchURL: *pr.PatchURL, - }) - if len(allPRs) >= limit { - return allPRs, nil - } - } - if resp.NextPage == 0 { - break - } - opt.Page = resp.NextPage + prs, _, err := g.client.PullRequests.List(g.ctx, g.repoOwner, g.repoName, opt) + if err != nil { + return nil, fmt.Errorf("error while listing repos: %v", err) } + for _, pr := range prs { + var body string + if pr.Body != nil { + body = *pr.Body + } + var milestone string + if pr.Milestone != nil { + milestone = *pr.Milestone.Title + } + var labels = make([]*base.Label, 0, len(pr.Labels)) + for _, l := range pr.Labels { + labels = append(labels, convertGithubLabel(l)) + } + + // FIXME: This API missing reactions, we may need another extra request to get reactions + + var email string + if pr.User.Email != nil { + email = *pr.User.Email + } + var merged bool + // pr.Merged is not valid, so use MergedAt to test if it's merged + if pr.MergedAt != nil { + merged = true + } + + var headRepoName string + var cloneURL string + if pr.Head.Repo != nil { + headRepoName = *pr.Head.Repo.Name + cloneURL = *pr.Head.Repo.CloneURL + } + var mergeCommitSHA string + if pr.MergeCommitSHA != nil { + mergeCommitSHA = *pr.MergeCommitSHA + } + + allPRs = append(allPRs, &base.PullRequest{ + Title: *pr.Title, + Number: int64(*pr.Number), + PosterName: *pr.User.Login, + PosterEmail: email, + Content: body, + Milestone: milestone, + State: *pr.State, + Created: *pr.CreatedAt, + Closed: pr.ClosedAt, + Labels: labels, + Merged: merged, + MergeCommitSHA: mergeCommitSHA, + MergedTime: pr.MergedAt, + IsLocked: pr.ActiveLockReason != nil, + Head: base.PullRequestBranch{ + Ref: *pr.Head.Ref, + SHA: *pr.Head.SHA, + RepoName: headRepoName, + OwnerName: *pr.Head.User.Login, + CloneURL: cloneURL, + }, + Base: base.PullRequestBranch{ + Ref: *pr.Base.Ref, + SHA: *pr.Base.SHA, + RepoName: *pr.Base.Repo.Name, + OwnerName: *pr.Base.User.Login, + }, + PatchURL: *pr.PatchURL, + }) + } + return allPRs, nil } diff --git a/modules/migrations/github_test.go b/modules/migrations/github_test.go index e1d3efad58..c14292ecc6 100644 --- a/modules/migrations/github_test.go +++ b/modules/migrations/github_test.go @@ -166,9 +166,11 @@ func TestGitHubDownloadRepo(t *testing.T) { }, releases[len(releases)-1:]) // downloader.GetIssues() - issues, err := downloader.GetIssues(0, 3) + issues, isEnd, err := downloader.GetIssues(1, 8) assert.NoError(t, err) assert.EqualValues(t, 3, len(issues)) + assert.False(t, isEnd) + var ( closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC) ) @@ -319,7 +321,7 @@ something like in the latest 15days could be enough don't you think ? }, comments[:3]) // downloader.GetPullRequests() - prs, err := downloader.GetPullRequests(0, 3) + prs, err := downloader.GetPullRequests(1, 3) assert.NoError(t, err) assert.EqualValues(t, 3, len(prs)) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index ac55a2e727..4b1229f949 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -128,8 +128,8 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if opts.Issues { log.Trace("migrating issues and comments") - for { - issues, err := downloader.GetIssues(0, 100) + for i := 1; ; i++ { + issues, isEnd, err := downloader.GetIssues(i, 100) if err != nil { return err } @@ -160,7 +160,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } } - if len(issues) < 100 { + if isEnd { break } } @@ -168,8 +168,8 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if opts.PullRequests { log.Trace("migrating pull requests and comments") - for { - prs, err := downloader.GetPullRequests(0, 100) + for i := 1; ; i++ { + prs, err := downloader.GetPullRequests(i, 100) if err != nil { return err } From 592924a34b8e671c93416c01a468b9aab0ab39aa Mon Sep 17 00:00:00 2001 From: "Robert A. Nowak" Date: Thu, 30 May 2019 23:23:16 +0200 Subject: [PATCH 074/220] Fix Erlang and Elixir highlight mappings (#7044) --- modules/highlight/highlight.go | 72 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go index fc9a4ad103..6d5e1a97ba 100644 --- a/modules/highlight/highlight.go +++ b/modules/highlight/highlight.go @@ -26,45 +26,47 @@ var ( // Extensions that are same as highlight classes. highlightExts = map[string]struct{}{ - ".arm": {}, - ".as": {}, - ".sh": {}, - ".cs": {}, - ".cpp": {}, - ".c": {}, - ".css": {}, - ".cmake": {}, - ".bat": {}, - ".dart": {}, - ".patch": {}, - ".elixir": {}, - ".erlang": {}, - ".go": {}, - ".html": {}, - ".xml": {}, - ".hs": {}, - ".ini": {}, - ".json": {}, - ".java": {}, - ".js": {}, - ".less": {}, - ".lua": {}, - ".php": {}, - ".py": {}, - ".rb": {}, - ".scss": {}, - ".sql": {}, - ".scala": {}, - ".swift": {}, - ".ts": {}, - ".vb": {}, - ".yml": {}, - ".yaml": {}, + ".arm": {}, + ".as": {}, + ".sh": {}, + ".cs": {}, + ".cpp": {}, + ".c": {}, + ".css": {}, + ".cmake": {}, + ".bat": {}, + ".dart": {}, + ".patch": {}, + ".erl": {}, + ".go": {}, + ".html": {}, + ".xml": {}, + ".hs": {}, + ".ini": {}, + ".json": {}, + ".java": {}, + ".js": {}, + ".less": {}, + ".lua": {}, + ".php": {}, + ".py": {}, + ".rb": {}, + ".scss": {}, + ".sql": {}, + ".scala": {}, + ".swift": {}, + ".ts": {}, + ".vb": {}, + ".yml": {}, + ".yaml": {}, } // Extensions that are not same as highlight classes. highlightMapping = map[string]string{ - ".txt": "nohighlight", + ".txt": "nohighlight", + ".escript": "erlang", + ".ex": "elixir", + ".exs": "elixir", } ) From de6ef14d04c36272143ad822bf5903f84c7f238b Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Fri, 31 May 2019 05:21:15 -0400 Subject: [PATCH 075/220] Validate External Tracker URL Format (#7089) * Validate External Tracker URL Format Add some validation checks for external tracker URL format. Fixes #7068 * Don't make {index} a hard requirement * Fix Description * make fmt * move regex to package level * fix copyright date --- modules/validation/helpers.go | 19 +++++++++ modules/validation/helpers_test.go | 67 ++++++++++++++++++++++++++++++ routers/repo/setting.go | 2 +- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/modules/validation/helpers.go b/modules/validation/helpers.go index 9a4dfab7a4..c22e667a2e 100644 --- a/modules/validation/helpers.go +++ b/modules/validation/helpers.go @@ -7,6 +7,7 @@ package validation import ( "net" "net/url" + "regexp" "strings" "code.gitea.io/gitea/modules/setting" @@ -14,6 +15,8 @@ import ( var loopbackIPBlocks []*net.IPNet +var externalTrackerRegex = regexp.MustCompile(`({?)(?:user|repo|index)+?(}?)`) + func init() { for _, cidr := range []string{ "127.0.0.0/8", // IPv4 loopback @@ -75,3 +78,19 @@ func IsValidExternalURL(uri string) bool { return true } + +// IsValidExternalTrackerURLFormat checks if URL matches required syntax for external trackers +func IsValidExternalTrackerURLFormat(uri string) bool { + if !IsValidExternalURL(uri) { + return false + } + + // check for typoed variables like /{index/ or /[repo} + for _, match := range externalTrackerRegex.FindAllStringSubmatch(uri, -1) { + if (match[1] == "{" || match[2] == "}") && (match[1] != "{" || match[2] != "}") { + return false + } + } + + return true +} diff --git a/modules/validation/helpers_test.go b/modules/validation/helpers_test.go index 875625a02c..9051ee1a0d 100644 --- a/modules/validation/helpers_test.go +++ b/modules/validation/helpers_test.go @@ -88,3 +88,70 @@ func Test_IsValidExternalURL(t *testing.T) { }) } } + +func Test_IsValidExternalTrackerURLFormat(t *testing.T) { + setting.AppURL = "https://try.gitea.io/" + + cases := []struct { + description string + url string + valid bool + }{ + { + description: "Correct external tracker URL with all placeholders", + url: "https://github.com/{user}/{repo}/issues/{index}", + valid: true, + }, + { + description: "Local external tracker URL with all placeholders", + url: "https://127.0.0.1/{user}/{repo}/issues/{index}", + valid: false, + }, + { + description: "External tracker URL with typo placeholder", + url: "https://github.com/{user}/{repo/issues/{index}", + valid: false, + }, + { + description: "External tracker URL with typo placeholder", + url: "https://github.com/[user}/{repo/issues/{index}", + valid: false, + }, + { + description: "External tracker URL with typo placeholder", + url: "https://github.com/{user}/repo}/issues/{index}", + valid: false, + }, + { + description: "External tracker URL missing optional placeholder", + url: "https://github.com/{user}/issues/{index}", + valid: true, + }, + { + description: "External tracker URL missing optional placeholder", + url: "https://github.com/{repo}/issues/{index}", + valid: true, + }, + { + description: "External tracker URL missing optional placeholder", + url: "https://github.com/issues/{index}", + valid: true, + }, + { + description: "External tracker URL missing optional placeholder", + url: "https://github.com/issues/{user}", + valid: true, + }, + { + description: "External tracker URL with similar placeholder names test", + url: "https://github.com/user/repo/issues/{index}", + valid: true, + }, + } + + for _, testCase := range cases { + t.Run(testCase.description, func(t *testing.T) { + assert.Equal(t, testCase.valid, IsValidExternalTrackerURLFormat(testCase.url)) + }) + } +} diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 07649982d2..767cdacde0 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -249,7 +249,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { ctx.Redirect(repo.Link() + "/settings") return } - if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalURL(form.TrackerURLFormat) { + if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) { ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error")) ctx.Redirect(repo.Link() + "/settings") return From fb4438a815b013895f3171f8f2f1ed22f79596de Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 31 May 2019 11:12:15 +0100 Subject: [PATCH 076/220] Improve git test (#7086) * Ensure that the lfs files are created with a different prefix * Reduce the replication in git_test.go --- .../api_helper_for_declarative_test.go | 42 ++ .../git_helper_for_declarative_test.go | 36 +- integrations/git_test.go | 420 +++++++++--------- 3 files changed, 277 insertions(+), 221 deletions(-) diff --git a/integrations/api_helper_for_declarative_test.go b/integrations/api_helper_for_declarative_test.go index 943981ead2..85f0ab621f 100644 --- a/integrations/api_helper_for_declarative_test.go +++ b/integrations/api_helper_for_declarative_test.go @@ -5,11 +5,14 @@ package integrations import ( + "encoding/json" "fmt" "io/ioutil" "net/http" "testing" + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" ) @@ -150,3 +153,42 @@ func doAPICreateDeployKey(ctx APITestContext, keyname, keyFile string, readOnly ctx.Session.MakeRequest(t, req, http.StatusCreated) } } + +func doAPICreatePullRequest(ctx APITestContext, owner, repo, baseBranch, headBranch string) func(*testing.T) (api.PullRequest, error) { + return func(t *testing.T) (api.PullRequest, error) { + urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", + owner, repo, ctx.Token) + req := NewRequestWithJSON(t, http.MethodPost, urlStr, &api.CreatePullRequestOption{ + Head: headBranch, + Base: baseBranch, + Title: fmt.Sprintf("create a pr from %s to %s", headBranch, baseBranch), + }) + + expected := 201 + if ctx.ExpectedCode != 0 { + expected = ctx.ExpectedCode + } + resp := ctx.Session.MakeRequest(t, req, expected) + decoder := json.NewDecoder(resp.Body) + pr := api.PullRequest{} + err := decoder.Decode(&pr) + return pr, err + } +} + +func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) { + return func(t *testing.T) { + urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s", + owner, repo, index, ctx.Token) + req := NewRequestWithJSON(t, http.MethodPost, urlStr, &auth.MergePullRequestForm{ + MergeMessageField: "doAPIMergePullRequest Merge", + Do: string(models.MergeStyleMerge), + }) + + if ctx.ExpectedCode != 0 { + ctx.Session.MakeRequest(t, req, ctx.ExpectedCode) + return + } + ctx.Session.MakeRequest(t, req, 200) + } +} diff --git a/integrations/git_helper_for_declarative_test.go b/integrations/git_helper_for_declarative_test.go index b4fead6625..235f4b4a9b 100644 --- a/integrations/git_helper_for_declarative_test.go +++ b/integrations/git_helper_for_declarative_test.go @@ -112,16 +112,44 @@ func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) { } } -func doGitPushTestRepository(dstPath, remoteName, branch string) func(*testing.T) { +func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) { return func(t *testing.T) { - _, err := git.NewCommand("push", "-u", remoteName, branch).RunInDir(dstPath) + _, err := git.NewCommand(append([]string{"push", "-u"}, args...)...).RunInDir(dstPath) assert.NoError(t, err) } } -func doGitPushTestRepositoryFail(dstPath, remoteName, branch string) func(*testing.T) { +func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) { return func(t *testing.T) { - _, err := git.NewCommand("push", "-u", remoteName, branch).RunInDir(dstPath) + _, err := git.NewCommand(append([]string{"push"}, args...)...).RunInDir(dstPath) assert.Error(t, err) } } + +func doGitCreateBranch(dstPath, branch string) func(*testing.T) { + return func(t *testing.T) { + _, err := git.NewCommand("checkout", "-b", branch).RunInDir(dstPath) + assert.NoError(t, err) + } +} + +func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) { + return func(t *testing.T) { + _, err := git.NewCommand(append([]string{"checkout"}, args...)...).RunInDir(dstPath) + assert.NoError(t, err) + } +} + +func doGitMerge(dstPath string, args ...string) func(*testing.T) { + return func(t *testing.T) { + _, err := git.NewCommand(append([]string{"merge"}, args...)...).RunInDir(dstPath) + assert.NoError(t, err) + } +} + +func doGitPull(dstPath string, args ...string) func(*testing.T) { + return func(t *testing.T) { + _, err := git.NewCommand(append([]string{"pull"}, args...)...).RunInDir(dstPath) + assert.NoError(t, err) + } +} diff --git a/integrations/git_test.go b/integrations/git_test.go index 0554f9a5ae..ce5aee493d 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -13,11 +13,13 @@ import ( "os" "path" "path/filepath" + "strconv" "testing" "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" ) @@ -43,119 +45,23 @@ func testGit(t *testing.T, u *url.URL) { httpContext.Reponame = "repo-tmp-17" dstPath, err := ioutil.TempDir("", httpContext.Reponame) - var little, big, littleLFS, bigLFS string - assert.NoError(t, err) defer os.RemoveAll(dstPath) - t.Run("Standard", func(t *testing.T) { - PrintCurrentTest(t) - ensureAnonymousClone(t, u) - t.Run("CreateRepo", doAPICreateRepository(httpContext, false)) + t.Run("CreateRepo", doAPICreateRepository(httpContext, false)) + ensureAnonymousClone(t, u) - u.Path = httpContext.GitPath() - u.User = url.UserPassword(username, userPassword) + u.Path = httpContext.GitPath() + u.User = url.UserPassword(username, userPassword) - t.Run("Clone", doGitClone(dstPath, u)) + t.Run("Clone", doGitClone(dstPath, u)) - t.Run("PushCommit", func(t *testing.T) { - PrintCurrentTest(t) - t.Run("Little", func(t *testing.T) { - PrintCurrentTest(t) - little = commitAndPush(t, littleSize, dstPath) - }) - t.Run("Big", func(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - return - } - PrintCurrentTest(t) - big = commitAndPush(t, bigSize, dstPath) - }) - }) - }) - t.Run("LFS", func(t *testing.T) { - PrintCurrentTest(t) - t.Run("PushCommit", func(t *testing.T) { - PrintCurrentTest(t) - //Setup git LFS - _, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath) - assert.NoError(t, err) - _, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath) - assert.NoError(t, err) - err = git.AddChanges(dstPath, false, ".gitattributes") - assert.NoError(t, err) - - t.Run("Little", func(t *testing.T) { - PrintCurrentTest(t) - littleLFS = commitAndPush(t, littleSize, dstPath) - lockFileTest(t, littleLFS, dstPath) - }) - t.Run("Big", func(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - return - } - PrintCurrentTest(t) - bigLFS = commitAndPush(t, bigSize, dstPath) - lockFileTest(t, bigLFS, dstPath) - }) - }) - t.Run("Locks", func(t *testing.T) { - PrintCurrentTest(t) - lockTest(t, u.String(), dstPath) - }) - }) - t.Run("Raw", func(t *testing.T) { - PrintCurrentTest(t) - session := loginUser(t, "user2") - - // Request raw paths - req := NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", little)) - resp := session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Body.Len()) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", littleLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, littleSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) - - if !testing.Short() { - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", big)) - nilResp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, bigSize, nilResp.Length) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", bigLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, bigSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) - } - - }) - t.Run("Media", func(t *testing.T) { - PrintCurrentTest(t) - session := loginUser(t, "user2") - - // Request media paths - req := NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", little)) - resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Length) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", littleLFS)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Length) - - if !testing.Short() { - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", big)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Length) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", bigLFS)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Length) - } - }) + little, big := standardCommitAndPushTest(t, dstPath) + littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath) + rawTest(t, &httpContext, little, big, littleLFS, bigLFS) + mediaTest(t, &httpContext, little, big, littleLFS, bigLFS) + t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath)) }) t.Run("SSH", func(t *testing.T) { PrintCurrentTest(t) @@ -165,123 +71,26 @@ func testGit(t *testing.T, u *url.URL) { //Setup key the user ssh key withKeyFile(t, keyname, func(keyFile string) { t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile)) - PrintCurrentTest(t) //Setup remote link + //TODO: get url from api sshURL := createSSHUrl(sshContext.GitPath(), u) //Setup clone folder dstPath, err := ioutil.TempDir("", sshContext.Reponame) assert.NoError(t, err) defer os.RemoveAll(dstPath) - var little, big, littleLFS, bigLFS string - t.Run("Standard", func(t *testing.T) { - PrintCurrentTest(t) - t.Run("CreateRepo", doAPICreateRepository(sshContext, false)) + t.Run("CreateRepo", doAPICreateRepository(sshContext, false)) - //TODO get url from api - t.Run("Clone", doGitClone(dstPath, sshURL)) + t.Run("Clone", doGitClone(dstPath, sshURL)) - //time.Sleep(5 * time.Minute) - t.Run("PushCommit", func(t *testing.T) { - PrintCurrentTest(t) - t.Run("Little", func(t *testing.T) { - PrintCurrentTest(t) - little = commitAndPush(t, littleSize, dstPath) - }) - t.Run("Big", func(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - return - } - PrintCurrentTest(t) - big = commitAndPush(t, bigSize, dstPath) - }) - }) - }) - t.Run("LFS", func(t *testing.T) { - PrintCurrentTest(t) - t.Run("PushCommit", func(t *testing.T) { - PrintCurrentTest(t) - //Setup git LFS - _, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath) - assert.NoError(t, err) - _, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath) - assert.NoError(t, err) - err = git.AddChanges(dstPath, false, ".gitattributes") - assert.NoError(t, err) - - t.Run("Little", func(t *testing.T) { - PrintCurrentTest(t) - littleLFS = commitAndPush(t, littleSize, dstPath) - lockFileTest(t, littleLFS, dstPath) - - }) - t.Run("Big", func(t *testing.T) { - if testing.Short() { - return - } - PrintCurrentTest(t) - bigLFS = commitAndPush(t, bigSize, dstPath) - lockFileTest(t, bigLFS, dstPath) - - }) - }) - t.Run("Locks", func(t *testing.T) { - PrintCurrentTest(t) - lockTest(t, u.String(), dstPath) - }) - }) - t.Run("Raw", func(t *testing.T) { - PrintCurrentTest(t) - session := loginUser(t, "user2") - - // Request raw paths - req := NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", little)) - resp := session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Body.Len()) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", littleLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, littleSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) - - if !testing.Short() { - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", big)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Body.Len()) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", bigLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, bigSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) - } - }) - t.Run("Media", func(t *testing.T) { - PrintCurrentTest(t) - session := loginUser(t, "user2") - - // Request media paths - req := NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", little)) - resp := session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Body.Len()) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", littleLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Body.Len()) - - if !testing.Short() { - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", big)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Body.Len()) - - req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", bigLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Body.Len()) - } - }) + little, big := standardCommitAndPushTest(t, dstPath) + littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath) + rawTest(t, &sshContext, little, big, littleLFS, bigLFS) + mediaTest(t, &sshContext, little, big, littleLFS, bigLFS) + t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath)) }) }) @@ -295,7 +104,116 @@ func ensureAnonymousClone(t *testing.T, u *url.URL) { } -func lockTest(t *testing.T, remote, repoPath string) { +func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string) { + t.Run("Standard", func(t *testing.T) { + PrintCurrentTest(t) + little, big = commitAndPushTest(t, dstPath, "data-file-") + }) + return +} + +func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) { + t.Run("LFS", func(t *testing.T) { + PrintCurrentTest(t) + prefix := "lfs-data-file-" + _, err := git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath) + assert.NoError(t, err) + _, err = git.NewCommand("lfs").AddArguments("track", prefix+"*").RunInDir(dstPath) + assert.NoError(t, err) + err = git.AddChanges(dstPath, false, ".gitattributes") + assert.NoError(t, err) + + littleLFS, bigLFS = commitAndPushTest(t, dstPath, prefix) + + t.Run("Locks", func(t *testing.T) { + PrintCurrentTest(t) + lockTest(t, dstPath) + }) + }) + return +} + +func commitAndPushTest(t *testing.T, dstPath, prefix string) (little, big string) { + t.Run("PushCommit", func(t *testing.T) { + PrintCurrentTest(t) + t.Run("Little", func(t *testing.T) { + PrintCurrentTest(t) + little = doCommitAndPush(t, littleSize, dstPath, prefix) + }) + t.Run("Big", func(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + return + } + PrintCurrentTest(t) + big = doCommitAndPush(t, bigSize, dstPath, prefix) + }) + }) + return +} + +func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS string) { + t.Run("Raw", func(t *testing.T) { + PrintCurrentTest(t) + username := ctx.Username + reponame := ctx.Reponame + + session := loginUser(t, username) + + // Request raw paths + req := NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", little)) + resp := session.MakeRequest(t, req, http.StatusOK) + assert.Equal(t, littleSize, resp.Body.Len()) + + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotEqual(t, littleSize, resp.Body.Len()) + assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + + if !testing.Short() { + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", big)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Body.Len()) + + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", bigLFS)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotEqual(t, bigSize, resp.Body.Len()) + assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + } + }) +} + +func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS string) { + t.Run("Media", func(t *testing.T) { + PrintCurrentTest(t) + + username := ctx.Username + reponame := ctx.Reponame + + session := loginUser(t, username) + + // Request media paths + req := NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", little)) + resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, littleSize, resp.Length) + + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, littleSize, resp.Length) + + if !testing.Short() { + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Length) + + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", bigLFS)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Length) + } + }) +} + +func lockTest(t *testing.T, repoPath string) { lockFileTest(t, "README.md", repoPath) } @@ -310,22 +228,22 @@ func lockFileTest(t *testing.T, filename, repoPath string) { assert.NoError(t, err) } -func commitAndPush(t *testing.T, size int, repoPath string) string { - name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two") +func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string { + name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix) assert.NoError(t, err) - _, err = git.NewCommand("push").RunInDir(repoPath) //Push + _, err = git.NewCommand("push", "origin", "master").RunInDir(repoPath) //Push assert.NoError(t, err) return name } -func generateCommitWithNewData(size int, repoPath, email, fullName string) (string, error) { +func generateCommitWithNewData(size int, repoPath, email, fullName, prefix string) (string, error) { //Generate random file data := make([]byte, size) _, err := rand.Read(data) if err != nil { return "", err } - tmpFile, err := ioutil.TempFile(repoPath, "data-file-") + tmpFile, err := ioutil.TempFile(repoPath, prefix) if err != nil { return "", err } @@ -355,3 +273,71 @@ func generateCommitWithNewData(size int, repoPath, email, fullName string) (stri }) return filepath.Base(tmpFile.Name()), err } + +func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { + return func(t *testing.T) { + PrintCurrentTest(t) + t.Run("CreateBranchProtected", doGitCreateBranch(dstPath, "protected")) + t.Run("PushProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected")) + + ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame) + t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "")) + t.Run("GenerateCommit", func(t *testing.T) { + _, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-") + assert.NoError(t, err) + }) + t.Run("FailToPushToProtectedBranch", doGitPushTestRepositoryFail(dstPath, "origin", "protected")) + t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected")) + var pr api.PullRequest + var err error + t.Run("CreatePullRequest", func(t *testing.T) { + pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, "protected", "unprotected")(t) + assert.NoError(t, err) + }) + t.Run("MergePR", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + t.Run("PullProtected", doGitPull(dstPath, "origin", "protected")) + t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username)) + + t.Run("CheckoutMaster", doGitCheckoutBranch(dstPath, "master")) + t.Run("CreateBranchForced", doGitCreateBranch(dstPath, "toforce")) + t.Run("GenerateCommit", func(t *testing.T) { + _, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-") + assert.NoError(t, err) + }) + t.Run("FailToForcePushToProtectedBranch", doGitPushTestRepositoryFail(dstPath, "-f", "origin", "toforce:protected")) + t.Run("MergeProtectedToToforce", doGitMerge(dstPath, "protected")) + t.Run("PushToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "toforce:protected")) + t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master")) + } +} + +func doProtectBranch(ctx APITestContext, branch string, userToWhitelist string) func(t *testing.T) { + // We are going to just use the owner to set the protection. + return func(t *testing.T) { + csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings/branches", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame))) + + if userToWhitelist == "" { + // Change branch to protected + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{ + "_csrf": csrf, + "protected": "on", + }) + ctx.Session.MakeRequest(t, req, http.StatusFound) + } else { + user, err := models.GetUserByName(userToWhitelist) + assert.NoError(t, err) + // Change branch to protected + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{ + "_csrf": csrf, + "protected": "on", + "enable_whitelist": "on", + "whitelist_users": strconv.FormatInt(user.ID, 10), + }) + ctx.Session.MakeRequest(t, req, http.StatusFound) + } + // Check if master branch has been locked successfully + flashCookie := ctx.Session.GetCookie("macaron_flash") + assert.NotNil(t, flashCookie) + assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527"+url.QueryEscape(branch)+"%2527%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value) + } +} From 8a343dda39b187627db6ffb4c24a6e0ae615867b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 1 Jun 2019 03:34:46 +0800 Subject: [PATCH 077/220] update go git from v4.10.0 to v4.11.0 (#7096) --- go.mod | 2 +- go.sum | 4 +- vendor/gopkg.in/src-d/go-git.v4/.travis.yml | 2 +- vendor/gopkg.in/src-d/go-git.v4/options.go | 4 +- .../go-git.v4/plumbing/cache/object_lru.go | 5 +++ .../src-d/go-git.v4/plumbing/object/commit.go | 38 +++++++++++-------- .../plumbing/object/commit_walker_bfs.go | 2 +- .../src-d/go-git.v4/plumbing/object/patch.go | 11 +++++- .../src-d/go-git.v4/plumbing/object/tree.go | 2 +- vendor/gopkg.in/src-d/go-git.v4/remote.go | 9 ++++- vendor/gopkg.in/src-d/go-git.v4/repository.go | 17 +++++++++ .../src-d/go-git.v4/utils/diff/diff.go | 18 ++++++++- vendor/gopkg.in/src-d/go-git.v4/worktree.go | 11 ------ .../src-d/go-git.v4/worktree_status.go | 6 ++- vendor/modules.txt | 2 +- 15 files changed, 93 insertions(+), 40 deletions(-) diff --git a/go.mod b/go.mod index 299a4b29f9..c6ebe16039 100644 --- a/go.mod +++ b/go.mod @@ -130,7 +130,7 @@ require ( gopkg.in/macaron.v1 v1.3.2 gopkg.in/redis.v2 v2.3.2 // indirect gopkg.in/src-d/go-billy.v4 v4.3.0 - gopkg.in/src-d/go-git.v4 v4.10.0 + gopkg.in/src-d/go-git.v4 v4.11.0 gopkg.in/testfixtures.v2 v2.5.0 mvdan.cc/xurls/v2 v2.0.0 strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a diff --git a/go.sum b/go.sum index 94d332cbc9..81b3aae5d4 100644 --- a/go.sum +++ b/go.sum @@ -380,8 +380,8 @@ gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs= gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.10.0 h1:NWjTJTQnk8UpIGlssuefyDZ6JruEjo5s88vm88uASbw= -gopkg.in/src-d/go-git.v4 v4.10.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= +gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU= +gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M= gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU= gopkg.in/testfixtures.v2 v2.5.0 h1:N08B7l2GzFQenyYbzqthDnKAA+cmb17iAZhhFxr7JHw= diff --git a/vendor/gopkg.in/src-d/go-git.v4/.travis.yml b/vendor/gopkg.in/src-d/go-git.v4/.travis.yml index c68b5f473e..3a65f3e082 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/.travis.yml +++ b/vendor/gopkg.in/src-d/go-git.v4/.travis.yml @@ -1,8 +1,8 @@ language: go go: - - "1.10" - "1.11" + - "1.12" go_import_path: gopkg.in/src-d/go-git.v4 diff --git a/vendor/gopkg.in/src-d/go-git.v4/options.go b/vendor/gopkg.in/src-d/go-git.v4/options.go index ed7689ab3f..7c9e687288 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/options.go +++ b/vendor/gopkg.in/src-d/go-git.v4/options.go @@ -229,7 +229,7 @@ var ( ErrCreateRequiresBranch = errors.New("Branch is mandatory when Create is used") ) -// CheckoutOptions describes how a checkout 31operation should be performed. +// CheckoutOptions describes how a checkout operation should be performed. type CheckoutOptions struct { // Hash is the hash of the commit to be checked out. If used, HEAD will be // in detached mode. If Create is not used, Branch and Hash are mutually @@ -288,7 +288,7 @@ const ( // ResetOptions describes how a reset operation should be performed. type ResetOptions struct { - // Commit, if commit is pressent set the current branch head (HEAD) to it. + // Commit, if commit is present set the current branch head (HEAD) to it. Commit plumbing.Hash // Mode, form resets the current branch head to Commit and possibly updates // the index (resetting it to the tree of Commit) and the working tree diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go index 53d8b02d96..cd3712b7d7 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go @@ -61,6 +61,11 @@ func (c *ObjectLRU) Put(obj plumbing.EncodedObject) { c.actualSize += objSize for c.actualSize > c.MaxSize { last := c.ll.Back() + if last == nil { + c.actualSize = 0 + break + } + lastObj := last.Value.(plumbing.EncodedObject) lastSize := FileSize(lastObj.Size()) diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go index e2543426ac..b569d3ce2d 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go @@ -76,8 +76,8 @@ func (c *Commit) Tree() (*Tree, error) { return GetTree(c.s, c.TreeHash) } -// Patch returns the Patch between the actual commit and the provided one. -// Error will be return if context expires. Provided context must be non-nil +// PatchContext returns the Patch between the actual commit and the provided one. +// Error will be return if context expires. Provided context must be non-nil. func (c *Commit) PatchContext(ctx context.Context, to *Commit) (*Patch, error) { fromTree, err := c.Tree() if err != nil { @@ -291,25 +291,33 @@ func (b *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) { return err } -// Stats shows the status of commit. +// Stats returns the stats of a commit. func (c *Commit) Stats() (FileStats, error) { - // Get the previous commit. - ci := c.Parents() - parentCommit, err := ci.Next() + return c.StatsContext(context.Background()) +} + +// StatsContext returns the stats of a commit. Error will be return if context +// expires. Provided context must be non-nil. +func (c *Commit) StatsContext(ctx context.Context) (FileStats, error) { + fromTree, err := c.Tree() if err != nil { - if err == io.EOF { - emptyNoder := treeNoder{} - parentCommit = &Commit{ - Hash: emptyNoder.hash, - // TreeHash: emptyNoder.parent.Hash, - s: c.s, - } - } else { + return nil, err + } + + toTree := &Tree{} + if c.NumParents() != 0 { + firstParent, err := c.Parents().Next() + if err != nil { + return nil, err + } + + toTree, err = firstParent.Tree() + if err != nil { return nil, err } } - patch, err := parentCommit.Patch(c) + patch, err := toTree.PatchContext(ctx, fromTree) if err != nil { return nil, err } diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs.go index aef1cf24c6..dabfe75c27 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs.go @@ -67,7 +67,7 @@ func (w *bfsCommitIterator) Next() (*Commit, error) { for _, h := range c.ParentHashes { err := w.appendHash(c.s, h) if err != nil { - return nil, nil + return nil, err } } diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/patch.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/patch.go index adeaccb0a8..068589eff8 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/patch.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/patch.go @@ -320,11 +320,18 @@ func getFileStatsFromFilePatches(filePatches []fdiff.FilePatch) FileStats { } for _, chunk := range fp.Chunks() { + s := chunk.Content() switch chunk.Type() { case fdiff.Add: - cs.Addition += strings.Count(chunk.Content(), "\n") + cs.Addition += strings.Count(s, "\n") + if s[len(s)-1] != '\n' { + cs.Addition++ + } case fdiff.Delete: - cs.Deletion += strings.Count(chunk.Content(), "\n") + cs.Deletion += strings.Count(s, "\n") + if s[len(s)-1] != '\n' { + cs.Deletion++ + } } } diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go index 78d61a1fba..1f9ea2651c 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go @@ -135,7 +135,7 @@ func (t *Tree) FindEntry(path string) (*TreeEntry, error) { pathCurrent := "" // search for the longest path in the tree path cache - for i := len(pathParts); i > 1; i-- { + for i := len(pathParts) - 1; i > 1; i-- { path := filepath.Join(pathParts[:i]...) tree, ok := t.t[path] diff --git a/vendor/gopkg.in/src-d/go-git.v4/remote.go b/vendor/gopkg.in/src-d/go-git.v4/remote.go index de537ce8e8..80604092ab 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/remote.go +++ b/vendor/gopkg.in/src-d/go-git.v4/remote.go @@ -1020,7 +1020,12 @@ func pushHashes( if err != nil { return nil, err } - done := make(chan error) + + // Set buffer size to 1 so the error message can be written when + // ReceivePack fails. Otherwise the goroutine will be blocked writing + // to the channel. + done := make(chan error, 1) + go func() { e := packfile.NewEncoder(wr, s, useRefDeltas) if _, err := e.Encode(hs, config.Pack.Window); err != nil { @@ -1033,6 +1038,8 @@ func pushHashes( rs, err := sess.ReceivePack(ctx, req) if err != nil { + // close the pipe to unlock encode write + _ = rd.Close() return nil, err } diff --git a/vendor/gopkg.in/src-d/go-git.v4/repository.go b/vendor/gopkg.in/src-d/go-git.v4/repository.go index de92d64709..e5b12b0c52 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/repository.go +++ b/vendor/gopkg.in/src-d/go-git.v4/repository.go @@ -49,6 +49,7 @@ var ( ErrRepositoryAlreadyExists = errors.New("repository already exists") ErrRemoteNotFound = errors.New("remote not found") ErrRemoteExists = errors.New("remote already exists") + ErrAnonymousRemoteName = errors.New("anonymous remote name must be 'anonymous'") ErrWorktreeNotProvided = errors.New("worktree should be provided") ErrIsBareRepository = errors.New("worktree not available in a bare repository") ErrUnableToResolveCommit = errors.New("unable to resolve commit") @@ -492,6 +493,22 @@ func (r *Repository) CreateRemote(c *config.RemoteConfig) (*Remote, error) { return remote, r.Storer.SetConfig(cfg) } +// CreateRemoteAnonymous creates a new anonymous remote. c.Name must be "anonymous". +// It's used like 'git fetch git@github.com:src-d/go-git.git master:master'. +func (r *Repository) CreateRemoteAnonymous(c *config.RemoteConfig) (*Remote, error) { + if err := c.Validate(); err != nil { + return nil, err + } + + if c.Name != "anonymous" { + return nil, ErrAnonymousRemoteName + } + + remote := newRemote(r.Storer, c) + + return remote, nil +} + // DeleteRemote delete a remote from the repository and delete the config func (r *Repository) DeleteRemote(name string) error { cfg, err := r.Storer.Config() diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/diff/diff.go b/vendor/gopkg.in/src-d/go-git.v4/utils/diff/diff.go index f49ae55bae..6142ed0515 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/diff/diff.go +++ b/vendor/gopkg.in/src-d/go-git.v4/utils/diff/diff.go @@ -8,14 +8,30 @@ package diff import ( "bytes" + "time" "github.com/sergi/go-diff/diffmatchpatch" ) // Do computes the (line oriented) modifications needed to turn the src -// string into the dst string. +// string into the dst string. The underlying algorithm is Meyers, +// its complexity is O(N*d) where N is min(lines(src), lines(dst)) and d +// is the size of the diff. func Do(src, dst string) (diffs []diffmatchpatch.Diff) { + // the default timeout is time.Second which may be too small under heavy load + return DoWithTimeout(src, dst, time.Hour) +} + +// DoWithTimeout computes the (line oriented) modifications needed to turn the src +// string into the dst string. The `timeout` argument specifies the maximum +// amount of time it is allowed to spend in this function. If the timeout +// is exceeded, the parts of the strings which were not considered are turned into +// a bulk delete+insert and the half-baked suboptimal result is returned at once. +// The underlying algorithm is Meyers, its complexity is O(N*d) where N is +// min(lines(src), lines(dst)) and d is the size of the diff. +func DoWithTimeout (src, dst string, timeout time.Duration) (diffs []diffmatchpatch.Diff) { dmp := diffmatchpatch.New() + dmp.DiffTimeout = timeout wSrc, wDst, warray := dmp.DiffLinesToRunes(src, dst) diffs = dmp.DiffMainRunes(wSrc, wDst, false) diffs = dmp.DiffCharsToLines(diffs, warray) diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree.go b/vendor/gopkg.in/src-d/go-git.v4/worktree.go index a14fd8d6c3..dae40a38a7 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree.go +++ b/vendor/gopkg.in/src-d/go-git.v4/worktree.go @@ -152,17 +152,6 @@ func (w *Worktree) Checkout(opts *CheckoutOptions) error { } } - if !opts.Force { - unstaged, err := w.containsUnstagedChanges() - if err != nil { - return err - } - - if unstaged { - return ErrUnstagedChanges - } - } - c, err := w.getCommitFromCheckoutOptions(opts) if err != nil { return err diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree_status.go b/vendor/gopkg.in/src-d/go-git.v4/worktree_status.go index 0e113d0937..16ce937077 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree_status.go +++ b/vendor/gopkg.in/src-d/go-git.v4/worktree_status.go @@ -142,12 +142,16 @@ func (w *Worktree) diffStagingWithWorktree(reverse bool) (merkletrie.Changes, er func (w *Worktree) excludeIgnoredChanges(changes merkletrie.Changes) merkletrie.Changes { patterns, err := gitignore.ReadPatterns(w.Filesystem, nil) - if err != nil || len(patterns) == 0 { + if err != nil { return changes } patterns = append(patterns, w.Excludes...) + if len(patterns) == 0 { + return changes + } + m := gitignore.NewMatcher(patterns) var res merkletrie.Changes diff --git a/vendor/modules.txt b/vendor/modules.txt index 0085f7bbda..9f9ae9b4fb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -422,7 +422,7 @@ gopkg.in/src-d/go-billy.v4 gopkg.in/src-d/go-billy.v4/util gopkg.in/src-d/go-billy.v4/helper/chroot gopkg.in/src-d/go-billy.v4/helper/polyfill -# gopkg.in/src-d/go-git.v4 v4.10.0 +# gopkg.in/src-d/go-git.v4 v4.11.0 gopkg.in/src-d/go-git.v4 gopkg.in/src-d/go-git.v4/config gopkg.in/src-d/go-git.v4/plumbing From 356854fc5f8d7d1a7e4d68c9e00929e9ce8aa867 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 1 Jun 2019 16:00:21 +0100 Subject: [PATCH 078/220] Move serv hook functionality & drop GitLogger (#6993) * Move hook functionality internally * Internalise serv logic * Remove old internal paths * finally remove the gitlogger * Disallow push on archived repositories * fix lint error * Update modules/private/key.go * Update routers/private/hook.go * Update routers/private/hook.go * Update routers/private/hook.go * Updated routers/private/serv.go * Fix LFS Locks over SSH * rev-list needs to be run by the hook process * fixup * Improve git test * Ensure that the lfs files are created with a different prefix * Reduce the replication in git_test.go * slight refactor * Remove unnecessary "/" * Restore ensureAnonymousClone * Restore ensureAnonymousClone * Run rev-list on server side * Try passing in the alternative directories instead * Mark test as skipped * Improve git test * Ensure that the lfs files are created with a different prefix * Reduce the replication in git_test.go * Remove unnecessary "/" --- cmd/hook.go | 125 +++----- cmd/serv.go | 177 ++++------- .../advanced/logging-documentation.en-us.md | 16 - integrations/internal_test.go | 44 --- models/helper_environment.go | 2 +- modules/log/log.go | 19 +- modules/pprof/pprof.go | 16 +- modules/private/branch.go | 67 ---- modules/private/hook.go | 84 +++++ modules/private/internal.go | 49 --- modules/private/key.go | 118 +------- modules/private/push_update.go | 40 --- modules/private/repository.go | 68 ----- modules/private/serv.go | 106 +++++++ modules/private/wiki.go | 33 -- routers/init.go | 2 - routers/private/branch.go | 52 ---- routers/private/hook.go | 209 +++++++++++++ routers/private/internal.go | 19 +- routers/private/key.go | 84 +---- routers/private/push_update.go | 47 --- routers/private/repository.go | 83 ----- routers/private/serv.go | 286 ++++++++++++++++++ routers/private/wiki.go | 34 --- routers/repo/http.go | 8 +- 25 files changed, 806 insertions(+), 982 deletions(-) delete mode 100644 integrations/internal_test.go delete mode 100644 modules/private/branch.go create mode 100644 modules/private/hook.go delete mode 100644 modules/private/push_update.go delete mode 100644 modules/private/repository.go create mode 100644 modules/private/serv.go delete mode 100644 modules/private/wiki.go delete mode 100644 routers/private/branch.go create mode 100644 routers/private/hook.go delete mode 100644 routers/private/push_update.go delete mode 100644 routers/private/repository.go create mode 100644 routers/private/serv.go delete mode 100644 routers/private/wiki.go diff --git a/cmd/hook.go b/cmd/hook.go index f8bd34c4e9..b3e900afee 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -8,15 +8,14 @@ import ( "bufio" "bytes" "fmt" + "net/http" "os" "strconv" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" - "code.gitea.io/gitea/modules/util" "github.com/urfave/cli" ) @@ -62,12 +61,10 @@ func runHookPreReceive(c *cli.Context) error { setup("hooks/pre-receive.log") // the environment setted on serv command - repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64) isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true") username := os.Getenv(models.EnvRepoUsername) reponame := os.Getenv(models.EnvRepoName) - userIDStr := os.Getenv(models.EnvPusherID) - repoPath := models.RepoPath(username, reponame) + userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64) buf := bytes.NewBuffer(nil) scanner := bufio.NewScanner(os.Stdin) @@ -91,35 +88,19 @@ func runHookPreReceive(c *cli.Context) error { // If the ref is a branch, check if it's protected if strings.HasPrefix(refFullName, git.BranchPrefix) { - branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) - protectBranch, err := private.GetProtectedBranchBy(repoID, branchName) - if err != nil { - fail("Internal error", fmt.Sprintf("retrieve protected branches information failed: %v", err)) - } - - if protectBranch != nil && protectBranch.IsProtected() { - // check and deletion - if newCommitID == git.EmptySHA { - fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "") - } - - // detect force push - if git.EmptySHA != oldCommitID { - output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath) - if err != nil { - fail("Internal error", "Fail to detect force push: %v", err) - } else if len(output) > 0 { - fail(fmt.Sprintf("branch %s is protected from force push", branchName), "") - } - } - - userID, _ := strconv.ParseInt(userIDStr, 10, 64) - canPush, err := private.CanUserPush(protectBranch.ID, userID) - if err != nil { - fail("Internal error", "Fail to detect user can push: %v", err) - } else if !canPush { - fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "") - } + statusCode, msg := private.HookPreReceive(username, reponame, private.HookOptions{ + OldCommitID: oldCommitID, + NewCommitID: newCommitID, + RefFullName: refFullName, + UserID: userID, + GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories), + GitObjectDirectory: os.Getenv(private.GitObjectDirectory), + }) + switch statusCode { + case http.StatusInternalServerError: + fail("Internal Server Error", msg) + case http.StatusForbidden: + fail(msg, "") } } } @@ -145,7 +126,6 @@ func runHookPostReceive(c *cli.Context) error { setup("hooks/post-receive.log") // the environment setted on serv command - repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64) repoUser := os.Getenv(models.EnvRepoUsername) isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true") repoName := os.Getenv(models.EnvRepoName) @@ -172,64 +152,31 @@ func runHookPostReceive(c *cli.Context) error { newCommitID := string(fields[1]) refFullName := string(fields[2]) - // Only trigger activity updates for changes to branches or - // tags. Updates to other refs (eg, refs/notes, refs/changes, - // or other less-standard refs spaces are ignored since there - // may be a very large number of them). - if strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) { - if err := private.PushUpdate(models.PushUpdateOptions{ - RefFullName: refFullName, - OldCommitID: oldCommitID, - NewCommitID: newCommitID, - PusherID: pusherID, - PusherName: pusherName, - RepoUserName: repoUser, - RepoName: repoName, - }); err != nil { - log.GitLogger.Error("Update: %v", err) - } + res, err := private.HookPostReceive(repoUser, repoName, private.HookOptions{ + OldCommitID: oldCommitID, + NewCommitID: newCommitID, + RefFullName: refFullName, + UserID: pusherID, + UserName: pusherName, + }) + + if res == nil { + fail("Internal Server Error", err) } - if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) { - branch := strings.TrimPrefix(refFullName, git.BranchPrefix) - repo, pullRequestAllowed, err := private.GetRepository(repoID) - if err != nil { - log.GitLogger.Error("get repo: %v", err) - break - } - if !pullRequestAllowed { - break - } - - baseRepo := repo - if repo.IsFork { - baseRepo = repo.BaseRepo - } - - if !repo.IsFork && branch == baseRepo.DefaultBranch { - break - } - - pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch) - if err != nil { - log.GitLogger.Error("get active pr: %v", err) - break - } - - fmt.Fprintln(os.Stderr, "") - if pr == nil { - if repo.IsFork { - branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch) - } - fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch) - fmt.Fprintf(os.Stderr, " %s/compare/%s...%s\n", baseRepo.HTMLURL(), util.PathEscapeSegments(baseRepo.DefaultBranch), util.PathEscapeSegments(branch)) - } else { - fmt.Fprint(os.Stderr, "Visit the existing pull request:\n") - fmt.Fprintf(os.Stderr, " %s/pulls/%d\n", baseRepo.HTMLURL(), pr.Index) - } - fmt.Fprintln(os.Stderr, "") + if res["message"] == false { + continue } + fmt.Fprintln(os.Stderr, "") + if res["create"] == true { + fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res["branch"]) + fmt.Fprintf(os.Stderr, " %s\n", res["url"]) + } else { + fmt.Fprint(os.Stderr, "Visit the existing pull request:\n") + fmt.Fprintf(os.Stderr, " %s\n", res["url"]) + } + fmt.Fprintln(os.Stderr, "") } return nil diff --git a/cmd/serv.go b/cmd/serv.go index a30e02e7a2..aa068d4cf6 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -8,9 +8,11 @@ package cmd import ( "encoding/json" "fmt" + "net/http" + "net/url" "os" "os/exec" - "path/filepath" + "strconv" "strings" "time" @@ -68,7 +70,6 @@ func setup(logPath string) { log.DelLogger("console") setting.NewContext() checkLFSVersion() - log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath)) } func parseCmd(cmd string) (string, string) { @@ -95,15 +96,14 @@ func fail(userMessage, logMessage string, args ...interface{}) { if !setting.ProdMode { fmt.Fprintf(os.Stderr, logMessage+"\n", args...) } - log.GitLogger.Fatal(logMessage, args...) return } - log.GitLogger.Close() os.Exit(1) } func runServ(c *cli.Context) error { + // FIXME: This needs to internationalised setup("serv.log") if setting.SSH.Disabled { @@ -116,9 +116,23 @@ func runServ(c *cli.Context) error { return nil } + keys := strings.Split(c.Args()[0], "-") + if len(keys) != 2 || keys[0] != "key" { + fail("Key ID format error", "Invalid key argument: %s", c.Args()[0]) + } + keyID := com.StrTo(keys[1]).MustInt64() + cmd := os.Getenv("SSH_ORIGINAL_COMMAND") if len(cmd) == 0 { - println("Hi there, You've successfully authenticated, but Gitea does not provide shell access.") + key, user, err := private.ServNoCommand(keyID) + if err != nil { + fail("Internal error", "Failed to check provided key: %v", err) + } + if key.Type == models.KeyTypeDeploy { + println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.") + } else { + println("Hi there: " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.") + } println("If this is unexpected, please log in with password and setup Gitea under another user.") return nil } @@ -152,41 +166,19 @@ func runServ(c *cli.Context) error { fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err) } - stopCPUProfiler := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username) + stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username) + if err != nil { + fail("Internal Server Error", "Unable to start CPU profile: %v", err) + } defer func() { stopCPUProfiler() - pprof.DumpMemProfileForUsername(setting.PprofDataPath, username) + err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username) + if err != nil { + fail("Internal Server Error", "Unable to dump Mem Profile: %v", err) + } }() } - var ( - isWiki bool - unitType = models.UnitTypeCode - unitName = "code" - ) - if strings.HasSuffix(reponame, ".wiki") { - isWiki = true - unitType = models.UnitTypeWiki - unitName = "wiki" - reponame = reponame[:len(reponame)-5] - } - - os.Setenv(models.EnvRepoUsername, username) - if isWiki { - os.Setenv(models.EnvRepoIsWiki, "true") - } else { - os.Setenv(models.EnvRepoIsWiki, "false") - } - os.Setenv(models.EnvRepoName, reponame) - - repo, err := private.GetRepositoryByOwnerAndName(username, reponame) - if err != nil { - if strings.Contains(err.Error(), "Failed to get repository: repository does not exist") { - fail(accessDenied, "Repository does not exist: %s/%s", username, reponame) - } - fail("Internal error", "Failed to get repository: %v", err) - } - requestedMode, has := allowedCommands[verb] if !has { fail("Unknown git command", "Unknown git command %s", verb) @@ -202,97 +194,36 @@ func runServ(c *cli.Context) error { } } - // Prohibit push to mirror repositories. - if requestedMode > models.AccessModeRead && repo.IsMirror { - fail("mirror repository is read-only", "") - } - - // Allow anonymous clone for public repositories. - var ( - keyID int64 - user *models.User - ) - if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView { - keys := strings.Split(c.Args()[0], "-") - if len(keys) != 2 { - fail("Key ID format error", "Invalid key argument: %s", c.Args()[0]) - } - - key, err := private.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64()) - if err != nil { - fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err) - } - keyID = key.ID - - // Check deploy key or user key. - if key.Type == models.KeyTypeDeploy { - // Now we have to get the deploy key for this repo - deployKey, err := private.GetDeployKey(key.ID, repo.ID) - if err != nil { - fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID) - } - - if deployKey == nil { - fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID) - } - - if deployKey.Mode < requestedMode { - fail("Key permission denied", "Cannot push with read-only deployment key: %d to repo_id: %d", key.ID, repo.ID) - } - - // Update deploy key activity. - if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil { - fail("Internal error", "UpdateDeployKey: %v", err) - } - - // FIXME: Deploy keys aren't really the owner of the repo pushing changes - // however we don't have good way of representing deploy keys in hook.go - // so for now use the owner - os.Setenv(models.EnvPusherName, username) - os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID)) - } else { - user, err = private.GetUserByKeyID(key.ID) - if err != nil { - fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err) - } - - if !user.IsActive || user.ProhibitLogin { - fail("Your account is not active or has been disabled by Administrator", - "User %s is disabled and have no access to repository %s", - user.Name, repoPath) - } - - mode, err := private.CheckUnitUser(user.ID, repo.ID, user.IsAdmin, unitType) - if err != nil { - fail("Internal error", "Failed to check access: %v", err) - } else if *mode < requestedMode { - clientMessage := accessDenied - if *mode >= models.AccessModeRead { - clientMessage = "You do not have sufficient authorization for this action" - } - fail(clientMessage, - "User %s does not have level %v access to repository %s's "+unitName, - user.Name, requestedMode, repoPath) - } - - os.Setenv(models.EnvPusherName, user.Name) - os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID)) - } + results, err := private.ServCommand(keyID, username, reponame, requestedMode, verb, lfsVerb) + if err != nil { + if private.IsErrServCommand(err) { + errServCommand := err.(private.ErrServCommand) + if errServCommand.StatusCode != http.StatusInternalServerError { + fail("Unauthorized", errServCommand.Error()) + } else { + fail("Internal Server Error", errServCommand.Error()) + } + } + fail("Internal Server Error", err.Error()) } + os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki)) + os.Setenv(models.EnvRepoName, results.RepoName) + os.Setenv(models.EnvRepoUsername, results.OwnerName) + os.Setenv(models.EnvPusherName, username) + os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) + os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10)) //LFS token authentication if verb == lfsAuthenticateVerb { - url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, username, repo.Name) + url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName)) now := time.Now() claims := jwt.MapClaims{ - "repo": repo.ID, + "repo": results.RepoID, "op": lfsVerb, "exp": now.Add(setting.LFS.HTTPAuthExpiry).Unix(), "nbf": now.Unix(), - } - if user != nil { - claims["user"] = user.ID + "user": results.UserID, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) @@ -313,7 +244,6 @@ func runServ(c *cli.Context) error { if err != nil { fail("Internal error", "Failed to encode LFS json response: %v", err) } - return nil } @@ -329,13 +259,8 @@ func runServ(c *cli.Context) error { } else { gitcmd = exec.Command(verb, repoPath) } - if isWiki { - if err = private.InitWiki(repo.ID); err != nil { - fail("Internal error", "Failed to init wiki repo: %v", err) - } - } - os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID)) + os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", results.RepoID)) gitcmd.Dir = setting.RepoRootPath gitcmd.Stdout = os.Stdout @@ -346,9 +271,9 @@ func runServ(c *cli.Context) error { } // Update user key activity. - if keyID > 0 { - if err = private.UpdatePublicKeyUpdated(keyID); err != nil { - fail("Internal error", "UpdatePublicKey: %v", err) + if results.KeyID > 0 { + if err = private.UpdatePublicKeyInRepo(results.KeyID, results.RepoID); err != nil { + fail("Internal error", "UpdatePublicKeyInRepo: %v", err) } } diff --git a/docs/content/doc/advanced/logging-documentation.en-us.md b/docs/content/doc/advanced/logging-documentation.en-us.md index df35786943..790e750084 100644 --- a/docs/content/doc/advanced/logging-documentation.en-us.md +++ b/docs/content/doc/advanced/logging-documentation.en-us.md @@ -27,7 +27,6 @@ log groups: * The Router logger * The Access logger * The XORM logger -* A logger called the `GitLogger` which is used during hooks. There is also the go log logger. @@ -180,21 +179,6 @@ which will not be inherited from the `[log]` or relevant * `EXPRESSION` will default to `""` * `PREFIX` will default to `""` -### The Hook and Serv "GitLoggers" - -These are less well defined loggers. Essentially these should only be -used within Gitea's subsystems and cannot be configured at present. - -They will write log files in: - -* `%(ROOT_PATH)/hooks/pre-receive.log` -* `%(ROOT_PATH)/hooks/update.log` -* `%(ROOT_PATH)/hooks/post-receive.log` -* `%(ROOT_PATH)/serv.log` -* `%(ROOT_PATH)/http.log` - -In the future these logs may be rationalised. - ## Log outputs Gitea provides 4 possible log outputs: diff --git a/integrations/internal_test.go b/integrations/internal_test.go deleted file mode 100644 index ee0c0d18f1..0000000000 --- a/integrations/internal_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 The Gitea 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 integrations - -import ( - "encoding/json" - "fmt" - "net/http" - "testing" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - - "github.com/stretchr/testify/assert" -) - -func assertProtectedBranch(t *testing.T, repoID int64, branchName string, isErr, canPush bool) { - reqURL := fmt.Sprintf("/api/internal/branch/%d/%s", repoID, util.PathEscapeSegments(branchName)) - req := NewRequest(t, "GET", reqURL) - t.Log(reqURL) - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", setting.InternalToken)) - - resp := MakeRequest(t, req, NoExpectedStatus) - if isErr { - assert.EqualValues(t, http.StatusInternalServerError, resp.Code) - } else { - assert.EqualValues(t, http.StatusOK, resp.Code) - var branch models.ProtectedBranch - t.Log(resp.Body.String()) - assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), &branch)) - assert.Equal(t, canPush, !branch.IsProtected()) - } -} - -func TestInternal_GetProtectedBranch(t *testing.T) { - prepareTestEnv(t) - - assertProtectedBranch(t, 1, "master", false, true) - assertProtectedBranch(t, 1, "dev", false, true) - assertProtectedBranch(t, 1, "lunny/dev", false, true) -} diff --git a/models/helper_environment.go b/models/helper_environment.go index 737a9a68c3..199eb6062d 100644 --- a/models/helper_environment.go +++ b/models/helper_environment.go @@ -27,7 +27,7 @@ func PushingEnvironment(doer *User, repo *Repository) []string { "GIT_COMMITTER_NAME="+sig.Name, "GIT_COMMITTER_EMAIL="+sig.Email, EnvRepoName+"="+repo.Name, - EnvRepoUsername+"="+repo.OwnerName, + EnvRepoUsername+"="+repo.MustOwnerName(), EnvRepoIsWiki+"="+isWiki, EnvPusherName+"="+doer.Name, EnvPusherID+"="+fmt.Sprintf("%d", doer.ID), diff --git a/modules/log/log.go b/modules/log/log.go index d18996d48d..8698e9eed3 100644 --- a/modules/log/log.go +++ b/modules/log/log.go @@ -5,9 +5,7 @@ package log import ( - "fmt" "os" - "path" "runtime" "strings" ) @@ -17,9 +15,7 @@ var ( DEFAULT = "default" // NamedLoggers map of named loggers NamedLoggers = make(map[string]*Logger) - // GitLogger logger for git - GitLogger *Logger - prefix string + prefix string ) // NewLogger create a logger for the default logger @@ -72,19 +68,6 @@ func GetLogger(name string) *Logger { return NamedLoggers[DEFAULT] } -// NewGitLogger create a logger for git -// FIXME: use same log level as other loggers. -func NewGitLogger(logPath string) { - path := path.Dir(logPath) - - if err := os.MkdirAll(path, os.ModePerm); err != nil { - Fatal("Failed to create dir %s: %v", path, err) - } - - GitLogger = newLogger("git", 0) - GitLogger.SetLogger("file", "file", fmt.Sprintf(`{"level":"TRACE","filename":"%s","rotate":true,"maxsize":%d,"daily":true,"maxdays":7,"compress":true,"compressionLevel":-1, "stacktraceLevel":"NONE"}`, logPath, 1<<28)) -} - // GetLevel returns the minimum logger level func GetLevel() Level { return NamedLoggers[DEFAULT].GetLevel() diff --git a/modules/pprof/pprof.go b/modules/pprof/pprof.go index e02c2d0f2a..b63904e713 100644 --- a/modules/pprof/pprof.go +++ b/modules/pprof/pprof.go @@ -9,34 +9,30 @@ import ( "io/ioutil" "runtime" "runtime/pprof" - - "code.gitea.io/gitea/modules/log" ) // DumpMemProfileForUsername dumps a memory profile at pprofDataPath as memprofile__ -func DumpMemProfileForUsername(pprofDataPath, username string) { +func DumpMemProfileForUsername(pprofDataPath, username string) error { f, err := ioutil.TempFile(pprofDataPath, fmt.Sprintf("memprofile_%s_", username)) if err != nil { - log.GitLogger.Fatal("Could not create memory profile: %v", err) + return err } defer f.Close() runtime.GC() // get up-to-date statistics - if err := pprof.WriteHeapProfile(f); err != nil { - log.GitLogger.Fatal("Could not write memory profile: %v", err) - } + return pprof.WriteHeapProfile(f) } // DumpCPUProfileForUsername dumps a CPU profile at pprofDataPath as cpuprofile__ // it returns the stop function which stops, writes and closes the CPU profile file -func DumpCPUProfileForUsername(pprofDataPath, username string) func() { +func DumpCPUProfileForUsername(pprofDataPath, username string) (func(), error) { f, err := ioutil.TempFile(pprofDataPath, fmt.Sprintf("cpuprofile_%s_", username)) if err != nil { - log.GitLogger.Fatal("Could not create cpu profile: %v", err) + return nil, err } pprof.StartCPUProfile(f) return func() { pprof.StopCPUProfile() f.Close() - } + }, nil } diff --git a/modules/private/branch.go b/modules/private/branch.go deleted file mode 100644 index bbd0d4b697..0000000000 --- a/modules/private/branch.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2017 The Gitea 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 private - -import ( - "encoding/json" - "fmt" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" -) - -// GetProtectedBranchBy get protected branch information -func GetProtectedBranchBy(repoID int64, branchName string) (*models.ProtectedBranch, error) { - // Ask for running deliver hook and test pull request tasks. - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/branch/%d/%s", repoID, util.PathEscapeSegments(branchName)) - log.GitLogger.Trace("GetProtectedBranchBy: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, err - } - - var branch models.ProtectedBranch - if err := json.NewDecoder(resp.Body).Decode(&branch); err != nil { - return nil, err - } - - defer resp.Body.Close() - - // All 2XX status codes are accepted and others will return an error - if resp.StatusCode/100 != 2 { - return nil, fmt.Errorf("Failed to get protected branch: %s", decodeJSONError(resp).Err) - } - - return &branch, nil -} - -// CanUserPush returns if user can push -func CanUserPush(protectedBranchID, userID int64) (bool, error) { - // Ask for running deliver hook and test pull request tasks. - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/protectedbranch/%d/%d", protectedBranchID, userID) - log.GitLogger.Trace("CanUserPush: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return false, err - } - - var canPush = make(map[string]interface{}) - if err := json.NewDecoder(resp.Body).Decode(&canPush); err != nil { - return false, err - } - - defer resp.Body.Close() - - // All 2XX status codes are accepted and others will return an error - if resp.StatusCode/100 != 2 { - return false, fmt.Errorf("Failed to retrieve push user: %s", decodeJSONError(resp).Err) - } - - return canPush["can_push"].(bool), nil -} diff --git a/modules/private/hook.go b/modules/private/hook.go new file mode 100644 index 0000000000..7e2a475d4b --- /dev/null +++ b/modules/private/hook.go @@ -0,0 +1,84 @@ +// Copyright 2019 The Gitea 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 private + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "code.gitea.io/gitea/modules/setting" +) + +// Git environment variables +const ( + GitAlternativeObjectDirectories = "GIT_ALTERNATE_OBJECT_DIRECTORIES" + GitObjectDirectory = "GIT_OBJECT_DIRECTORY" + GitQuarantinePath = "GIT_QUARANTINE_PATH" +) + +// HookOptions represents the options for the Hook calls +type HookOptions struct { + OldCommitID string + NewCommitID string + RefFullName string + UserID int64 + UserName string + GitObjectDirectory string + GitAlternativeObjectDirectories string +} + +// HookPreReceive check whether the provided commits are allowed +func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) { + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s", + url.PathEscape(ownerName), + url.PathEscape(repoName), + url.QueryEscape(opts.OldCommitID), + url.QueryEscape(opts.NewCommitID), + url.QueryEscape(opts.RefFullName), + opts.UserID, + url.QueryEscape(opts.GitObjectDirectory), + url.QueryEscape(opts.GitAlternativeObjectDirectories), + ) + + resp, err := newInternalRequest(reqURL, "GET").Response() + if err != nil { + return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error()) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return resp.StatusCode, decodeJSONError(resp).Err + } + + return http.StatusOK, "" +} + +// HookPostReceive updates services and users +func HookPostReceive(ownerName, repoName string, opts HookOptions) (map[string]interface{}, string) { + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/post-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&username=%s", + url.PathEscape(ownerName), + url.PathEscape(repoName), + url.QueryEscape(opts.OldCommitID), + url.QueryEscape(opts.NewCommitID), + url.QueryEscape(opts.RefFullName), + opts.UserID, + url.QueryEscape(opts.UserName)) + + resp, err := newInternalRequest(reqURL, "GET").Response() + if err != nil { + return nil, fmt.Sprintf("Unable to contact gitea: %v", err.Error()) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, decodeJSONError(resp).Err + } + res := map[string]interface{}{} + _ = json.NewDecoder(resp.Body).Decode(&res) + + return res, "" +} diff --git a/modules/private/internal.go b/modules/private/internal.go index 56852ce63c..b4fee2680f 100644 --- a/modules/private/internal.go +++ b/modules/private/internal.go @@ -10,11 +10,8 @@ import ( "fmt" "net" "net/http" - "net/url" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/httplib" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) @@ -51,49 +48,3 @@ func newInternalRequest(url, method string) *httplib.Request { } return req } - -// CheckUnitUser check whether user could visit the unit of this repository -func CheckUnitUser(userID, repoID int64, isAdmin bool, unitType models.UnitType) (*models.AccessMode, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/user/%d/checkunituser?isAdmin=%t&unitType=%d", repoID, userID, isAdmin, unitType) - log.GitLogger.Trace("CheckUnitUser: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Failed to CheckUnitUser: %s", decodeJSONError(resp).Err) - } - - var a models.AccessMode - if err := json.NewDecoder(resp.Body).Decode(&a); err != nil { - return nil, err - } - - return &a, nil -} - -// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. -func GetRepositoryByOwnerAndName(ownerName, repoName string) (*models.Repository, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repo/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName)) - log.GitLogger.Trace("GetRepositoryByOwnerAndName: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Failed to get repository: %s", decodeJSONError(resp).Err) - } - - var repo models.Repository - if err := json.NewDecoder(resp.Body).Decode(&repo); err != nil { - return nil, err - } - - return &repo, nil -} diff --git a/modules/private/key.go b/modules/private/key.go index 1c6511846b..ebc28eb871 100644 --- a/modules/private/key.go +++ b/modules/private/key.go @@ -5,127 +5,15 @@ package private import ( - "encoding/json" "fmt" - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) -// UpdateDeployKeyUpdated update deploy key updates -func UpdateDeployKeyUpdated(keyID int64, repoID int64) error { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/keys/%d/update", repoID, keyID) - log.GitLogger.Trace("UpdateDeployKeyUpdated: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "POST").Response() - if err != nil { - return err - } - - defer resp.Body.Close() - - // All 2XX status codes are accepted and others will return an error - if resp.StatusCode/100 != 2 { - return fmt.Errorf("Failed to update deploy key: %s", decodeJSONError(resp).Err) - } - return nil -} - -// GetDeployKey check if repo has deploy key -func GetDeployKey(keyID, repoID int64) (*models.DeployKey, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/keys/%d", repoID, keyID) - log.GitLogger.Trace("GetDeployKey: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, err - } - defer resp.Body.Close() - - switch resp.StatusCode { - case 404: - return nil, nil - case 200: - var dKey models.DeployKey - if err := json.NewDecoder(resp.Body).Decode(&dKey); err != nil { - return nil, err - } - return &dKey, nil - default: - return nil, fmt.Errorf("Failed to get deploy key: %s", decodeJSONError(resp).Err) - } -} - -// HasDeployKey check if repo has deploy key -func HasDeployKey(keyID, repoID int64) (bool, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/has-keys/%d", repoID, keyID) - log.GitLogger.Trace("HasDeployKey: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return false, err - } - defer resp.Body.Close() - - if resp.StatusCode == 200 { - return true, nil - } - return false, nil -} - -// GetPublicKeyByID get public ssh key by his ID -func GetPublicKeyByID(keyID int64) (*models.PublicKey, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d", keyID) - log.GitLogger.Trace("GetPublicKeyByID: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, err - } - - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Failed to get repository: %s", decodeJSONError(resp).Err) - } - - var pKey models.PublicKey - if err := json.NewDecoder(resp.Body).Decode(&pKey); err != nil { - return nil, err - } - return &pKey, nil -} - -// GetUserByKeyID get user attached to key -func GetUserByKeyID(keyID int64) (*models.User, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/user", keyID) - log.GitLogger.Trace("GetUserByKeyID: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Failed to get user: %s", decodeJSONError(resp).Err) - } - - var user models.User - if err := json.NewDecoder(resp.Body).Decode(&user); err != nil { - return nil, err - } - - return &user, nil -} - -// UpdatePublicKeyUpdated update public key updates -func UpdatePublicKeyUpdated(keyID int64) error { +// UpdatePublicKeyInRepo update public key and if necessary deploy key updates +func UpdatePublicKeyInRepo(keyID, repoID int64) error { // Ask for running deliver hook and test pull request tasks. - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/update", keyID) - log.GitLogger.Trace("UpdatePublicKeyUpdated: %s", reqURL) - + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/update/%d", keyID, repoID) resp, err := newInternalRequest(reqURL, "POST").Response() if err != nil { return err diff --git a/modules/private/push_update.go b/modules/private/push_update.go deleted file mode 100644 index f3071b63ad..0000000000 --- a/modules/private/push_update.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2017 The Gitea 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 private - -import ( - "encoding/json" - "fmt" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" -) - -// PushUpdate update publick key updates -func PushUpdate(opt models.PushUpdateOptions) error { - // Ask for running deliver hook and test pull request tasks. - reqURL := setting.LocalURL + "api/internal/push/update" - log.GitLogger.Trace("PushUpdate: %s", reqURL) - - body, err := json.Marshal(&opt) - if err != nil { - return err - } - - resp, err := newInternalRequest(reqURL, "POST").Body(body).Response() - if err != nil { - return err - } - - defer resp.Body.Close() - - // All 2XX status codes are accepted and others will return an error - if resp.StatusCode/100 != 2 { - return fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err) - } - - return nil -} diff --git a/modules/private/repository.go b/modules/private/repository.go deleted file mode 100644 index cf8ae68409..0000000000 --- a/modules/private/repository.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018 The Gitea 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 private - -import ( - "encoding/json" - "fmt" - "net/url" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" -) - -// GetRepository return the repository by its ID and a bool about if it's allowed to have PR -func GetRepository(repoID int64) (*models.Repository, bool, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repository/%d", repoID) - log.GitLogger.Trace("GetRepository: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, false, err - } - - var repoInfo struct { - Repository *models.Repository - AllowPullRequest bool - } - if err := json.NewDecoder(resp.Body).Decode(&repoInfo); err != nil { - return nil, false, err - } - - defer resp.Body.Close() - - // All 2XX status codes are accepted and others will return an error - if resp.StatusCode/100 != 2 { - return nil, false, fmt.Errorf("failed to retrieve repository: %s", decodeJSONError(resp).Err) - } - - return repoInfo.Repository, repoInfo.AllowPullRequest, nil -} - -// ActivePullRequest returns an active pull request if it exists -func ActivePullRequest(baseRepoID int64, headRepoID int64, baseBranch, headBranch string) (*models.PullRequest, error) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/active-pull-request?baseRepoID=%d&headRepoID=%d&baseBranch=%s&headBranch=%s", baseRepoID, headRepoID, url.QueryEscape(baseBranch), url.QueryEscape(headBranch)) - log.GitLogger.Trace("ActivePullRequest: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return nil, err - } - - var pr *models.PullRequest - if err := json.NewDecoder(resp.Body).Decode(&pr); err != nil { - return nil, err - } - - defer resp.Body.Close() - - // All 2XX status codes are accepted and others will return an error - if resp.StatusCode/100 != 2 { - return nil, fmt.Errorf("failed to retrieve pull request: %s", decodeJSONError(resp).Err) - } - - return pr, nil -} diff --git a/modules/private/serv.go b/modules/private/serv.go new file mode 100644 index 0000000000..5b4a27f116 --- /dev/null +++ b/modules/private/serv.go @@ -0,0 +1,106 @@ +// Copyright 2019 The Gitea 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 private + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/setting" +) + +// KeyAndOwner is the response from ServNoCommand +type KeyAndOwner struct { + Key *models.PublicKey `json:"key"` + Owner *models.User `json:"user"` +} + +// ServNoCommand returns information about the provided key +func ServNoCommand(keyID int64) (*models.PublicKey, *models.User, error) { + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/none/%d", + keyID) + resp, err := newInternalRequest(reqURL, "GET").Response() + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, nil, fmt.Errorf("%s", decodeJSONError(resp).Err) + } + + var keyAndOwner KeyAndOwner + if err := json.NewDecoder(resp.Body).Decode(&keyAndOwner); err != nil { + return nil, nil, err + } + return keyAndOwner.Key, keyAndOwner.Owner, nil +} + +// ServCommandResults are the results of a call to the private route serv +type ServCommandResults struct { + IsWiki bool + IsDeployKey bool + KeyID int64 + KeyName string + UserName string + UserID int64 + OwnerName string + RepoName string + RepoID int64 +} + +// ErrServCommand is an error returned from ServCommmand. +type ErrServCommand struct { + Results ServCommandResults + Type string + Err string + StatusCode int +} + +func (err ErrServCommand) Error() string { + return err.Err +} + +// IsErrServCommand checks if an error is a ErrServCommand. +func IsErrServCommand(err error) bool { + _, ok := err.(ErrServCommand) + return ok +} + +// ServCommand preps for a serv call +func ServCommand(keyID int64, ownerName, repoName string, mode models.AccessMode, verbs ...string) (*ServCommandResults, error) { + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/command/%d/%s/%s?mode=%d", + keyID, + url.PathEscape(ownerName), + url.PathEscape(repoName), + mode) + for _, verb := range verbs { + if verb != "" { + reqURL += fmt.Sprintf("&verb=%s", url.QueryEscape(verb)) + } + } + + resp, err := newInternalRequest(reqURL, "GET").Response() + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + var errServCommand ErrServCommand + if err := json.NewDecoder(resp.Body).Decode(&errServCommand); err != nil { + return nil, err + } + errServCommand.StatusCode = resp.StatusCode + return nil, errServCommand + } + var results ServCommandResults + if err := json.NewDecoder(resp.Body).Decode(&results); err != nil { + return nil, err + } + return &results, nil + +} diff --git a/modules/private/wiki.go b/modules/private/wiki.go deleted file mode 100644 index 4ad0cc7c4e..0000000000 --- a/modules/private/wiki.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018 The Gitea 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 private - -import ( - "fmt" - - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" -) - -// InitWiki initwiki via repo id -func InitWiki(repoID int64) error { - // Ask for running deliver hook and test pull request tasks. - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/wiki/init", repoID) - log.GitLogger.Trace("InitWiki: %s", reqURL) - - resp, err := newInternalRequest(reqURL, "GET").Response() - if err != nil { - return err - } - - defer resp.Body.Close() - - // All 2XX status codes are accepted and others will return an error - if resp.StatusCode/100 != 2 { - return fmt.Errorf("Failed to init wiki: %s", decodeJSONError(resp).Err) - } - - return nil -} diff --git a/routers/init.go b/routers/init.go index cfeb928819..b3078b478a 100644 --- a/routers/init.go +++ b/routers/init.go @@ -5,7 +5,6 @@ package routers import ( - "path" "strings" "time" @@ -99,7 +98,6 @@ func GlobalInit() { models.InitSyncMirrors() models.InitDeliverHooks() models.InitTestPullRequests() - log.NewGitLogger(path.Join(setting.LogRootPath, "http.log")) } if models.EnableSQLite3 { log.Info("SQLite3 Supported") diff --git a/routers/private/branch.go b/routers/private/branch.go deleted file mode 100644 index 448c61f1db..0000000000 --- a/routers/private/branch.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 The Gitea 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 private - -import ( - "code.gitea.io/gitea/models" - - macaron "gopkg.in/macaron.v1" -) - -// GetProtectedBranchBy get protected branch information -func GetProtectedBranchBy(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":id") - branchName := ctx.Params("*") - protectBranch, err := models.GetProtectedBranchBy(repoID, branchName) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } else if protectBranch != nil { - ctx.JSON(200, protectBranch) - } else { - ctx.JSON(200, &models.ProtectedBranch{ - ID: 0, - }) - } -} - -// CanUserPush returns if user push -func CanUserPush(ctx *macaron.Context) { - pbID := ctx.ParamsInt64(":pbid") - userID := ctx.ParamsInt64(":userid") - - protectBranch, err := models.GetProtectedBranchByID(pbID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } else if protectBranch != nil { - ctx.JSON(200, map[string]interface{}{ - "can_push": protectBranch.CanUserPush(userID), - }) - } else { - ctx.JSON(200, map[string]interface{}{ - "can_push": false, - }) - } -} diff --git a/routers/private/hook.go b/routers/private/hook.go new file mode 100644 index 0000000000..700c8bf332 --- /dev/null +++ b/routers/private/hook.go @@ -0,0 +1,209 @@ +// Copyright 2019 The Gitea 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 private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead. +package private + +import ( + "fmt" + "net/http" + "os" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/util" + + macaron "gopkg.in/macaron.v1" +) + +// HookPreReceive checks whether a individual commit is acceptable +func HookPreReceive(ctx *macaron.Context) { + ownerName := ctx.Params(":owner") + repoName := ctx.Params(":repo") + oldCommitID := ctx.QueryTrim("old") + newCommitID := ctx.QueryTrim("new") + refFullName := ctx.QueryTrim("ref") + userID := ctx.QueryInt64("userID") + gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory") + gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories") + + branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) + repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + if err != nil { + log.Error("Unable to get repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": err.Error(), + }) + return + } + repo.OwnerName = ownerName + protectBranch, err := models.GetProtectedBranchBy(repo.ID, branchName) + if err != nil { + log.Error("Unable to get protected branch: %s in %-v Error: %v", branchName, repo, err) + ctx.JSON(500, map[string]interface{}{ + "err": err.Error(), + }) + return + } + if protectBranch != nil && protectBranch.IsProtected() { + // check and deletion + if newCommitID == git.EmptySHA { + log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo) + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": fmt.Sprintf("branch %s is protected from deletion", branchName), + }) + return + } + + // detect force push + if git.EmptySHA != oldCommitID { + env := append(os.Environ(), + private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories, + private.GitObjectDirectory+"="+gitObjectDirectory, + private.GitQuarantinePath+"="+gitObjectDirectory, + ) + + output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), env) + if err != nil { + log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Fail to detect force push: %v", err), + }) + return + } else if len(output) > 0 { + log.Warn("Forbidden: Branch: %s in %-v is protected from force push", branchName, repo) + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": fmt.Sprintf("branch %s is protected from force push", branchName), + }) + return + + } + } + + if !protectBranch.CanUserPush(userID) { + log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v", userID, branchName, repo) + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": fmt.Sprintf("protected branch %s can not be pushed to", branchName), + }) + return + } + } + ctx.PlainText(http.StatusOK, []byte("ok")) +} + +// HookPostReceive updates services and users +func HookPostReceive(ctx *macaron.Context) { + ownerName := ctx.Params(":owner") + repoName := ctx.Params(":repo") + oldCommitID := ctx.Query("old") + newCommitID := ctx.Query("new") + refFullName := ctx.Query("ref") + userID := ctx.QueryInt64("userID") + userName := ctx.Query("username") + + branch := refFullName + if strings.HasPrefix(refFullName, git.BranchPrefix) { + branch = strings.TrimPrefix(refFullName, git.BranchPrefix) + } else if strings.HasPrefix(refFullName, git.TagPrefix) { + branch = strings.TrimPrefix(refFullName, git.TagPrefix) + } + + // Only trigger activity updates for changes to branches or + // tags. Updates to other refs (eg, refs/notes, refs/changes, + // or other less-standard refs spaces are ignored since there + // may be a very large number of them). + if strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) { + if err := models.PushUpdate(branch, models.PushUpdateOptions{ + RefFullName: refFullName, + OldCommitID: oldCommitID, + NewCommitID: newCommitID, + PusherID: userID, + PusherName: userName, + RepoUserName: ownerName, + RepoName: repoName, + }); err != nil { + log.Error("Failed to Update: %s/%s Branch: %s Error: %v", ownerName, repoName, branch, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Failed to Update: %s/%s Branch: %s Error: %v", ownerName, repoName, branch, err), + }) + return + } + } + + if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) { + repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + if err != nil { + log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + repo.OwnerName = ownerName + + pullRequestAllowed := repo.AllowsPulls() + if !pullRequestAllowed { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": false, + }) + return + } + + baseRepo := repo + if repo.IsFork { + if err := repo.GetBaseRepo(); err != nil { + log.Error("Failed to get Base Repository of Forked repository: %-v Error: %v", repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Failed to get Base Repository of Forked repository: %-v Error: %v", repo, err), + }) + return + } + baseRepo = repo.BaseRepo + } + + if !repo.IsFork && branch == baseRepo.DefaultBranch { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": false, + }) + return + } + + pr, err := models.GetUnmergedPullRequest(repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch) + if err != nil && !models.IsErrPullRequestNotExist(err) { + log.Error("Failed to get active PR in: %-v Branch: %s to: %-v Branch: %s Error: %v", repo, branch, baseRepo, baseRepo.DefaultBranch, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf( + "Failed to get active PR in: %-v Branch: %s to: %-v Branch: %s Error: %v", repo, branch, baseRepo, baseRepo.DefaultBranch, err), + }) + return + } + + if pr == nil { + if repo.IsFork { + branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch) + } + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": true, + "create": true, + "branch": branch, + "url": fmt.Sprintf("%s/compare/%s...%s", baseRepo.HTMLURL(), util.PathEscapeSegments(baseRepo.DefaultBranch), util.PathEscapeSegments(branch)), + }) + } else { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": true, + "create": false, + "branch": branch, + "url": fmt.Sprintf("%s/pulls/%d", baseRepo.HTMLURL(), pr.Index), + }) + } + return + } + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": false, + }) + return +} diff --git a/routers/private/internal.go b/routers/private/internal.go index ee6e1274c3..11cea8b4b9 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -76,19 +76,10 @@ func CheckUnitUser(ctx *macaron.Context) { // These APIs will be invoked by internal commands for example `gitea serv` and etc. func RegisterRoutes(m *macaron.Macaron) { m.Group("/", func() { - m.Get("/ssh/:id", GetPublicKeyByID) - m.Get("/ssh/:id/user", GetUserByKeyID) - m.Post("/ssh/:id/update", UpdatePublicKey) - m.Post("/repositories/:repoid/keys/:keyid/update", UpdateDeployKey) - m.Get("/repositories/:repoid/user/:userid/checkunituser", CheckUnitUser) - m.Get("/repositories/:repoid/has-keys/:keyid", HasDeployKey) - m.Get("/repositories/:repoid/keys/:keyid", GetDeployKey) - m.Get("/repositories/:repoid/wiki/init", InitWiki) - m.Post("/push/update", PushUpdate) - m.Get("/protectedbranch/:pbid/:userid", CanUserPush) - m.Get("/repo/:owner/:repo", GetRepositoryByOwnerAndName) - m.Get("/branch/:id/*", GetProtectedBranchBy) - m.Get("/repository/:rid", GetRepository) - m.Get("/active-pull-request", GetActivePullRequest) + m.Post("/ssh/:id/update/:repoid", UpdatePublicKeyInRepo) + m.Get("/hook/pre-receive/:owner/:repo", HookPreReceive) + m.Get("/hook/post-receive/:owner/:repo", HookPostReceive) + m.Get("/serv/none/:keyid", ServNoCommand) + m.Get("/serv/command/:keyid/:owner/:repo", ServCommand) }, CheckInternalToken) } diff --git a/routers/private/key.go b/routers/private/key.go index ee22f6ac48..f7212ec892 100644 --- a/routers/private/key.go +++ b/routers/private/key.go @@ -12,12 +12,23 @@ import ( macaron "gopkg.in/macaron.v1" ) -// UpdateDeployKey update deploy key updates -func UpdateDeployKey(ctx *macaron.Context) { +// UpdatePublicKeyInRepo update public key and deploy key updates +func UpdatePublicKeyInRepo(ctx *macaron.Context) { + keyID := ctx.ParamsInt64(":id") repoID := ctx.ParamsInt64(":repoid") - keyID := ctx.ParamsInt64(":keyid") + if err := models.UpdatePublicKeyUpdated(keyID); err != nil { + ctx.JSON(500, map[string]interface{}{ + "err": err.Error(), + }) + return + } + deployKey, err := models.GetDeployKeyByRepo(keyID, repoID) if err != nil { + if models.IsErrDeployKeyNotExist(err) { + ctx.PlainText(200, []byte("success")) + return + } ctx.JSON(500, map[string]interface{}{ "err": err.Error(), }) @@ -30,73 +41,6 @@ func UpdateDeployKey(ctx *macaron.Context) { }) return } - ctx.PlainText(200, []byte("success")) -} - -// UpdatePublicKey update publick key updates -func UpdatePublicKey(ctx *macaron.Context) { - keyID := ctx.ParamsInt64(":id") - if err := models.UpdatePublicKeyUpdated(keyID); err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } ctx.PlainText(200, []byte("success")) } - -//GetPublicKeyByID chainload to models.GetPublicKeyByID -func GetPublicKeyByID(ctx *macaron.Context) { - keyID := ctx.ParamsInt64(":id") - key, err := models.GetPublicKeyByID(keyID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - ctx.JSON(200, key) -} - -//GetUserByKeyID chainload to models.GetUserByKeyID -func GetUserByKeyID(ctx *macaron.Context) { - keyID := ctx.ParamsInt64(":id") - user, err := models.GetUserByKeyID(keyID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - ctx.JSON(200, user) -} - -//GetDeployKey chainload to models.GetDeployKey -func GetDeployKey(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":repoid") - keyID := ctx.ParamsInt64(":keyid") - dKey, err := models.GetDeployKeyByRepo(keyID, repoID) - if err != nil { - if models.IsErrDeployKeyNotExist(err) { - ctx.JSON(404, []byte("not found")) - return - } - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - ctx.JSON(200, dKey) -} - -//HasDeployKey chainload to models.HasDeployKey -func HasDeployKey(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":repoid") - keyID := ctx.ParamsInt64(":keyid") - if models.HasDeployKey(keyID, repoID) { - ctx.PlainText(200, []byte("success")) - return - } - ctx.PlainText(404, []byte("not found")) -} diff --git a/routers/private/push_update.go b/routers/private/push_update.go deleted file mode 100644 index 5c42f066ee..0000000000 --- a/routers/private/push_update.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017 The Gitea 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 private - -import ( - "encoding/json" - "strings" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - - macaron "gopkg.in/macaron.v1" -) - -// PushUpdate update public key updates -func PushUpdate(ctx *macaron.Context) { - var opt models.PushUpdateOptions - if err := json.NewDecoder(ctx.Req.Request.Body).Decode(&opt); err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - branch := strings.TrimPrefix(opt.RefFullName, git.BranchPrefix) - if len(branch) == 0 || opt.PusherID <= 0 { - ctx.Error(404) - log.Trace("PushUpdate: branch or secret is empty, or pusher ID is not valid") - return - } - - err := models.PushUpdate(branch, opt) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.Error(404) - } else { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - } - return - } - ctx.Status(202) -} diff --git a/routers/private/repository.go b/routers/private/repository.go deleted file mode 100644 index 9f451bcf1d..0000000000 --- a/routers/private/repository.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 The Gitea 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 private - -import ( - "net/http" - - "code.gitea.io/gitea/models" - - macaron "gopkg.in/macaron.v1" -) - -// GetRepository return the default branch of a repository -func GetRepository(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":rid") - repository, err := models.GetRepositoryByID(repoID) - repository.MustOwnerName() - allowPulls := repository.AllowsPulls() - // put it back to nil because json unmarshal can't unmarshal it - repository.Units = nil - - if err != nil { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - if repository.IsFork { - repository.GetBaseRepo() - if err != nil { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": err.Error(), - }) - return - } - repository.BaseRepo.MustOwnerName() - allowPulls = repository.BaseRepo.AllowsPulls() - // put it back to nil because json unmarshal can't unmarshal it - repository.BaseRepo.Units = nil - } - - ctx.JSON(http.StatusOK, struct { - Repository *models.Repository - AllowPullRequest bool - }{ - Repository: repository, - AllowPullRequest: allowPulls, - }) -} - -// GetActivePullRequest return an active pull request when it exists or an empty object -func GetActivePullRequest(ctx *macaron.Context) { - baseRepoID := ctx.QueryInt64("baseRepoID") - headRepoID := ctx.QueryInt64("headRepoID") - baseBranch := ctx.QueryTrim("baseBranch") - if len(baseBranch) == 0 { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": "QueryTrim failed", - }) - return - } - - headBranch := ctx.QueryTrim("headBranch") - if len(headBranch) == 0 { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": "QueryTrim failed", - }) - return - } - - pr, err := models.GetUnmergedPullRequest(headRepoID, baseRepoID, headBranch, baseBranch) - if err != nil && !models.IsErrPullRequestNotExist(err) { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - ctx.JSON(http.StatusOK, pr) -} diff --git a/routers/private/serv.go b/routers/private/serv.go new file mode 100644 index 0000000000..68e4361e56 --- /dev/null +++ b/routers/private/serv.go @@ -0,0 +1,286 @@ +// Copyright 2019 The Gitea 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 private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead. +package private + +import ( + "fmt" + "net/http" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" + + macaron "gopkg.in/macaron.v1" +) + +// ServNoCommand returns information about the provided keyid +func ServNoCommand(ctx *macaron.Context) { + keyID := ctx.ParamsInt64(":keyid") + if keyID <= 0 { + ctx.JSON(http.StatusBadRequest, map[string]interface{}{ + "err": fmt.Sprintf("Bad key id: %d", keyID), + }) + } + results := private.KeyAndOwner{} + + key, err := models.GetPublicKeyByID(keyID) + if err != nil { + if models.IsErrKeyNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "err": fmt.Sprintf("Cannot find key: %d", keyID), + }) + return + } + log.Error("Unable to get public key: %d Error: %v", keyID, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": err.Error(), + }) + return + } + results.Key = key + + if key.Type == models.KeyTypeUser { + user, err := models.GetUserByID(key.OwnerID) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "err": fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID), + }) + return + } + log.Error("Unable to get owner with id: %d for public key: %d Error: %v", key.OwnerID, keyID, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": err.Error(), + }) + return + } + results.Owner = user + } + ctx.JSON(http.StatusOK, &results) + return +} + +// ServCommand returns information about the provided keyid +func ServCommand(ctx *macaron.Context) { + // Although we provide the verbs we don't need them at present they're just for logging purposes + keyID := ctx.ParamsInt64(":keyid") + ownerName := ctx.Params(":owner") + repoName := ctx.Params(":repo") + mode := models.AccessMode(ctx.QueryInt("mode")) + + // Set the basic parts of the results to return + results := private.ServCommandResults{ + RepoName: repoName, + OwnerName: ownerName, + KeyID: keyID, + } + + // Now because we're not translating things properly let's just default some Engish strings here + modeString := "read" + if mode > models.AccessModeRead { + modeString = "write to" + } + + // The default unit we're trying to look at is code + unitType := models.UnitTypeCode + + // Unless we're a wiki... + if strings.HasSuffix(repoName, ".wiki") { + // in which case we need to look at the wiki + unitType = models.UnitTypeWiki + // And we'd better munge the reponame and tell downstream we're looking at a wiki + results.IsWiki = true + results.RepoName = repoName[:len(repoName)-5] + } + + // Now get the Repository and set the results section + repo, err := models.GetRepositoryByOwnerAndName(results.OwnerName, results.RepoName) + if err != nil { + if models.IsErrRepoNotExist(err) { + ctx.JSON(http.StatusNotFound, map[string]interface{}{ + "results": results, + "type": "ErrRepoNotExist", + "err": fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName), + }) + return + } + log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get repository: %s/%s %v", results.OwnerName, results.RepoName, err), + }) + return + } + repo.OwnerName = ownerName + results.RepoID = repo.ID + + // We can shortcut at this point if the repo is a mirror + if mode > models.AccessModeRead && repo.IsMirror { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrMirrorReadOnly", + "err": fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName), + }) + return + } + + // Get the Public Key represented by the keyID + key, err := models.GetPublicKeyByID(keyID) + if err != nil { + if models.IsErrKeyNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrKeyNotExist", + "err": fmt.Sprintf("Cannot find key: %d", keyID), + }) + return + } + log.Error("Unable to get public key: %d Error: %v", keyID, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get key: %d Error: %v", keyID, err), + }) + return + } + results.KeyName = key.Name + results.KeyID = key.ID + results.UserID = key.OwnerID + + // Deploy Keys have ownerID set to 0 therefore we can't use the owner + // So now we need to check if the key is a deploy key + // We'll keep hold of the deploy key here for permissions checking + var deployKey *models.DeployKey + var user *models.User + if key.Type == models.KeyTypeDeploy { + results.IsDeployKey = true + + var err error + deployKey, err = models.GetDeployKeyByRepo(key.ID, repo.ID) + if err != nil { + if models.IsErrDeployKeyNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrDeployKeyNotExist", + "err": fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName), + }) + return + } + log.Error("Unable to get deploy for public (deploy) key: %d in %-v Error: %v", key.ID, repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get Deploy Key for Public Key: %d:%s in %s/%s.", key.ID, key.Name, results.OwnerName, results.RepoName), + }) + return + } + results.KeyName = deployKey.Name + + // FIXME: Deploy keys aren't really the owner of the repo pushing changes + // however we don't have good way of representing deploy keys in hook.go + // so for now use the owner of the repository + results.UserName = results.OwnerName + results.UserID = repo.OwnerID + } else { + // Get the user represented by the Key + var err error + user, err = models.GetUserByID(key.OwnerID) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrUserNotExist", + "err": fmt.Sprintf("Public Key: %d:%s owner %d does not exist.", key.ID, key.Name, key.OwnerID), + }) + return + } + log.Error("Unable to get owner: %d for public key: %d:%s Error: %v", key.OwnerID, key.ID, key.Name, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get Owner: %d for Deploy Key: %d:%s in %s/%s.", key.OwnerID, key.ID, key.Name, ownerName, repoName), + }) + return + } + results.UserName = user.Name + } + + // Don't allow pushing if the repo is archived + if mode > models.AccessModeRead && repo.IsArchived { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrRepoIsArchived", + "err": fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName), + }) + return + } + + // Permissions checking: + if mode > models.AccessModeRead || repo.IsPrivate || setting.Service.RequireSignInView { + if key.Type == models.KeyTypeDeploy { + if deployKey.Mode < mode { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrUnauthorized", + "err": fmt.Sprintf("Deploy Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName), + }) + return + } + } else { + perm, err := models.GetUserRepoPermission(repo, user) + if err != nil { + log.Error("Unable to get permissions for %-v with key %d in %-v Error: %v", user, key.ID, repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get permissions for user %d:%s with key %d in %s/%s Error: %v", user.ID, user.Name, key.ID, results.OwnerName, results.RepoName, err), + }) + return + } + + userMode := perm.UnitAccessMode(unitType) + + if userMode < mode { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrUnauthorized", + "err": fmt.Sprintf("User: %d:%s with Key: %d:%s is not authorized to %s %s/%s.", user.ID, user.Name, key.ID, key.Name, modeString, ownerName, repoName), + }) + return + } + } + } + + // Finally if we're trying to touch the wiki we should init it + if results.IsWiki { + if err = repo.InitWiki(); err != nil { + log.Error("Failed to initialize the wiki in %-v Error: %v", repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Failed to initialize the wiki in %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + } + log.Debug("Serv Results:\nIsWiki: %t\nIsDeployKey: %t\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d", + results.IsWiki, + results.IsDeployKey, + results.KeyID, + results.KeyName, + results.UserName, + results.UserID, + results.OwnerName, + results.RepoName, + results.RepoID) + + ctx.JSON(http.StatusOK, results) + // We will update the keys in a different call. + return +} diff --git a/routers/private/wiki.go b/routers/private/wiki.go deleted file mode 100644 index 33bcbaf17e..0000000000 --- a/routers/private/wiki.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 The Gitea 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 private - -import ( - "code.gitea.io/gitea/models" - - macaron "gopkg.in/macaron.v1" -) - -// InitWiki initilizes wiki via repo id -func InitWiki(ctx *macaron.Context) { - repoID := ctx.ParamsInt64("repoid") - - repo, err := models.GetRepositoryByID(repoID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - err = repo.InitWiki() - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - ctx.Status(202) -} diff --git a/routers/repo/http.go b/routers/repo/http.go index fccecfb71d..214e2f3411 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -351,7 +351,7 @@ func gitCommand(dir string, args ...string) []byte { cmd.Dir = dir out, err := cmd.Output() if err != nil { - log.GitLogger.Error(fmt.Sprintf("%v - %s", err, out)) + log.Error("%v - %s", err, out) } return out } @@ -409,7 +409,7 @@ func serviceRPC(h serviceHandler, service string) { if h.r.Header.Get("Content-Encoding") == "gzip" { reqBody, err = gzip.NewReader(reqBody) if err != nil { - log.GitLogger.Error("Fail to create gzip reader: %v", err) + log.Error("Fail to create gzip reader: %v", err) h.w.WriteHeader(http.StatusInternalServerError) return } @@ -428,7 +428,7 @@ func serviceRPC(h serviceHandler, service string) { cmd.Stdin = reqBody cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - log.GitLogger.Error("Fail to serve RPC(%s): %v - %v", service, err, stderr) + log.Error("Fail to serve RPC(%s): %v - %v", service, err, stderr) return } } @@ -541,7 +541,7 @@ func HTTPBackend(ctx *context.Context, cfg *serviceConfig) http.HandlerFunc { file := strings.Replace(r.URL.Path, m[1]+"/", "", 1) dir, err := getGitRepoPath(m[1]) if err != nil { - log.GitLogger.Error(err.Error()) + log.Error(err.Error()) ctx.NotFound("HTTPBackend", err) return } From 8eba27c79257c6bc68cefbdffbb36d3596e6d3ee Mon Sep 17 00:00:00 2001 From: Mario Lubenka Date: Sun, 2 Jun 2019 08:40:12 +0200 Subject: [PATCH 079/220] Repository avatar fallback configuration (#7087) * Only show repository avatar in list when one was selected Signed-off-by: Mario Lubenka * Adds fallback configuration option for repository avatar Signed-off-by: Mario Lubenka * Implements repository avatar fallback Signed-off-by: Mario Lubenka * Adds admin task for deleting generated repository avatars Signed-off-by: Mario Lubenka * Solve linting issues Signed-off-by: Mario Lubenka * Save avatar before updating database * Linting * Update models/repo.go Co-Authored-By: zeripath --- custom/conf/app.ini.sample | 4 + .../doc/advanced/config-cheat-sheet.en-us.md | 5 ++ models/repo.go | 77 ++++++++++++++++-- modules/setting/setting.go | 24 +++--- options/locale/locale_en-US.ini | 2 + public/img/repo_default.png | Bin 0 -> 2464 bytes routers/admin/admin.go | 4 + templates/admin/dashboard.tmpl | 4 + templates/explore/repo_list.tmpl | 4 +- 9 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 public/img/repo_default.png diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index e8e3ffada6..a674984a25 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -505,6 +505,10 @@ SESSION_LIFE_TIME = 86400 [picture] AVATAR_UPLOAD_PATH = data/avatars REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars +; How Gitea deals with missing repository avatars +; none = no avatar will be displayed; random = random avatar will be displayed; image = default image will be used +REPOSITORY_AVATAR_FALLBACK = none +REPOSITORY_AVATAR_FALLBACK_IMAGE = /img/repo_default.png ; Max Width and Height of uploaded avatars. ; This is to limit the amount of RAM used when resizing the image. AVATAR_MAX_WIDTH = 4096 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 052ced6e2a..ecc196c86e 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -292,6 +292,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. [http://www.libravatar.org](http://www.libravatar.org)). - `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files. - `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: Path to store repository avatar image files. +- `REPOSITORY_AVATAR_FALLBACK`: **none**: How Gitea deals with missing repository avatars + - none = no avatar will be displayed + - random = random avatar will be generated + - image = default image will be used (which is set in `REPOSITORY_AVATAR_DEFAULT_IMAGE`) +- `REPOSITORY_AVATAR_FALLBACK_IMAGE`: **/img/repo_default.png**: Image used as default repository avatar (if `REPOSITORY_AVATAR_FALLBACK` is set to image and none was uploaded) - `AVATAR_MAX_WIDTH`: **4096**: Maximum avatar image width in pixels. - `AVATAR_MAX_HEIGHT`: **3072**: Maximum avatar image height in pixels. - `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): Maximum avatar image file size in bytes. diff --git a/models/repo.go b/models/repo.go index 16684bdeef..d5eca3d225 100644 --- a/models/repo.go +++ b/models/repo.go @@ -2528,17 +2528,78 @@ func (repo *Repository) CustomAvatarPath() string { return filepath.Join(setting.RepositoryAvatarUploadPath, repo.Avatar) } -// RelAvatarLink returns a relative link to the user's avatar. -// The link a sub-URL to this site -// Since Gravatar support not needed here - just check for image path. +// GenerateRandomAvatar generates a random avatar for repository. +func (repo *Repository) GenerateRandomAvatar() error { + return repo.generateRandomAvatar(x) +} + +func (repo *Repository) generateRandomAvatar(e Engine) error { + idToString := fmt.Sprintf("%d", repo.ID) + + seed := idToString + img, err := avatar.RandomImage([]byte(seed)) + if err != nil { + return fmt.Errorf("RandomImage: %v", err) + } + + repo.Avatar = idToString + if err = os.MkdirAll(filepath.Dir(repo.CustomAvatarPath()), os.ModePerm); err != nil { + return fmt.Errorf("MkdirAll: %v", err) + } + fw, err := os.Create(repo.CustomAvatarPath()) + if err != nil { + return fmt.Errorf("Create: %v", err) + } + defer fw.Close() + + if err = png.Encode(fw, img); err != nil { + return fmt.Errorf("Encode: %v", err) + } + log.Info("New random avatar created for repository: %d", repo.ID) + + if _, err := e.ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil { + return err + } + + return nil +} + +// RemoveRandomAvatars removes the randomly generated avatars that were created for repositories +func RemoveRandomAvatars() error { + var ( + err error + ) + err = x. + Where("id > 0").BufferSize(setting.IterateBufferSize). + Iterate(new(Repository), + func(idx int, bean interface{}) error { + repository := bean.(*Repository) + stringifiedID := strconv.FormatInt(repository.ID, 10) + if repository.Avatar == stringifiedID { + return repository.DeleteAvatar() + } + return nil + }) + return err +} + +// RelAvatarLink returns a relative link to the repository's avatar. func (repo *Repository) RelAvatarLink() string { + // If no avatar - path is empty avatarPath := repo.CustomAvatarPath() - if len(avatarPath) <= 0 { - return "" - } - if !com.IsFile(avatarPath) { - return "" + if len(avatarPath) <= 0 || !com.IsFile(avatarPath) { + switch mode := setting.RepositoryAvatarFallback; mode { + case "image": + return setting.RepositoryAvatarFallbackImage + case "random": + if err := repo.GenerateRandomAvatar(); err != nil { + log.Error("GenerateRandomAvatar: %v", err) + } + default: + // default behaviour: do not display avatar + return "" + } } return setting.AppSubURL + "/repo-avatars/" + repo.Avatar } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 9e96105788..ff53e9a375 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -250,16 +250,18 @@ var ( } // Picture settings - AvatarUploadPath string - AvatarMaxWidth int - AvatarMaxHeight int - GravatarSource string - GravatarSourceURL *url.URL - DisableGravatar bool - EnableFederatedAvatar bool - LibravatarService *libravatar.Libravatar - AvatarMaxFileSize int64 - RepositoryAvatarUploadPath string + AvatarUploadPath string + AvatarMaxWidth int + AvatarMaxHeight int + GravatarSource string + GravatarSourceURL *url.URL + DisableGravatar bool + EnableFederatedAvatar bool + LibravatarService *libravatar.Libravatar + AvatarMaxFileSize int64 + RepositoryAvatarUploadPath string + RepositoryAvatarFallback string + RepositoryAvatarFallbackImage string // Log settings LogLevel string @@ -842,6 +844,8 @@ func NewContext() { if !filepath.IsAbs(RepositoryAvatarUploadPath) { RepositoryAvatarUploadPath = path.Join(AppWorkPath, RepositoryAvatarUploadPath) } + RepositoryAvatarFallback = sec.Key("REPOSITORY_AVATAR_FALLBACK").MustString("none") + RepositoryAvatarFallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString("/img/repo_default.png") AvatarMaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096) AvatarMaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072) AvatarMaxFileSize = sec.Key("AVATAR_MAX_FILE_SIZE").MustInt64(1048576) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 645c9770a4..ebc6ca31ce 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1522,6 +1522,8 @@ dashboard.delete_repo_archives = Delete all repository archives dashboard.delete_repo_archives_success = All repository archives have been deleted. dashboard.delete_missing_repos = Delete all repositories missing their Git files dashboard.delete_missing_repos_success = All repositories missing their Git files have been deleted. +dashboard.delete_generated_repository_avatars = Delete generated repository avatars +dashboard.delete_generated_repository_avatars_success = Generated repository avatars were deleted. dashboard.git_gc_repos = Garbage collect all repositories dashboard.git_gc_repos_success = All repositories have finished garbage collection. dashboard.resync_all_sshkeys = Update the '.ssh/authorized_keys' file with Gitea SSH keys. (Not needed for the built-in SSH server.) diff --git a/public/img/repo_default.png b/public/img/repo_default.png new file mode 100644 index 0000000000000000000000000000000000000000..dbfa8437235208c9c565581c3ea54c38f0a70d43 GIT binary patch literal 2464 zcmb_edsGuw9-hXy;XoBuTu}%KFLA3vLJ*pSsG!hM1Bv*6SW<)-C?YSzLnCNRBeK*- zh>92^Nmq+hc}TQsBM;w_kdRoQU0%v=nM{fY*b?Yw(?r>sp3~FQKX%Wq>>qQ!`F+3d z`|h1PckY?Wtt@bXtG6ov01Gy6iroeP?^L0e3l?Ek-gyHefc-coAqD`{Qa5M%e5Cf< zvuRrb02~SifTPC%;3tGS`aJ*?lL6pW8UWBQ0DxD)rF)4Cq=Dfv!B_yeekzcHRJfwe z330g5`Gf`UV_T~fp#b3W#pc+U9R~*|UUWCW8NQuUCTh}!K<~jVxW)bN&X8pu%QRUZi_LvY%f*8MO~2R&|^1XQqaP5!P!%No0M!>UmsZ!BZAuQoxmil~3e6!~!KdhLmmMp6y;(HU`@ zzYPl4Wa(N>uX4=?*D302yzg`Uh+WBr-|%_|m`Yu({SD=cdno0{@9=sx_nzUSOq1|% zp2;jE*IPi6TGAG3vs`gAWaLN5hNhh}&+XBnx_O$6vXzd98#TFf*;u_6SI8w?s!y>t zjU_YcRT8}3_p#>y`{lWf_9^JWKm~`WbzdT~l(*-uBI<1LvxL;lt$!$m=t%hI#^`W6bP zQqoNGTF2KXG$ru7sqM23q78)c&m=T@cvd!!HfCGfpD2al%CK-TxBdKx`yL{Vv43Yb z5Ah9to4rUy`1y1hV0-fAMk3+t`C~8%cGl#@<*A=G}kjR8Xn(OVg9tz zKU|FWMo3K#PixS(r8r<^OX(d^^}9~P;dQRA;%I-5KVmWE(Vuy^EXIg8_-%E;{KkpVzr-Am%Nm@oUo4U?TqR?THj>cHU_J+@mZ@sm88_ zZ?`tTOe)g;*RPs#M;;{>`gG1cirV>Le^SX?zp$StrPkp(b8{U_PG20N{vV=fzdL>F zreqGg$OZf9>%xNJZ+qO**3UKQHUWPiZEQX{uNs`4>t6cM{j{P5+1z;f-OxF%QyB7m zZo-Mke6?}oi{PBewIj`<_;=+4F-jlg%d|V5RLP^2zR0bxgr|-76D>vA*C@+66`y{K z5gEo0uG)PPy=8>);g;78(~uS)sf!S1+bRs>erz*Zc3$xm8rl;N&OXOSKAn<>Z5Nro zFCds6{(0B9hy)MHD<-x_X+7=m^PtFw?_X7ZV|*Rgrm(J3IeFkEqs&>7**Cnrlwv#8 z%@egASScO2f9+5P%Y6NzaGcGy9Czj-$DBlYA6lr|X~yK5dkcm9e^%Fxn5}L5iUJ(n z>N25Vc!qgny-wC9JQ(cgtSnnuzXHcvhog<2VN|6&tG`KPoEx$_$F+8^RF%mwJu!7{ z{O}5R`hw_B)j=e$5lhLhC6*3A zDy^#>p#P_Xk-viRKo)brF@7xZYoqS_UZrxYWL1=u!f@R}70$LVD zDZrcIl@GRz7ZG%C*Tl50Y`S5JBr%P>_xak_ftTR8T4mvZzo2EW4DC z3KXE=2r4Kc=GzzCg|j`oN5V^loo@t*45SgKv{1R zJ9Eb3e%LmP>9b$HO8&e!0QrqsUKGbE;-?p7(Dw*35CACTFj@#XA|#x=BP^UA5kV)f p2_dhclgU@Q_ka5vLvB8QZ>I3y8+xjA*@ywy9LI`n-jMdmzW{dZ%{Tx6 literal 0 HcmV?d00001 diff --git a/routers/admin/admin.go b/routers/admin/admin.go index 0e6fa2c242..5107e18b7d 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -125,6 +125,7 @@ const ( reinitMissingRepository syncExternalUsers gitFsck + deleteGeneratedRepositoryAvatars ) // Dashboard show admin panel dashboard @@ -167,6 +168,9 @@ func Dashboard(ctx *context.Context) { case gitFsck: success = ctx.Tr("admin.dashboard.git_fsck_started") go models.GitFsck() + case deleteGeneratedRepositoryAvatars: + success = ctx.Tr("admin.dashboard.delete_generated_repository_avatars_success") + err = models.RemoveRandomAvatars() } if err != nil { diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index 13c06334a5..262db04b90 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -53,6 +53,10 @@ {{.i18n.Tr "admin.dashboard.git_fsck"}} {{.i18n.Tr "admin.dashboard.operation_run"}} + + {{.i18n.Tr "admin.dashboard.delete_generated_repository_avatars"}} + {{.i18n.Tr "admin.dashboard.operation_run"}} +
    diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl index 34aab6477a..8c7ba51a54 100644 --- a/templates/explore/repo_list.tmpl +++ b/templates/explore/repo_list.tmpl @@ -2,7 +2,9 @@ {{range .Repos}}
    - + {{if .RelAvatarLink}} + + {{end}} {{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} / {{end}}{{end}}{{.Name}} {{if .IsArchived}}{{end}} From 83b90e41999d30e4abb46f6bf0f1c3359cfd4d04 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 3 Jun 2019 05:43:47 +0800 Subject: [PATCH 080/220] Use vfsgen instead of go-bindata (#7080) * use vfsgen instead of go-bindata * fix templates * fix fmt * vendor vsfgen --- Makefile | 5 +- go.mod | 4 +- go.sum | 9 +- main.go | 3 + modules/options/main.go | 23 + modules/options/options.go | 4 +- modules/options/static.go | 28 +- modules/public/main.go | 23 + modules/public/public.go | 4 +- modules/public/static.go | 9 +- modules/templates/main.go | 23 + modules/templates/static.go | 18 + modules/templates/templates.go | 4 +- snap/snapcraft.yaml | 1 - .../elazarl/go-bindata-assetfs/LICENSE | 23 - .../elazarl/go-bindata-assetfs/README.md | 46 -- .../elazarl/go-bindata-assetfs/assetfs.go | 158 ------ .../elazarl/go-bindata-assetfs/doc.go | 13 - .../github.com/go-macaron/bindata/.travis.yml | 14 - vendor/github.com/go-macaron/bindata/LICENSE | 191 ------- .../github.com/go-macaron/bindata/README.md | 16 - .../github.com/go-macaron/bindata/bindata.go | 117 ----- vendor/github.com/shurcooL/httpfs/LICENSE | 21 + .../shurcooL/httpfs/vfsutil/file.go | 21 + .../shurcooL/httpfs/vfsutil/vfsutil.go | 39 ++ .../shurcooL/httpfs/vfsutil/walk.go | 146 ++++++ vendor/github.com/shurcooL/vfsgen/.travis.yml | 16 + .../shurcooL/vfsgen/CONTRIBUTING.md | 10 + vendor/github.com/shurcooL/vfsgen/LICENSE | 21 + vendor/github.com/shurcooL/vfsgen/README.md | 201 ++++++++ .../shurcooL/vfsgen/commentwriter.go | 45 ++ vendor/github.com/shurcooL/vfsgen/doc.go | 15 + .../github.com/shurcooL/vfsgen/generator.go | 485 ++++++++++++++++++ vendor/github.com/shurcooL/vfsgen/options.go | 45 ++ .../shurcooL/vfsgen/stringwriter.go | 27 + vendor/modules.txt | 8 +- 36 files changed, 1224 insertions(+), 612 deletions(-) create mode 100644 modules/options/main.go create mode 100644 modules/public/main.go create mode 100644 modules/templates/main.go delete mode 100644 vendor/github.com/elazarl/go-bindata-assetfs/LICENSE delete mode 100644 vendor/github.com/elazarl/go-bindata-assetfs/README.md delete mode 100644 vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go delete mode 100644 vendor/github.com/elazarl/go-bindata-assetfs/doc.go delete mode 100644 vendor/github.com/go-macaron/bindata/.travis.yml delete mode 100644 vendor/github.com/go-macaron/bindata/LICENSE delete mode 100644 vendor/github.com/go-macaron/bindata/README.md delete mode 100644 vendor/github.com/go-macaron/bindata/bindata.go create mode 100644 vendor/github.com/shurcooL/httpfs/LICENSE create mode 100644 vendor/github.com/shurcooL/httpfs/vfsutil/file.go create mode 100644 vendor/github.com/shurcooL/httpfs/vfsutil/vfsutil.go create mode 100644 vendor/github.com/shurcooL/httpfs/vfsutil/walk.go create mode 100644 vendor/github.com/shurcooL/vfsgen/.travis.yml create mode 100644 vendor/github.com/shurcooL/vfsgen/CONTRIBUTING.md create mode 100644 vendor/github.com/shurcooL/vfsgen/LICENSE create mode 100644 vendor/github.com/shurcooL/vfsgen/README.md create mode 100644 vendor/github.com/shurcooL/vfsgen/commentwriter.go create mode 100644 vendor/github.com/shurcooL/vfsgen/doc.go create mode 100644 vendor/github.com/shurcooL/vfsgen/generator.go create mode 100644 vendor/github.com/shurcooL/vfsgen/options.go create mode 100644 vendor/github.com/shurcooL/vfsgen/stringwriter.go diff --git a/Makefile b/Makefile index cf1a645805..f175b95ae1 100644 --- a/Makefile +++ b/Makefile @@ -97,10 +97,7 @@ vet: .PHONY: generate generate: - @hash go-bindata > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/jteeuwen/go-bindata/go-bindata; \ - fi - $(GO) generate $(PACKAGES) + GO111MODULE=on $(GO) generate $(PACKAGES) .PHONY: generate-swagger generate-swagger: diff --git a/go.mod b/go.mod index c6ebe16039..4f68a6b964 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,6 @@ require ( github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect - github.com/elazarl/go-bindata-assetfs v0.0.0-20151224045452-57eb5e1fc594 // indirect github.com/emirpasic/gods v1.12.0 github.com/etcd-io/bbolt v1.3.2 // indirect github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a @@ -44,7 +43,6 @@ require ( github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd // indirect github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect - github.com/go-macaron/bindata v0.0.0-20161222093048-85786f57eee3 github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab @@ -103,7 +101,9 @@ require ( github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect github.com/satori/go.uuid v1.2.0 github.com/sergi/go-diff v1.0.0 + github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc // indirect + github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d // indirect github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff // indirect github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect diff --git a/go.sum b/go.sum index 81b3aae5d4..7f042aecf1 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,6 @@ github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac h1:xrQJVwQCGqDvOO github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elazarl/go-bindata-assetfs v0.0.0-20151224045452-57eb5e1fc594 h1:McZ/pt/pP/XAbLMDQGzm/iQUwW6OXmKVbFtmH9klWmc= -github.com/elazarl/go-bindata-assetfs v0.0.0-20151224045452-57eb5e1fc594/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= @@ -97,8 +95,6 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04M github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-macaron/bindata v0.0.0-20161222093048-85786f57eee3 h1:n0H90987ZwasTc9r/RnuaU1G5ePfzLG6Bkc1cY3KqnY= -github.com/go-macaron/bindata v0.0.0-20161222093048-85786f57eee3/go.mod h1:NkmXhFuAlCOqgV5EWhU1DKLrgztCEIVXGmr2DZv/+sk= github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76uRMLLlGVyb0hiYbgX1FM5+ur81TJWzIw= github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM= github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw= @@ -282,8 +278,12 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA= +github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc h1:3wIrJvFb3Pf6B/2mDBnN1G5IfUVev4X5apadQlWOczE= github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= +github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -348,6 +348,7 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqY golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635 h1:2eB4G6bDQDeP69ZXbOKC00S2Kf6TIiRS+DzfKsKeQU0= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24= diff --git a/main.go b/main.go index 4d94d00aba..d8c37fee2f 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,9 @@ import ( _ "code.gitea.io/gitea/modules/markup/markdown" _ "code.gitea.io/gitea/modules/markup/orgmode" + // for embed + _ "github.com/shurcooL/vfsgen" + "github.com/urfave/cli" ) diff --git a/modules/options/main.go b/modules/options/main.go new file mode 100644 index 0000000000..0bc6c04e24 --- /dev/null +++ b/modules/options/main.go @@ -0,0 +1,23 @@ +// +build ignore + +package main + +import ( + "log" + "net/http" + + "github.com/shurcooL/vfsgen" +) + +func main() { + var fsTemplates http.FileSystem = http.Dir("../../options") + err := vfsgen.Generate(fsTemplates, vfsgen.Options{ + PackageName: "options", + BuildTags: "bindata", + VariableName: "Assets", + Filename: "bindata.go", + }) + if err != nil { + log.Fatal("%v", err) + } +} diff --git a/modules/options/options.go b/modules/options/options.go index 4f0c69b335..723dd54585 100644 --- a/modules/options/options.go +++ b/modules/options/options.go @@ -4,10 +4,8 @@ package options -//go:generate go-bindata -tags "bindata" -ignore "TRANSLATORS" -pkg "options" -o "bindata.go" ../../options/... +//go:generate go run -mod=vendor main.go //go:generate go fmt bindata.go -//go:generate sed -i.bak s/..\/..\/options\/// bindata.go -//go:generate rm -f bindata.go.bak type directorySet map[string][]string diff --git a/modules/options/static.go b/modules/options/static.go index 3301f45171..629901f740 100644 --- a/modules/options/static.go +++ b/modules/options/static.go @@ -41,7 +41,7 @@ func Dir(name string) ([]string, error) { result = append(result, files...) } - files, err := AssetDir(path.Join("..", "..", "options", name)) + files, err := AssetDir(name) if err != nil { return []string{}, fmt.Errorf("Failed to read embedded directory. %v", err) @@ -52,6 +52,24 @@ func Dir(name string) ([]string, error) { return directories.AddAndGet(name, result), nil } +func AssetDir(dirName string) ([]string, error) { + d, err := Assets.Open(dirName) + if err != nil { + return nil, err + } + defer d.Close() + + files, err := d.Readdir(-1) + if err != nil { + return nil, err + } + var results = make([]string, 0, len(files)) + for _, file := range files { + results = append(results, file.Name()) + } + return results, nil +} + // Locale reads the content of a specific locale from bindata or custom path. func Locale(name string) ([]byte, error) { return fileFromDir(path.Join("locale", name)) @@ -85,5 +103,11 @@ func fileFromDir(name string) ([]byte, error) { return ioutil.ReadFile(customPath) } - return Asset(name) + f, err := Assets.Open(name) + if err != nil { + return nil, err + } + defer f.Close() + + return ioutil.ReadAll(f) } diff --git a/modules/public/main.go b/modules/public/main.go new file mode 100644 index 0000000000..707dbe2b22 --- /dev/null +++ b/modules/public/main.go @@ -0,0 +1,23 @@ +// +build ignore + +package main + +import ( + "log" + "net/http" + + "github.com/shurcooL/vfsgen" +) + +func main() { + var fsPublic http.FileSystem = http.Dir("../../public") + err := vfsgen.Generate(fsPublic, vfsgen.Options{ + PackageName: "public", + BuildTags: "bindata", + VariableName: "Assets", + Filename: "bindata.go", + }) + if err != nil { + log.Fatal("%v", err) + } +} diff --git a/modules/public/public.go b/modules/public/public.go index 2e004536f8..8362b42576 100644 --- a/modules/public/public.go +++ b/modules/public/public.go @@ -17,10 +17,8 @@ import ( "gopkg.in/macaron.v1" ) -//go:generate go-bindata -tags "bindata" -ignore "\\.go|\\.less" -pkg "public" -o "bindata.go" ../../public/... +//go:generate go run -mod=vendor main.go //go:generate go fmt bindata.go -//go:generate sed -i.bak s/..\/..\/public\/// bindata.go -//go:generate rm -f bindata.go.bak // Options represents the available options to configure the macaron handler. type Options struct { diff --git a/modules/public/static.go b/modules/public/static.go index 10e32dbd10..054b9a806c 100644 --- a/modules/public/static.go +++ b/modules/public/static.go @@ -7,19 +7,12 @@ package public import ( - "github.com/go-macaron/bindata" "gopkg.in/macaron.v1" ) // Static implements the macaron static handler for serving assets. func Static(opts *Options) macaron.Handler { - opts.FileSystem = bindata.Static(bindata.Options{ - Asset: Asset, - AssetDir: AssetDir, - AssetInfo: AssetInfo, - AssetNames: AssetNames, - Prefix: "", - }) + opts.FileSystem = Assets // we don't need to pass the directory, because the directory var is only // used when in the options there is no FileSystem. return opts.staticHandler("") diff --git a/modules/templates/main.go b/modules/templates/main.go new file mode 100644 index 0000000000..4460f58cbf --- /dev/null +++ b/modules/templates/main.go @@ -0,0 +1,23 @@ +// +build ignore + +package main + +import ( + "log" + "net/http" + + "github.com/shurcooL/vfsgen" +) + +func main() { + var fsTemplates http.FileSystem = http.Dir("../../templates") + err := vfsgen.Generate(fsTemplates, vfsgen.Options{ + PackageName: "templates", + BuildTags: "bindata", + VariableName: "Assets", + Filename: "bindata.go", + }) + if err != nil { + log.Fatal("%v", err) + } +} diff --git a/modules/templates/static.go b/modules/templates/static.go index e69e1cae48..3aabe17e4f 100644 --- a/modules/templates/static.go +++ b/modules/templates/static.go @@ -203,3 +203,21 @@ func Mailer() *template.Template { return templates } + +func Asset(name string) ([]byte, error) { + f, err := Assets.Open("/" + name) + if err != nil { + return nil, err + } + defer f.Close() + return ioutil.ReadAll(f) +} + +func AssetNames() []string { + realFS := Assets.(vfsgen۰FS) + var results = make([]string, 0, len(realFS)) + for k := range realFS { + results = append(results, k[1:]) + } + return results +} diff --git a/modules/templates/templates.go b/modules/templates/templates.go index 91c8db5228..e7fe3b2bfb 100644 --- a/modules/templates/templates.go +++ b/modules/templates/templates.go @@ -4,7 +4,5 @@ package templates -//go:generate go-bindata -tags "bindata" -ignore "\\.go" -pkg "templates" -o "bindata.go" ../../templates/... +//go:generate go run -mod=vendor main.go //go:generate go fmt bindata.go -//go:generate sed -i.bak s/..\/..\/templates\/// bindata.go -//go:generate rm -f bindata.go.bak diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index aab1c2b05c..d1ea4689cf 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -65,7 +65,6 @@ parts: build: | export PATH=$SNAPCRAFT_PART_INSTALL/../go/bin/:$SNAPCRAFT_PART_INSTALL/../../go/install/bin:$PATH export GOPATH=$SNAPCRAFT_PART_INSTALL/../go - go get -u github.com/jteeuwen/go-bindata/... cd $GOPATH/src/code.gitea.io/gitea TAGS="bindata sqlite sqlite_unlock_notify pam cert" make generate build install: | diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE b/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE deleted file mode 100644 index 5782c72690..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2014, Elazar Leibovich -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/README.md b/vendor/github.com/elazarl/go-bindata-assetfs/README.md deleted file mode 100644 index 27ee48f09d..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# go-bindata-assetfs - -Serve embedded files from [jteeuwen/go-bindata](https://github.com/jteeuwen/go-bindata) with `net/http`. - -[GoDoc](http://godoc.org/github.com/elazarl/go-bindata-assetfs) - -### Installation - -Install with - - $ go get github.com/jteeuwen/go-bindata/... - $ go get github.com/elazarl/go-bindata-assetfs/... - -### Creating embedded data - -Usage is identical to [jteeuwen/go-bindata](https://github.com/jteeuwen/go-bindata) usage, -instead of running `go-bindata` run `go-bindata-assetfs`. - -The tool will create a `bindata_assetfs.go` file, which contains the embedded data. - -A typical use case is - - $ go-bindata-assetfs data/... - -### Using assetFS in your code - -The generated file provides an `assetFS()` function that returns a `http.Filesystem` -wrapping the embedded files. What you usually want to do is: - - http.Handle("/", http.FileServer(assetFS())) - -This would run an HTTP server serving the embedded files. - -## Without running binary tool - -You can always just run the `go-bindata` tool, and then - -use - - import "github.com/elazarl/go-bindata-assetfs" - ... - http.Handle("/", - http.FileServer( - &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: "data"})) - -to serve files embedded from the `data` directory. diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go b/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go deleted file mode 100644 index 9397e58d52..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go +++ /dev/null @@ -1,158 +0,0 @@ -package assetfs - -import ( - "bytes" - "errors" - "io" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "time" -) - -var ( - defaultFileTimestamp = time.Now() -) - -// FakeFile implements os.FileInfo interface for a given path and size -type FakeFile struct { - // Path is the path of this file - Path string - // Dir marks of the path is a directory - Dir bool - // Len is the length of the fake file, zero if it is a directory - Len int64 - // Timestamp is the ModTime of this file - Timestamp time.Time -} - -func (f *FakeFile) Name() string { - _, name := filepath.Split(f.Path) - return name -} - -func (f *FakeFile) Mode() os.FileMode { - mode := os.FileMode(0644) - if f.Dir { - return mode | os.ModeDir - } - return mode -} - -func (f *FakeFile) ModTime() time.Time { - return f.Timestamp -} - -func (f *FakeFile) Size() int64 { - return f.Len -} - -func (f *FakeFile) IsDir() bool { - return f.Mode().IsDir() -} - -func (f *FakeFile) Sys() interface{} { - return nil -} - -// AssetFile implements http.File interface for a no-directory file with content -type AssetFile struct { - *bytes.Reader - io.Closer - FakeFile -} - -func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile { - if timestamp.IsZero() { - timestamp = defaultFileTimestamp - } - return &AssetFile{ - bytes.NewReader(content), - ioutil.NopCloser(nil), - FakeFile{name, false, int64(len(content)), timestamp}} -} - -func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) { - return nil, errors.New("not a directory") -} - -func (f *AssetFile) Size() int64 { - return f.FakeFile.Size() -} - -func (f *AssetFile) Stat() (os.FileInfo, error) { - return f, nil -} - -// AssetDirectory implements http.File interface for a directory -type AssetDirectory struct { - AssetFile - ChildrenRead int - Children []os.FileInfo -} - -func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory { - fileinfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - _, err := fs.AssetDir(filepath.Join(name, child)) - fileinfos = append(fileinfos, &FakeFile{child, err == nil, 0, time.Time{}}) - } - return &AssetDirectory{ - AssetFile{ - bytes.NewReader(nil), - ioutil.NopCloser(nil), - FakeFile{name, true, 0, time.Time{}}, - }, - 0, - fileinfos} -} - -func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) { - if count <= 0 { - return f.Children, nil - } - if f.ChildrenRead+count > len(f.Children) { - count = len(f.Children) - f.ChildrenRead - } - rv := f.Children[f.ChildrenRead : f.ChildrenRead+count] - f.ChildrenRead += count - return rv, nil -} - -func (f *AssetDirectory) Stat() (os.FileInfo, error) { - return f, nil -} - -// AssetFS implements http.FileSystem, allowing -// embedded files to be served from net/http package. -type AssetFS struct { - // Asset should return content of file in path if exists - Asset func(path string) ([]byte, error) - // AssetDir should return list of files in the path - AssetDir func(path string) ([]string, error) - // AssetInfo should return the info of file in path if exists - AssetInfo func(path string) (os.FileInfo, error) - // Prefix would be prepended to http requests - Prefix string -} - -func (fs *AssetFS) Open(name string) (http.File, error) { - name = path.Join(fs.Prefix, name) - if len(name) > 0 && name[0] == '/' { - name = name[1:] - } - if b, err := fs.Asset(name); err == nil { - timestamp := defaultFileTimestamp - if info, err := fs.AssetInfo(name); err == nil { - timestamp = info.ModTime() - } - return NewAssetFile(name, b, timestamp), nil - } - if children, err := fs.AssetDir(name); err == nil { - return NewAssetDirectory(name, children, fs), nil - } else { - return nil, err - } -} diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/doc.go b/vendor/github.com/elazarl/go-bindata-assetfs/doc.go deleted file mode 100644 index a664249f34..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/doc.go +++ /dev/null @@ -1,13 +0,0 @@ -// assetfs allows packages to serve static content embedded -// with the go-bindata tool with the standard net/http package. -// -// See https://github.com/jteeuwen/go-bindata for more information -// about embedding binary data with go-bindata. -// -// Usage example, after running -// $ go-bindata data/... -// use: -// http.Handle("/", -// http.FileServer( -// &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "data"})) -package assetfs diff --git a/vendor/github.com/go-macaron/bindata/.travis.yml b/vendor/github.com/go-macaron/bindata/.travis.yml deleted file mode 100644 index 2774fb35d5..0000000000 --- a/vendor/github.com/go-macaron/bindata/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -sudo: false -language: go - -go: - - 1.3 - - 1.4 - - 1.5 - - tip - -script: go test -v -cover -race - -notifications: - email: - - u@gogs.io diff --git a/vendor/github.com/go-macaron/bindata/LICENSE b/vendor/github.com/go-macaron/bindata/LICENSE deleted file mode 100644 index 37ec93a14f..0000000000 --- a/vendor/github.com/go-macaron/bindata/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/go-macaron/bindata/README.md b/vendor/github.com/go-macaron/bindata/README.md deleted file mode 100644 index fd32bf3fb5..0000000000 --- a/vendor/github.com/go-macaron/bindata/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# bindata [![Build Status](https://travis-ci.org/go-macaron/bindata.svg?branch=master)](https://travis-ci.org/go-macaron/bindata) [![](http://gocover.io/_badge/github.com/go-macaron/bindata)](http://gocover.io/github.com/go-macaron/bindata) - -Package bindata is a helper module that allows to use in-memory static and template files for Macaron via [go-bindata](https://github.com/jteeuwen/go-bindata). - -### Installation - - go get github.com/go-macaron/bindata - -## Getting Help - -- [API Reference](https://gowalker.org/github.com/go-macaron/bindata) -- [Documentation](http://go-macaron.com/docs/middlewares/bindata) - -## License - -This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text. \ No newline at end of file diff --git a/vendor/github.com/go-macaron/bindata/bindata.go b/vendor/github.com/go-macaron/bindata/bindata.go deleted file mode 100644 index 637489e1cd..0000000000 --- a/vendor/github.com/go-macaron/bindata/bindata.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2014 Dustin Webber -// Copyright 2015 The Macaron 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 bindata is a helper module that allows to use in-memory static and template files for Macaron. -package bindata - -import ( - "bytes" - "fmt" - "io" - "os" - - "github.com/elazarl/go-bindata-assetfs" - "gopkg.in/macaron.v1" -) - -const _VERSION = "0.1.1" - -func Version() string { - return _VERSION -} - -type ( - templateFileSystem struct { - files []macaron.TemplateFile - } - - templateFile struct { - name string - data []byte - ext string - } - - Options struct { - // Asset should return content of file in path if exists - Asset func(path string) ([]byte, error) - // AssetDir should return list of files in the path - AssetDir func(path string) ([]string, error) - // AssetInfo should return the info of file in path if exists - AssetInfo func(path string) (os.FileInfo, error) - // AssetNames should return list of all asset names - AssetNames func() []string - // Prefix would be prepended to http requests - Prefix string - } -) - -func Static(opt Options) *assetfs.AssetFS { - fs := &assetfs.AssetFS{ - Asset: opt.Asset, - AssetDir: opt.AssetDir, - AssetInfo: opt.AssetInfo, - Prefix: opt.Prefix, - } - - return fs -} - -func (templates templateFileSystem) ListFiles() []macaron.TemplateFile { - return templates.files -} - -func (templates templateFileSystem) Get(name string) (io.Reader, error) { - for i := range templates.files { - if templates.files[i].Name()+templates.files[i].Ext() == name { - return bytes.NewReader(templates.files[i].Data()), nil - } - } - return nil, fmt.Errorf("file '%s' not found", name) -} - -func (f *templateFile) Name() string { - return f.name -} - -func (f *templateFile) Data() []byte { - return f.data -} - -func (f *templateFile) Ext() string { - return f.ext -} - -func Templates(opt Options) templateFileSystem { - fs := templateFileSystem{} - fs.files = make([]macaron.TemplateFile, 0, 10) - - list := opt.AssetNames() - - for _, key := range list { - ext := macaron.GetExt(key) - - data, err := opt.Asset(key) - - if err != nil { - continue - } - - name := (key[0 : len(key)-len(ext)]) - - fs.files = append(fs.files, &templateFile{name, data, ext}) - } - - return fs -} diff --git a/vendor/github.com/shurcooL/httpfs/LICENSE b/vendor/github.com/shurcooL/httpfs/LICENSE new file mode 100644 index 0000000000..c35c17af98 --- /dev/null +++ b/vendor/github.com/shurcooL/httpfs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015 Dmitri Shuralyov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/shurcooL/httpfs/vfsutil/file.go b/vendor/github.com/shurcooL/httpfs/vfsutil/file.go new file mode 100644 index 0000000000..4cb0dadadb --- /dev/null +++ b/vendor/github.com/shurcooL/httpfs/vfsutil/file.go @@ -0,0 +1,21 @@ +package vfsutil + +import ( + "net/http" + "os" +) + +// File implements http.FileSystem using the native file system restricted to a +// specific file served at root. +// +// While the FileSystem.Open method takes '/'-separated paths, a File's string +// value is a filename on the native file system, not a URL, so it is separated +// by filepath.Separator, which isn't necessarily '/'. +type File string + +func (f File) Open(name string) (http.File, error) { + if name != "/" { + return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist} + } + return os.Open(string(f)) +} diff --git a/vendor/github.com/shurcooL/httpfs/vfsutil/vfsutil.go b/vendor/github.com/shurcooL/httpfs/vfsutil/vfsutil.go new file mode 100644 index 0000000000..df071d112c --- /dev/null +++ b/vendor/github.com/shurcooL/httpfs/vfsutil/vfsutil.go @@ -0,0 +1,39 @@ +// Package vfsutil implements some I/O utility functions for http.FileSystem. +package vfsutil + +import ( + "io/ioutil" + "net/http" + "os" +) + +// ReadDir reads the contents of the directory associated with file and +// returns a slice of FileInfo values in directory order. +func ReadDir(fs http.FileSystem, name string) ([]os.FileInfo, error) { + f, err := fs.Open(name) + if err != nil { + return nil, err + } + defer f.Close() + return f.Readdir(0) +} + +// Stat returns the FileInfo structure describing file. +func Stat(fs http.FileSystem, name string) (os.FileInfo, error) { + f, err := fs.Open(name) + if err != nil { + return nil, err + } + defer f.Close() + return f.Stat() +} + +// ReadFile reads the file named by path from fs and returns the contents. +func ReadFile(fs http.FileSystem, path string) ([]byte, error) { + rc, err := fs.Open(path) + if err != nil { + return nil, err + } + defer rc.Close() + return ioutil.ReadAll(rc) +} diff --git a/vendor/github.com/shurcooL/httpfs/vfsutil/walk.go b/vendor/github.com/shurcooL/httpfs/vfsutil/walk.go new file mode 100644 index 0000000000..f256bbec26 --- /dev/null +++ b/vendor/github.com/shurcooL/httpfs/vfsutil/walk.go @@ -0,0 +1,146 @@ +package vfsutil + +import ( + "io" + "net/http" + "os" + pathpkg "path" + "path/filepath" + "sort" +) + +// Walk walks the filesystem rooted at root, calling walkFn for each file or +// directory in the filesystem, including root. All errors that arise visiting files +// and directories are filtered by walkFn. The files are walked in lexical +// order. +func Walk(fs http.FileSystem, root string, walkFn filepath.WalkFunc) error { + info, err := Stat(fs, root) + if err != nil { + return walkFn(root, nil, err) + } + return walk(fs, root, info, walkFn) +} + +// readDirNames reads the directory named by dirname and returns +// a sorted list of directory entries. +func readDirNames(fs http.FileSystem, dirname string) ([]string, error) { + fis, err := ReadDir(fs, dirname) + if err != nil { + return nil, err + } + names := make([]string, len(fis)) + for i := range fis { + names[i] = fis[i].Name() + } + sort.Strings(names) + return names, nil +} + +// walk recursively descends path, calling walkFn. +func walk(fs http.FileSystem, path string, info os.FileInfo, walkFn filepath.WalkFunc) error { + err := walkFn(path, info, nil) + if err != nil { + if info.IsDir() && err == filepath.SkipDir { + return nil + } + return err + } + + if !info.IsDir() { + return nil + } + + names, err := readDirNames(fs, path) + if err != nil { + return walkFn(path, info, err) + } + + for _, name := range names { + filename := pathpkg.Join(path, name) + fileInfo, err := Stat(fs, filename) + if err != nil { + if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { + return err + } + } else { + err = walk(fs, filename, fileInfo, walkFn) + if err != nil { + if !fileInfo.IsDir() || err != filepath.SkipDir { + return err + } + } + } + } + return nil +} + +// WalkFilesFunc is the type of the function called for each file or directory visited by WalkFiles. +// It's like filepath.WalkFunc, except it provides an additional ReadSeeker parameter for file being visited. +type WalkFilesFunc func(path string, info os.FileInfo, rs io.ReadSeeker, err error) error + +// WalkFiles walks the filesystem rooted at root, calling walkFn for each file or +// directory in the filesystem, including root. In addition to FileInfo, it passes an +// ReadSeeker to walkFn for each file it visits. +func WalkFiles(fs http.FileSystem, root string, walkFn WalkFilesFunc) error { + file, info, err := openStat(fs, root) + if err != nil { + return walkFn(root, nil, nil, err) + } + return walkFiles(fs, root, info, file, walkFn) +} + +// walkFiles recursively descends path, calling walkFn. +// It closes the input file after it's done with it, so the caller shouldn't. +func walkFiles(fs http.FileSystem, path string, info os.FileInfo, file http.File, walkFn WalkFilesFunc) error { + err := walkFn(path, info, file, nil) + file.Close() + if err != nil { + if info.IsDir() && err == filepath.SkipDir { + return nil + } + return err + } + + if !info.IsDir() { + return nil + } + + names, err := readDirNames(fs, path) + if err != nil { + return walkFn(path, info, nil, err) + } + + for _, name := range names { + filename := pathpkg.Join(path, name) + file, fileInfo, err := openStat(fs, filename) + if err != nil { + if err := walkFn(filename, nil, nil, err); err != nil && err != filepath.SkipDir { + return err + } + } else { + err = walkFiles(fs, filename, fileInfo, file, walkFn) + // file is closed by walkFiles, so we don't need to close it here. + if err != nil { + if !fileInfo.IsDir() || err != filepath.SkipDir { + return err + } + } + } + } + return nil +} + +// openStat performs Open and Stat and returns results, or first error encountered. +// The caller is responsible for closing the returned file when done. +func openStat(fs http.FileSystem, name string) (http.File, os.FileInfo, error) { + f, err := fs.Open(name) + if err != nil { + return nil, nil, err + } + fi, err := f.Stat() + if err != nil { + f.Close() + return nil, nil, err + } + return f, fi, nil +} diff --git a/vendor/github.com/shurcooL/vfsgen/.travis.yml b/vendor/github.com/shurcooL/vfsgen/.travis.yml new file mode 100644 index 0000000000..93b1fcdb31 --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/.travis.yml @@ -0,0 +1,16 @@ +sudo: false +language: go +go: + - 1.x + - master +matrix: + allow_failures: + - go: master + fast_finish: true +install: + - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d -s .) + - go tool vet . + - go test -v -race ./... diff --git a/vendor/github.com/shurcooL/vfsgen/CONTRIBUTING.md b/vendor/github.com/shurcooL/vfsgen/CONTRIBUTING.md new file mode 100644 index 0000000000..6127ddce82 --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/CONTRIBUTING.md @@ -0,0 +1,10 @@ +Contributing +============ + +vfsgen is open source, thanks for considering contributing! + +Please note that vfsgen aims to be simple and minimalistic, with as little to configure as possible. If you'd like to remove or simplify code (while having tests continue to pass), fix bugs, or improve code (e.g., add missing error checking, etc.), PRs and issues are welcome. + +However, if you'd like to add new functionality that increases complexity or scope, please make an issue and discuss your proposal first. I'm unlikely to accept such changes outright. It might be that your request is already a part of other similar packages, or it might fit in their scope better. See [Comparison and Alternatives](https://github.com/shurcooL/vfsgen/tree/README-alternatives-and-comparison-section#comparison) sections. + +Thank you! diff --git a/vendor/github.com/shurcooL/vfsgen/LICENSE b/vendor/github.com/shurcooL/vfsgen/LICENSE new file mode 100644 index 0000000000..c35c17af98 --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015 Dmitri Shuralyov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/shurcooL/vfsgen/README.md b/vendor/github.com/shurcooL/vfsgen/README.md new file mode 100644 index 0000000000..659a0a0344 --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/README.md @@ -0,0 +1,201 @@ +vfsgen +====== + +[![Build Status](https://travis-ci.org/shurcooL/vfsgen.svg?branch=master)](https://travis-ci.org/shurcooL/vfsgen) [![GoDoc](https://godoc.org/github.com/shurcooL/vfsgen?status.svg)](https://godoc.org/github.com/shurcooL/vfsgen) + +Package vfsgen takes an http.FileSystem (likely at `go generate` time) and +generates Go code that statically implements the provided http.FileSystem. + +Features: + +- Efficient generated code without unneccessary overhead. + +- Uses gzip compression internally (selectively, only for files that compress well). + +- Enables direct access to internal gzip compressed bytes via an optional interface. + +- Outputs `gofmt`ed Go code. + +Installation +------------ + +```bash +go get -u github.com/shurcooL/vfsgen +``` + +Usage +----- + +Package `vfsgen` is a Go code generator library. It has a `Generate` function that takes an input filesystem (as a [`http.FileSystem`](https://godoc.org/net/http#FileSystem) type), and generates a Go code file that statically implements the contents of the input filesystem. + +For example, we can use [`http.Dir`](https://godoc.org/net/http#Dir) as a `http.FileSystem` implementation that uses the contents of the `/path/to/assets` directory: + +```Go +var fs http.FileSystem = http.Dir("/path/to/assets") +``` + +Now, when you execute the following code: + +```Go +err := vfsgen.Generate(fs, vfsgen.Options{}) +if err != nil { + log.Fatalln(err) +} +``` + +An assets_vfsdata.go file will be generated in the current directory: + +```Go +// Code generated by vfsgen; DO NOT EDIT. + +package main + +import ... + +// assets statically implements the virtual filesystem provided to vfsgen.Generate. +var assets http.FileSystem = ... +``` + +Then, in your program, you can use `assets` as any other [`http.FileSystem`](https://godoc.org/net/http#FileSystem), for example: + +```Go +file, err := assets.Open("/some/file.txt") +if err != nil { + return err +} +defer file.Close() +``` + +```Go +http.Handle("/assets/", http.FileServer(assets)) +``` + +`vfsgen` can be more useful when combined with build tags and go generate directives. This is described below. + +### `go generate` Usage + +vfsgen is great to use with go generate directives. The code invoking `vfsgen.Generate` can go in an assets_generate.go file, which can then be invoked via "//go:generate go run assets_generate.go". The input virtual filesystem can read directly from disk, or it can be more involved. + +By using build tags, you can create a development mode where assets are loaded directly from disk via `http.Dir`, but then statically implemented for final releases. + +For example, suppose your source filesystem is defined in a package with import path "example.com/project/data" as: + +```Go +// +build dev + +package data + +import "net/http" + +// Assets contains project assets. +var Assets http.FileSystem = http.Dir("assets") +``` + +When built with the "dev" build tag, accessing `data.Assets` will read from disk directly via `http.Dir`. + +A generate helper file assets_generate.go can be invoked via "//go:generate go run -tags=dev assets_generate.go" directive: + +```Go +// +build ignore + +package main + +import ( + "log" + + "example.com/project/data" + "github.com/shurcooL/vfsgen" +) + +func main() { + err := vfsgen.Generate(data.Assets, vfsgen.Options{ + PackageName: "data", + BuildTags: "!dev", + VariableName: "Assets", + }) + if err != nil { + log.Fatalln(err) + } +} +``` + +Note that "dev" build tag is used to access the source filesystem, and the output file will contain "!dev" build tag. That way, the statically implemented version will be used during normal builds and `go get`, when custom builds tags are not specified. + +### `vfsgendev` Usage + +`vfsgendev` is a binary that can be used to replace the need for the assets_generate.go file. + +Make sure it's installed and available in your PATH. + +```bash +go get -u github.com/shurcooL/vfsgen/cmd/vfsgendev +``` + +Then the "//go:generate go run -tags=dev assets_generate.go" directive can be replaced with: + +``` +//go:generate vfsgendev -source="example.com/project/data".Assets +``` + +vfsgendev accesses the source variable using "dev" build tag, and generates an output file with "!dev" build tag. + +### Additional Embedded Information + +All compressed files implement [`httpgzip.GzipByter` interface](https://godoc.org/github.com/shurcooL/httpgzip#GzipByter) for efficient direct access to the internal compressed bytes: + +```Go +// GzipByter is implemented by compressed files for +// efficient direct access to the internal compressed bytes. +type GzipByter interface { + // GzipBytes returns gzip compressed contents of the file. + GzipBytes() []byte +} +``` + +Files that have been determined to not be worth gzip compressing (their compressed size is larger than original) implement [`httpgzip.NotWorthGzipCompressing` interface](https://godoc.org/github.com/shurcooL/httpgzip#NotWorthGzipCompressing): + +```Go +// NotWorthGzipCompressing is implemented by files that were determined +// not to be worth gzip compressing (the file size did not decrease as a result). +type NotWorthGzipCompressing interface { + // NotWorthGzipCompressing is a noop. It's implemented in order to indicate + // the file is not worth gzip compressing. + NotWorthGzipCompressing() +} +``` + +Comparison +---------- + +vfsgen aims to be conceptually simple to use. The [`http.FileSystem`](https://godoc.org/net/http#FileSystem) abstraction is central to vfsgen. It's used as both input for code generation, and as output in the generated code. + +That enables great flexibility through orthogonality, since helpers and wrappers can operate on `http.FileSystem` without knowing about vfsgen. If you want, you can perform pre-processing, minifying assets, merging folders, filtering out files and otherwise modifying input via generic `http.FileSystem` middleware. + +It avoids unneccessary overhead by merging what was previously done with two distinct packages into a single package. + +It strives to be the best in its class in terms of code quality and efficiency of generated code. However, if your use goals are different, there are other similar packages that may fit your needs better. + +### Alternatives + +- [`go-bindata`](https://github.com/jteeuwen/go-bindata) - Reads from disk, generates Go code that provides access to data via a [custom API](https://github.com/jteeuwen/go-bindata#accessing-an-asset). +- [`go-bindata-assetfs`](https://github.com/elazarl/go-bindata-assetfs) - Takes output of go-bindata and provides a wrapper that implements `http.FileSystem` interface (the same as what vfsgen outputs directly). +- [`becky`](https://github.com/tv42/becky) - Embeds assets as string literals in Go source. +- [`statik`](https://github.com/rakyll/statik) - Embeds a directory of static files to be accessed via `http.FileSystem` interface (sounds very similar to vfsgen); implementation sourced from [camlistore](https://camlistore.org). +- [`go.rice`](https://github.com/GeertJohan/go.rice) - Makes working with resources such as HTML, JS, CSS, images and templates very easy. +- [`esc`](https://github.com/mjibson/esc) - Embeds files into Go programs and provides `http.FileSystem` interfaces to them. +- [`staticfiles`](https://github.com/bouk/staticfiles) - Allows you to embed a directory of files into your Go binary. +- [`togo`](https://github.com/flazz/togo) - Generates a Go source file with a `[]byte` var containing the given file's contents. +- [`fileb0x`](https://github.com/UnnoTed/fileb0x) - Simple customizable tool to embed files in Go. +- [`embedfiles`](https://github.com/leighmcculloch/embedfiles) - Simple tool for embedding files in Go code as a map. +- [`packr`](https://github.com/gobuffalo/packr) - Simple solution for bundling static assets inside of Go binaries. +- [`rsrc`](https://github.com/akavel/rsrc) - Tool for embedding .ico & manifest resources in Go programs for Windows. + +Attribution +----------- + +This package was originally based on the excellent work by [@jteeuwen](https://github.com/jteeuwen) on [`go-bindata`](https://github.com/jteeuwen/go-bindata) and [@elazarl](https://github.com/elazarl) on [`go-bindata-assetfs`](https://github.com/elazarl/go-bindata-assetfs). + +License +------- + +- [MIT License](LICENSE) diff --git a/vendor/github.com/shurcooL/vfsgen/commentwriter.go b/vendor/github.com/shurcooL/vfsgen/commentwriter.go new file mode 100644 index 0000000000..b6847f52b0 --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/commentwriter.go @@ -0,0 +1,45 @@ +package vfsgen + +import "io" + +// commentWriter writes a Go comment to the underlying io.Writer, +// using line comment form (//). +type commentWriter struct { + W io.Writer + wroteSlashes bool // Wrote "//" at the beginning of the current line. +} + +func (c *commentWriter) Write(p []byte) (int, error) { + var n int + for i, b := range p { + if !c.wroteSlashes { + s := "//" + if b != '\n' { + s = "// " + } + if _, err := io.WriteString(c.W, s); err != nil { + return n, err + } + c.wroteSlashes = true + } + n0, err := c.W.Write(p[i : i+1]) + n += n0 + if err != nil { + return n, err + } + if b == '\n' { + c.wroteSlashes = false + } + } + return len(p), nil +} + +func (c *commentWriter) Close() error { + if !c.wroteSlashes { + if _, err := io.WriteString(c.W, "//"); err != nil { + return err + } + c.wroteSlashes = true + } + return nil +} diff --git a/vendor/github.com/shurcooL/vfsgen/doc.go b/vendor/github.com/shurcooL/vfsgen/doc.go new file mode 100644 index 0000000000..46f28504e3 --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/doc.go @@ -0,0 +1,15 @@ +/* +Package vfsgen takes an http.FileSystem (likely at `go generate` time) and +generates Go code that statically implements the provided http.FileSystem. + +Features: + +- Efficient generated code without unneccessary overhead. + +- Uses gzip compression internally (selectively, only for files that compress well). + +- Enables direct access to internal gzip compressed bytes via an optional interface. + +- Outputs `gofmt`ed Go code. +*/ +package vfsgen diff --git a/vendor/github.com/shurcooL/vfsgen/generator.go b/vendor/github.com/shurcooL/vfsgen/generator.go new file mode 100644 index 0000000000..5782693ebb --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/generator.go @@ -0,0 +1,485 @@ +package vfsgen + +import ( + "bytes" + "compress/gzip" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + pathpkg "path" + "sort" + "strconv" + "text/template" + "time" + + "github.com/shurcooL/httpfs/vfsutil" +) + +// Generate Go code that statically implements input filesystem, +// write the output to a file specified in opt. +func Generate(input http.FileSystem, opt Options) error { + opt.fillMissing() + + // Use an in-memory buffer to generate the entire output. + buf := new(bytes.Buffer) + + err := t.ExecuteTemplate(buf, "Header", opt) + if err != nil { + return err + } + + var toc toc + err = findAndWriteFiles(buf, input, &toc) + if err != nil { + return err + } + + err = t.ExecuteTemplate(buf, "DirEntries", toc.dirs) + if err != nil { + return err + } + + err = t.ExecuteTemplate(buf, "Trailer", toc) + if err != nil { + return err + } + + // Write output file (all at once). + fmt.Println("writing", opt.Filename) + err = ioutil.WriteFile(opt.Filename, buf.Bytes(), 0644) + return err +} + +type toc struct { + dirs []*dirInfo + + HasCompressedFile bool // There's at least one compressedFile. + HasFile bool // There's at least one uncompressed file. +} + +// fileInfo is a definition of a file. +type fileInfo struct { + Path string + Name string + ModTime time.Time + UncompressedSize int64 +} + +// dirInfo is a definition of a directory. +type dirInfo struct { + Path string + Name string + ModTime time.Time + Entries []string +} + +// findAndWriteFiles recursively finds all the file paths in the given directory tree. +// They are added to the given map as keys. Values will be safe function names +// for each file, which will be used when generating the output code. +func findAndWriteFiles(buf *bytes.Buffer, fs http.FileSystem, toc *toc) error { + walkFn := func(path string, fi os.FileInfo, r io.ReadSeeker, err error) error { + if err != nil { + // Consider all errors reading the input filesystem as fatal. + return err + } + + switch fi.IsDir() { + case false: + file := &fileInfo{ + Path: path, + Name: pathpkg.Base(path), + ModTime: fi.ModTime().UTC(), + UncompressedSize: fi.Size(), + } + + marker := buf.Len() + + // Write CompressedFileInfo. + err = writeCompressedFileInfo(buf, file, r) + switch err { + default: + return err + case nil: + toc.HasCompressedFile = true + // If compressed file is not smaller than original, revert and write original file. + case errCompressedNotSmaller: + _, err = r.Seek(0, io.SeekStart) + if err != nil { + return err + } + + buf.Truncate(marker) + + // Write FileInfo. + err = writeFileInfo(buf, file, r) + if err != nil { + return err + } + toc.HasFile = true + } + case true: + entries, err := readDirPaths(fs, path) + if err != nil { + return err + } + + dir := &dirInfo{ + Path: path, + Name: pathpkg.Base(path), + ModTime: fi.ModTime().UTC(), + Entries: entries, + } + + toc.dirs = append(toc.dirs, dir) + + // Write DirInfo. + err = t.ExecuteTemplate(buf, "DirInfo", dir) + if err != nil { + return err + } + } + + return nil + } + + err := vfsutil.WalkFiles(fs, "/", walkFn) + return err +} + +// readDirPaths reads the directory named by dirname and returns +// a sorted list of directory paths. +func readDirPaths(fs http.FileSystem, dirname string) ([]string, error) { + fis, err := vfsutil.ReadDir(fs, dirname) + if err != nil { + return nil, err + } + paths := make([]string, len(fis)) + for i := range fis { + paths[i] = pathpkg.Join(dirname, fis[i].Name()) + } + sort.Strings(paths) + return paths, nil +} + +// writeCompressedFileInfo writes CompressedFileInfo. +// It returns errCompressedNotSmaller if compressed file is not smaller than original. +func writeCompressedFileInfo(w io.Writer, file *fileInfo, r io.Reader) error { + err := t.ExecuteTemplate(w, "CompressedFileInfo-Before", file) + if err != nil { + return err + } + sw := &stringWriter{Writer: w} + gw := gzip.NewWriter(sw) + _, err = io.Copy(gw, r) + if err != nil { + return err + } + err = gw.Close() + if err != nil { + return err + } + if sw.N >= file.UncompressedSize { + return errCompressedNotSmaller + } + err = t.ExecuteTemplate(w, "CompressedFileInfo-After", file) + return err +} + +var errCompressedNotSmaller = errors.New("compressed file is not smaller than original") + +// Write FileInfo. +func writeFileInfo(w io.Writer, file *fileInfo, r io.Reader) error { + err := t.ExecuteTemplate(w, "FileInfo-Before", file) + if err != nil { + return err + } + sw := &stringWriter{Writer: w} + _, err = io.Copy(sw, r) + if err != nil { + return err + } + err = t.ExecuteTemplate(w, "FileInfo-After", file) + return err +} + +var t = template.Must(template.New("").Funcs(template.FuncMap{ + "quote": strconv.Quote, + "comment": func(s string) (string, error) { + var buf bytes.Buffer + cw := &commentWriter{W: &buf} + _, err := io.WriteString(cw, s) + if err != nil { + return "", err + } + err = cw.Close() + return buf.String(), err + }, +}).Parse(`{{define "Header"}}// Code generated by vfsgen; DO NOT EDIT. + +{{with .BuildTags}}// +build {{.}} + +{{end}}package {{.PackageName}} + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + pathpkg "path" + "time" +) + +{{comment .VariableComment}} +var {{.VariableName}} = func() http.FileSystem { + fs := vfsgen۰FS{ +{{end}} + + + +{{define "CompressedFileInfo-Before"}} {{quote .Path}}: &vfsgen۰CompressedFileInfo{ + name: {{quote .Name}}, + modTime: {{template "Time" .ModTime}}, + uncompressedSize: {{.UncompressedSize}}, +{{/* This blank line separating compressedContent is neccessary to prevent potential gofmt issues. See issue #19. */}} + compressedContent: []byte("{{end}}{{define "CompressedFileInfo-After"}}"), + }, +{{end}} + + + +{{define "FileInfo-Before"}} {{quote .Path}}: &vfsgen۰FileInfo{ + name: {{quote .Name}}, + modTime: {{template "Time" .ModTime}}, + content: []byte("{{end}}{{define "FileInfo-After"}}"), + }, +{{end}} + + + +{{define "DirInfo"}} {{quote .Path}}: &vfsgen۰DirInfo{ + name: {{quote .Name}}, + modTime: {{template "Time" .ModTime}}, + }, +{{end}} + + + +{{define "DirEntries"}} } +{{range .}}{{if .Entries}} fs[{{quote .Path}}].(*vfsgen۰DirInfo).entries = []os.FileInfo{{"{"}}{{range .Entries}} + fs[{{quote .}}].(os.FileInfo),{{end}} + } +{{end}}{{end}} + return fs +}() +{{end}} + + + +{{define "Trailer"}} +type vfsgen۰FS map[string]interface{} + +func (fs vfsgen۰FS) Open(path string) (http.File, error) { + path = pathpkg.Clean("/" + path) + f, ok := fs[path] + if !ok { + return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist} + } + + switch f := f.(type) {{"{"}}{{if .HasCompressedFile}} + case *vfsgen۰CompressedFileInfo: + gr, err := gzip.NewReader(bytes.NewReader(f.compressedContent)) + if err != nil { + // This should never happen because we generate the gzip bytes such that they are always valid. + panic("unexpected error reading own gzip compressed bytes: " + err.Error()) + } + return &vfsgen۰CompressedFile{ + vfsgen۰CompressedFileInfo: f, + gr: gr, + }, nil{{end}}{{if .HasFile}} + case *vfsgen۰FileInfo: + return &vfsgen۰File{ + vfsgen۰FileInfo: f, + Reader: bytes.NewReader(f.content), + }, nil{{end}} + case *vfsgen۰DirInfo: + return &vfsgen۰Dir{ + vfsgen۰DirInfo: f, + }, nil + default: + // This should never happen because we generate only the above types. + panic(fmt.Sprintf("unexpected type %T", f)) + } +} +{{if .HasCompressedFile}} +// vfsgen۰CompressedFileInfo is a static definition of a gzip compressed file. +type vfsgen۰CompressedFileInfo struct { + name string + modTime time.Time + compressedContent []byte + uncompressedSize int64 +} + +func (f *vfsgen۰CompressedFileInfo) Readdir(count int) ([]os.FileInfo, error) { + return nil, fmt.Errorf("cannot Readdir from file %s", f.name) +} +func (f *vfsgen۰CompressedFileInfo) Stat() (os.FileInfo, error) { return f, nil } + +func (f *vfsgen۰CompressedFileInfo) GzipBytes() []byte { + return f.compressedContent +} + +func (f *vfsgen۰CompressedFileInfo) Name() string { return f.name } +func (f *vfsgen۰CompressedFileInfo) Size() int64 { return f.uncompressedSize } +func (f *vfsgen۰CompressedFileInfo) Mode() os.FileMode { return 0444 } +func (f *vfsgen۰CompressedFileInfo) ModTime() time.Time { return f.modTime } +func (f *vfsgen۰CompressedFileInfo) IsDir() bool { return false } +func (f *vfsgen۰CompressedFileInfo) Sys() interface{} { return nil } + +// vfsgen۰CompressedFile is an opened compressedFile instance. +type vfsgen۰CompressedFile struct { + *vfsgen۰CompressedFileInfo + gr *gzip.Reader + grPos int64 // Actual gr uncompressed position. + seekPos int64 // Seek uncompressed position. +} + +func (f *vfsgen۰CompressedFile) Read(p []byte) (n int, err error) { + if f.grPos > f.seekPos { + // Rewind to beginning. + err = f.gr.Reset(bytes.NewReader(f.compressedContent)) + if err != nil { + return 0, err + } + f.grPos = 0 + } + if f.grPos < f.seekPos { + // Fast-forward. + _, err = io.CopyN(ioutil.Discard, f.gr, f.seekPos-f.grPos) + if err != nil { + return 0, err + } + f.grPos = f.seekPos + } + n, err = f.gr.Read(p) + f.grPos += int64(n) + f.seekPos = f.grPos + return n, err +} +func (f *vfsgen۰CompressedFile) Seek(offset int64, whence int) (int64, error) { + switch whence { + case io.SeekStart: + f.seekPos = 0 + offset + case io.SeekCurrent: + f.seekPos += offset + case io.SeekEnd: + f.seekPos = f.uncompressedSize + offset + default: + panic(fmt.Errorf("invalid whence value: %v", whence)) + } + return f.seekPos, nil +} +func (f *vfsgen۰CompressedFile) Close() error { + return f.gr.Close() +} +{{else}} +// We already imported "compress/gzip" and "io/ioutil", but ended up not using them. Avoid unused import error. +var _ = gzip.Reader{} +var _ = ioutil.Discard +{{end}}{{if .HasFile}} +// vfsgen۰FileInfo is a static definition of an uncompressed file (because it's not worth gzip compressing). +type vfsgen۰FileInfo struct { + name string + modTime time.Time + content []byte +} + +func (f *vfsgen۰FileInfo) Readdir(count int) ([]os.FileInfo, error) { + return nil, fmt.Errorf("cannot Readdir from file %s", f.name) +} +func (f *vfsgen۰FileInfo) Stat() (os.FileInfo, error) { return f, nil } + +func (f *vfsgen۰FileInfo) NotWorthGzipCompressing() {} + +func (f *vfsgen۰FileInfo) Name() string { return f.name } +func (f *vfsgen۰FileInfo) Size() int64 { return int64(len(f.content)) } +func (f *vfsgen۰FileInfo) Mode() os.FileMode { return 0444 } +func (f *vfsgen۰FileInfo) ModTime() time.Time { return f.modTime } +func (f *vfsgen۰FileInfo) IsDir() bool { return false } +func (f *vfsgen۰FileInfo) Sys() interface{} { return nil } + +// vfsgen۰File is an opened file instance. +type vfsgen۰File struct { + *vfsgen۰FileInfo + *bytes.Reader +} + +func (f *vfsgen۰File) Close() error { + return nil +} +{{else if not .HasCompressedFile}} +// We already imported "bytes", but ended up not using it. Avoid unused import error. +var _ = bytes.Reader{} +{{end}} +// vfsgen۰DirInfo is a static definition of a directory. +type vfsgen۰DirInfo struct { + name string + modTime time.Time + entries []os.FileInfo +} + +func (d *vfsgen۰DirInfo) Read([]byte) (int, error) { + return 0, fmt.Errorf("cannot Read from directory %s", d.name) +} +func (d *vfsgen۰DirInfo) Close() error { return nil } +func (d *vfsgen۰DirInfo) Stat() (os.FileInfo, error) { return d, nil } + +func (d *vfsgen۰DirInfo) Name() string { return d.name } +func (d *vfsgen۰DirInfo) Size() int64 { return 0 } +func (d *vfsgen۰DirInfo) Mode() os.FileMode { return 0755 | os.ModeDir } +func (d *vfsgen۰DirInfo) ModTime() time.Time { return d.modTime } +func (d *vfsgen۰DirInfo) IsDir() bool { return true } +func (d *vfsgen۰DirInfo) Sys() interface{} { return nil } + +// vfsgen۰Dir is an opened dir instance. +type vfsgen۰Dir struct { + *vfsgen۰DirInfo + pos int // Position within entries for Seek and Readdir. +} + +func (d *vfsgen۰Dir) Seek(offset int64, whence int) (int64, error) { + if offset == 0 && whence == io.SeekStart { + d.pos = 0 + return 0, nil + } + return 0, fmt.Errorf("unsupported Seek in directory %s", d.name) +} + +func (d *vfsgen۰Dir) Readdir(count int) ([]os.FileInfo, error) { + if d.pos >= len(d.entries) && count > 0 { + return nil, io.EOF + } + if count <= 0 || count > len(d.entries)-d.pos { + count = len(d.entries) - d.pos + } + e := d.entries[d.pos : d.pos+count] + d.pos += count + return e, nil +} +{{end}} + + + +{{define "Time"}} +{{- if .IsZero -}} + time.Time{} +{{- else -}} + time.Date({{.Year}}, {{printf "%d" .Month}}, {{.Day}}, {{.Hour}}, {{.Minute}}, {{.Second}}, {{.Nanosecond}}, time.UTC) +{{- end -}} +{{end}} +`)) diff --git a/vendor/github.com/shurcooL/vfsgen/options.go b/vendor/github.com/shurcooL/vfsgen/options.go new file mode 100644 index 0000000000..d10d348e70 --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/options.go @@ -0,0 +1,45 @@ +package vfsgen + +import ( + "fmt" + "strings" +) + +// Options for vfsgen code generation. +type Options struct { + // Filename of the generated Go code output (including extension). + // If left empty, it defaults to "{{toLower .VariableName}}_vfsdata.go". + Filename string + + // PackageName is the name of the package in the generated code. + // If left empty, it defaults to "main". + PackageName string + + // BuildTags are the optional build tags in the generated code. + // The build tags syntax is specified by the go tool. + BuildTags string + + // VariableName is the name of the http.FileSystem variable in the generated code. + // If left empty, it defaults to "assets". + VariableName string + + // VariableComment is the comment of the http.FileSystem variable in the generated code. + // If left empty, it defaults to "{{.VariableName}} statically implements the virtual filesystem provided to vfsgen.". + VariableComment string +} + +// fillMissing sets default values for mandatory options that are left empty. +func (opt *Options) fillMissing() { + if opt.PackageName == "" { + opt.PackageName = "main" + } + if opt.VariableName == "" { + opt.VariableName = "assets" + } + if opt.Filename == "" { + opt.Filename = fmt.Sprintf("%s_vfsdata.go", strings.ToLower(opt.VariableName)) + } + if opt.VariableComment == "" { + opt.VariableComment = fmt.Sprintf("%s statically implements the virtual filesystem provided to vfsgen.", opt.VariableName) + } +} diff --git a/vendor/github.com/shurcooL/vfsgen/stringwriter.go b/vendor/github.com/shurcooL/vfsgen/stringwriter.go new file mode 100644 index 0000000000..a781efdc6d --- /dev/null +++ b/vendor/github.com/shurcooL/vfsgen/stringwriter.go @@ -0,0 +1,27 @@ +package vfsgen + +import ( + "io" +) + +// stringWriter writes given bytes to underlying io.Writer as a Go interpreted string literal value, +// not including double quotes. It tracks the total number of bytes written. +type stringWriter struct { + io.Writer + N int64 // Total bytes written. +} + +func (sw *stringWriter) Write(p []byte) (n int, err error) { + const hex = "0123456789abcdef" + buf := []byte{'\\', 'x', 0, 0} + for _, b := range p { + buf[2], buf[3] = hex[b/16], hex[b%16] + _, err = sw.Writer.Write(buf) + if err != nil { + return n, err + } + n++ + sw.N++ + } + return n, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 9f9ae9b4fb..4bb4a5e247 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -91,8 +91,6 @@ github.com/denisenkom/go-mssqldb github.com/dgrijalva/jwt-go # github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 github.com/edsrzf/mmap-go -# github.com/elazarl/go-bindata-assetfs v0.0.0-20151224045452-57eb5e1fc594 -github.com/elazarl/go-bindata-assetfs # github.com/emirpasic/gods v1.12.0 github.com/emirpasic/gods/trees/binaryheap github.com/emirpasic/gods/containers @@ -115,8 +113,6 @@ github.com/facebookgo/httpdown github.com/facebookgo/stats # github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd github.com/glycerine/go-unsnap-stream -# github.com/go-macaron/bindata v0.0.0-20161222093048-85786f57eee3 -github.com/go-macaron/bindata # github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 github.com/go-macaron/binding # github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 @@ -296,8 +292,12 @@ github.com/russross/blackfriday github.com/satori/go.uuid # github.com/sergi/go-diff v1.0.0 github.com/sergi/go-diff/diffmatchpatch +# github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b +github.com/shurcooL/httpfs/vfsutil # github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc github.com/shurcooL/sanitized_anchor_name +# github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd +github.com/shurcooL/vfsgen # github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d github.com/siddontang/go-snappy/snappy # github.com/src-d/gcfg v1.4.0 From 9002c5157b352afb944d0c6a5065deee1e8b113d Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 2 Jun 2019 21:46:35 +0000 Subject: [PATCH 081/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 7 ++++++- options/locale/locale_es-ES.ini | 16 ++++++++-------- options/locale/locale_ja-JP.ini | 2 ++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 3a3e970d77..7c24abefab 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -305,6 +305,8 @@ password_not_match=Die Passwörter stimmen nicht überein. username_been_taken=Der Benutzername ist bereits vergeben. repo_name_been_taken=Der Repository-Name wird schon verwendet. +visit_rate_limit=Das Rate-Limit bei der Gegenseite wurde erreicht. +2fa_auth_required=Die Gegenseite benötigt Zweifaktorauthentifikation. org_name_been_taken=Der Organisationsname ist bereits vergeben. team_name_been_taken=Der Teamname ist bereits vergeben. team_no_units_error=Das Team muss auf mindestens einen Bereich Zugriff haben. @@ -608,6 +610,7 @@ migrate_items_milestones=Meilensteine migrate_items_labels=Labels migrate_items_issues=Issues migrate_items_pullrequests=Pull-Requests +migrate_items_releases=Releases migrate_repo=Repository migrieren migrate.clone_address=Migrations- / Klon-URL migrate.clone_address_desc=Die HTTP(S)- oder „git clone“-URL eines bereits existierenden Repositorys @@ -1518,6 +1521,8 @@ dashboard.delete_repo_archives=Alle Repository-Archive löschen dashboard.delete_repo_archives_success=Alle Repository-Archive wurden gelöscht. dashboard.delete_missing_repos=Alle Repository-Datensätze mit verlorenen gegangenen Git-Dateien löschen dashboard.delete_missing_repos_success=Alle Repository-Datensätze mit verlorenen Git-Dateien wurden gelöscht. +dashboard.delete_generated_repository_avatars=Generierte Repository-Avatare löschen +dashboard.delete_generated_repository_avatars_success=Generierte Repository-Avatare wurden gelöscht. dashboard.git_gc_repos=Garbage-Collection auf Repositories ausführen dashboard.git_gc_repos_success=Alle Repositories haben Garbage-Collection beendet. dashboard.resync_all_sshkeys=„.ssh/authorized_keys“-Datei mit Gitea-SSH-Keys neu schreiben. (Wenn Du den eingebauten SSH-Server nutzt, musst du das nicht ausführen.) @@ -1576,7 +1581,7 @@ users.auth_source=Authentifizierungsquelle users.local=Lokal users.auth_login_name=Anmeldename zur Authentifizierung users.password_helper=Passwort leer lassen, um es nicht zu verändern. -users.update_profile_success=Der Account „%s“ wurde aktualisiert. +users.update_profile_success=Das Benutzerkonto wurde aktualisiert. users.edit_account=Benutzerkonto bearbeiten users.max_repo_creation=Maximale Anzahl Repositories users.max_repo_creation_desc=(Gib -1 ein, um das globale Standardlimit zu verwenden.) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 4853680492..28a3952bfa 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -26,7 +26,7 @@ email=Correo electrónico password=Contraseña re_type=Vuelva a escribir la contraseña captcha=CAPTCHA -twofa=Autenticación en dos pasos +twofa=Autenticación de doble factor passcode=Contraseña u2f_insert_key=Inserte su clave de seguridad @@ -49,7 +49,7 @@ your_starred=Destacado your_settings=Configuración all=Todos -sources=Fuentes +sources=Proprios mirrors=Réplica collaborative=Colaborativos forks=Forks @@ -158,7 +158,7 @@ email_not_associate=Esta dirección de correo electrónico no esta asociada a ni invalid_code=Su código de confirmación no es válido o ha caducado. non_local_account=Los usuarios no locales no pueden actualizar su contraseña a través de la interfaz web de Gitea. verify=Verificar -twofa_scratch_used=Ya has utilizado el código. Has sido redirigido a la página de configuración de dos factores poder remover la inscripción del dispositivo o generar un nuevo código. +twofa_scratch_used=Ya has utilizado el código. Has sido redirigido a la página de configuración de doble factor poder retirar la inscripción del dispositivo o generar un nuevo código. twofa_scratch_token_incorrect=El código cero es incorrecto. login_userpass=Iniciar sesión login_openid=OpenID @@ -237,7 +237,7 @@ ssh_gpg_keys=SSH / claves GPG social=Redes Sociales repos=Repositorios delete=Eliminar cuenta -twofa=Autenticación en dos pasos +twofa=Autenticación de doble factor uid=UUID public_profile=Perfil público @@ -294,9 +294,9 @@ delete_token=Eliminar -twofa_is_enrolled=Su cuenta actualmente está registrada en la autenticación de dos factores. +twofa_is_enrolled=Su cuenta actualmente está registrada en la autenticación de doble factor. twofa_not_enrolled=Tu cuenta no está actualmente inscrita en la autenticación de doble factor. -twofa_disabled=La autenticación en dos pasos ha sido deshabilitada. +twofa_disabled=La autenticación de doble factor ha sido deshabilitada. scan_this_image=Analiza esta imagen con la aplicación de autenticación: or_enter_secret=O introduzca el secreto: %s @@ -343,9 +343,9 @@ copy_link=Copiar copied=Copiado OK unwatch=Dejar de seguir watch=Seguir -unstar=Eliminar destacado +unstar=Eliminar de favoritos star=Destacar -fork=Cuchillo +fork=Bifurcar no_desc=Sin descripción quick_guide=Guía rápida diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index e65162dfe2..033f78c1f1 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1521,6 +1521,8 @@ dashboard.delete_repo_archives=リポジトリアーカイブをすべて削除 dashboard.delete_repo_archives_success=リポジトリアーカイブをすべて削除しました。 dashboard.delete_missing_repos=Gitファイルが存在しないリポジトリをすべて削除 dashboard.delete_missing_repos_success=Gitファイルが存在しないリポジトリをすべて削除しました。 +dashboard.delete_generated_repository_avatars=自動生成したリポジトリアバターを削除 +dashboard.delete_generated_repository_avatars_success=自動生成したリポジトリアバターを削除しました。 dashboard.git_gc_repos=すべてのリポジトリでガベージコレクションを実行 dashboard.git_gc_repos_success=すべてのリポジトリでガベージコレクションを完了しました。 dashboard.resync_all_sshkeys=GiteaのSSHキーで '.ssh/authorized_keys' ファイルを更新 (ビルトインSSHサーバーには不要) From 45f588e85dbd3004334718dc9fbbb27675814ee0 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Mon, 3 Jun 2019 10:07:03 +0200 Subject: [PATCH 082/220] Avoid arbitrary format strings upon calling fail() function (#7112) --- cmd/serv.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/serv.go b/cmd/serv.go index aa068d4cf6..0b0a4e8efb 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -53,7 +53,7 @@ func checkLFSVersion() { //Needs at least git v2.1.2 binVersion, err := git.BinVersion() if err != nil { - fail(fmt.Sprintf("Error retrieving git version: %v", err), fmt.Sprintf("Error retrieving git version: %v", err)) + fail("LFS server error", "Error retrieving git version: %v", err) } if !version.Compare(binVersion, "2.1.2", ">=") { @@ -199,12 +199,12 @@ func runServ(c *cli.Context) error { if private.IsErrServCommand(err) { errServCommand := err.(private.ErrServCommand) if errServCommand.StatusCode != http.StatusInternalServerError { - fail("Unauthorized", errServCommand.Error()) + fail("Unauthorized", "%s", errServCommand.Error()) } else { - fail("Internal Server Error", errServCommand.Error()) + fail("Internal Server Error", "%s", errServCommand.Error()) } } - fail("Internal Server Error", err.Error()) + fail("Internal Server Error", "%s", err.Error()) } os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki)) os.Setenv(models.EnvRepoName, results.RepoName) From 2ac2a5b0ba9f9a07867ed92792de7d54a8e10d23 Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Mon, 3 Jun 2019 11:11:20 -0400 Subject: [PATCH 083/220] Refactor submodule URL parsing (#7100) Use combination of url.Parse and regex to parse refURL rather than by hand with indexes & attempt to check if refURL is from same instance and adjust output to match. Also now return empty string instead of our original guess at URL if we are unable to parse it. Fixes #1526 --- modules/git/submodule.go | 90 ++++++++++++++++++++++++----------- modules/git/submodule_test.go | 13 ++++- 2 files changed, 75 insertions(+), 28 deletions(-) diff --git a/modules/git/submodule.go b/modules/git/submodule.go index 294df3986a..6fc2e2444f 100644 --- a/modules/git/submodule.go +++ b/modules/git/submodule.go @@ -1,10 +1,19 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. // 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 "strings" +import ( + "fmt" + "net" + "net/url" + "regexp" + "strings" +) + +var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+@)?([a-zA-Z0-9._-]+):(.*)$`) // SubModule submodule is a reference on git repository type SubModule struct { @@ -34,46 +43,73 @@ func getRefURL(refURL, urlPrefix, parentPath string) string { return "" } - url := strings.TrimSuffix(refURL, ".git") + refURI := strings.TrimSuffix(refURL, ".git") - // git://xxx/user/repo - if strings.HasPrefix(url, "git://") { - return "http://" + strings.TrimPrefix(url, "git://") - } - - // http[s]://xxx/user/repo - if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") { - return url + prefixURL, _ := url.Parse(urlPrefix) + urlPrefixHostname, _, err := net.SplitHostPort(prefixURL.Host) + if err != nil { + urlPrefixHostname = prefixURL.Host } // Relative url prefix check (according to git submodule documentation) - if strings.HasPrefix(url, "./") || strings.HasPrefix(url, "../") { + if strings.HasPrefix(refURI, "./") || strings.HasPrefix(refURI, "../") { // ...construct and return correct submodule url here... idx := strings.Index(parentPath, "/src/") if idx == -1 { - return url + return refURI } - return strings.TrimSuffix(urlPrefix, "/") + parentPath[:idx] + "/" + url + return strings.TrimSuffix(urlPrefix, "/") + parentPath[:idx] + "/" + refURI } - // sysuser@xxx:user/repo - i := strings.Index(url, "@") - j := strings.LastIndex(url, ":") + if !strings.Contains(refURI, "://") { + // scp style syntax which contains *no* port number after the : (and is not parsed by net/url) + // ex: git@try.gitea.io:go-gitea/gitea + match := scpSyntax.FindAllStringSubmatch(refURI, -1) + if len(match) > 0 { - // Only process when i < j because git+ssh://git@git.forwardbias.in/npploader.git - if i > -1 && j > -1 && i < j { - // fix problem with reverse proxy works only with local server - if strings.Contains(urlPrefix, url[i+1:j]) { - return urlPrefix + url[j+1:] + m := match[0] + refHostname := m[2] + path := m[3] + + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + + if urlPrefixHostname == refHostname { + return prefixURL.Scheme + "://" + urlPrefixHostname + path + } + return "http://" + refHostname + path } - if strings.HasPrefix(url, "ssh://") || strings.HasPrefix(url, "git+ssh://") { - k := strings.Index(url[j+1:], "/") - return "http://" + url[i+1:j] + "/" + url[j+1:][k+1:] - } - return "http://" + url[i+1:j] + "/" + url[j+1:] } - return url + ref, err := url.Parse(refURI) + if err != nil { + return "" + } + + refHostname, _, err := net.SplitHostPort(ref.Host) + if err != nil { + refHostname = ref.Host + } + + supportedSchemes := []string{"http", "https", "git", "ssh", "git+ssh"} + + for _, scheme := range supportedSchemes { + if ref.Scheme == scheme { + if urlPrefixHostname == refHostname { + return prefixURL.Scheme + "://" + prefixURL.Host + ref.Path + } else if ref.Scheme == "http" || ref.Scheme == "https" { + if len(ref.User.Username()) > 0 { + return ref.Scheme + "://" + fmt.Sprintf("%v", ref.User) + "@" + ref.Host + ref.Path + } + return ref.Scheme + "://" + ref.Host + ref.Path + } else { + return "http://" + refHostname + ref.Path + } + } + } + + return "" } // RefURL guesses and returns reference URL. diff --git a/modules/git/submodule_test.go b/modules/git/submodule_test.go index 6a3bb7ec7b..fd6c2aa955 100644 --- a/modules/git/submodule_test.go +++ b/modules/git/submodule_test.go @@ -19,8 +19,19 @@ func TestGetRefURL(t *testing.T) { }{ {"git://github.com/user1/repo1", "/", "/", "http://github.com/user1/repo1"}, {"https://localhost/user1/repo1.git", "/", "/", "https://localhost/user1/repo1"}, - {"git@github.com/user1/repo1.git", "/", "/", "git@github.com/user1/repo1"}, + {"http://localhost/user1/repo1.git", "/", "/", "http://localhost/user1/repo1"}, + {"git@github.com:user1/repo1.git", "/", "/", "http://github.com/user1/repo1"}, {"ssh://git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "/", "http://git.zefie.net/zefie/lge_g6_kernel_scripts"}, + {"git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "/", "http://git.zefie.net/2222/zefie/lge_g6_kernel_scripts"}, + {"git@try.gitea.io:go-gitea/gitea", "https://try.gitea.io/go-gitea/gitea", "/", "https://try.gitea.io/go-gitea/gitea"}, + {"ssh://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/go-gitea/gitea", "/", "https://try.gitea.io/go-gitea/gitea"}, + {"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/go-gitea/log", "/", "https://try.gitea.io/go-gitea/gitea"}, + {"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/go-gitea/log", "/", "https://127.0.0.1:3000/go-gitea/gitea"}, + {"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/go-gitea/gitea", "/", "https://gitea.com:3000/user1/repo1"}, + {"https://username:password@github.com/username/repository.git", "/", "/", "https://username:password@github.com/username/repository"}, + {"somethingbad", "https://127.0.0.1:3000/go-gitea/gitea", "/", ""}, + {"git@localhost:user/repo", "https://localhost/user/repo2", "/", "https://localhost/user/repo"}, + {"../path/to/repo.git/", "https://localhost/user/repo2/src/branch/master/test", "/", "../path/to/repo.git/"}, } for _, kase := range kases { From 160e7edd047c0e26eb3ab806c8c73551a74f881a Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 3 Jun 2019 15:13:51 +0000 Subject: [PATCH 084/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_fr-FR.ini | 2 +- options/locale/locale_pt-BR.ini | 2 ++ options/locale/locale_zh-CN.ini | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index e6755f8cb5..45e6dbf20b 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -91,7 +91,7 @@ ssl_mode=SSL charset=Jeu de caractères path=Emplacement sqlite_helper=Chemin d'accès pour la base de données SQLite3.
    Entrer un chemin absolu si vous exécutez Gitea en tant que service. -err_empty_db_path=Le chemin de la base de donnée SQLite3 ne peut être vide. +err_empty_db_path=Le chemin de la base de données SQLite3 ne peut être vide. no_admin_and_disable_registration=Vous ne pouvez pas désactiver la création de nouveaux utilisateurs avant d'avoir créé un compte administrateur. err_empty_admin_password=Le mot de passe administrateur ne peut pas être vide. err_empty_admin_email=L'adresse e-mail de l'administrateur ne peut pas être vide. diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 65b26c6ee9..011b9f9e54 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1521,6 +1521,8 @@ dashboard.delete_repo_archives=Excluir todos os arquivos do repositório dashboard.delete_repo_archives_success=Todos os arquivos do repositório foram excluídos. dashboard.delete_missing_repos=Excluir todos os repositórios que não possuem seus arquivos Git dashboard.delete_missing_repos_success=Todos os repositórios que não possuem seus arquivos Git foram excluídos. +dashboard.delete_generated_repository_avatars=Excluir avatares gerados do repositório +dashboard.delete_generated_repository_avatars_success=Os avatares gerados do repositório foram excluídos. dashboard.git_gc_repos=Coleta de lixo em todos os repositórios dashboard.git_gc_repos_success=Todos os repositórios finalizaram a execução da coleta de lixo. dashboard.resync_all_sshkeys=Atualizar o arquivo '.ssh/authorized_keys' com as chaves SSH do Gitea. (Não necessária para o servidor SSH nativo.) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 5ac415460d..1a2ed9fc1f 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -926,7 +926,7 @@ issues.dependency.add_error_dep_not_same_repo=这两个工单必须在同一仓 issues.review.self.approval=您不能批准您自己的合并请求。 issues.review.self.rejection=您不能请求对您自己的合并请求进行更改。 issues.review.approve=已批准这些更改 %s -issues.review.comment=已评审 %s +issues.review.comment=评审于 %s issues.review.content.empty=您需要留下一个注释,表明需要的更改。 issues.review.reject=请求变更 %s issues.review.pending=待定 From 2a8037fe4e95f2197f1123e43e5c626de9826eb8 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Tue, 4 Jun 2019 14:36:09 -0500 Subject: [PATCH 085/220] Migration Tweaks (#6260) * Adds auto-name if repo name is blank Adds error checking before sanitization in migration Signed-off-by: jolheiser * Changed err from sanitization to a different variable Signed-off-by: jolheiser * Remove handleCreatePost and implement separately Signed-off-by: jolheiser * Make fmt Signed-off-by: jolheiser --- public/js/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/public/js/index.js b/public/js/index.js index 96a56a4241..ed3198594a 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2160,6 +2160,14 @@ $(document).ready(function () { break; } } + + var $cloneAddr = $('#clone_addr'); + $cloneAddr.change(function() { + var $repoName = $('#repo_name'); + if ($cloneAddr.val().length > 0 && $repoName.val().length === 0) { // Only modify if repo_name input is blank + $repoName.val($cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]); + } + }); }); function changeHash(hash) { From 8bf405986e9940be863088e65903d4e2e2fe84ce Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Tue, 4 Jun 2019 23:01:47 +0200 Subject: [PATCH 086/220] Add Rust highlighting (#7125) --- modules/highlight/highlight.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go index 6d5e1a97ba..cb52f6ac2e 100644 --- a/modules/highlight/highlight.go +++ b/modules/highlight/highlight.go @@ -51,6 +51,7 @@ var ( ".php": {}, ".py": {}, ".rb": {}, + ".rs": {}, ".scss": {}, ".sql": {}, ".scala": {}, From 5d3177dbb650b64eed4a1f35c7e469438270b90b Mon Sep 17 00:00:00 2001 From: Nick Meyer Date: Tue, 4 Jun 2019 20:17:17 -0500 Subject: [PATCH 087/220] Exclude pull_request from fetch-tags step, fixes #7108 (#7120) Signed-off-by: Nick Meyer --- .drone.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.drone.yml b/.drone.yml index 6d9cde5ca9..0b8c8422b6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,6 +7,9 @@ pipeline: image: docker:git commands: - git fetch --tags --force + when: + event: + exclude: [ pull_request ] download_translations: image: jonasfranz/crowdin From 3fb54e11c1bb6375b19758af89f88e330018c363 Mon Sep 17 00:00:00 2001 From: katherine Date: Wed, 5 Jun 2019 07:16:06 -0700 Subject: [PATCH 088/220] minor fixes in en-US locale (#7130) a few spelling fixes and one rewritten line Signed-off-by: katherine --- options/locale/locale_en-US.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ebc6ca31ce..71c76fd9b6 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -488,7 +488,7 @@ manage_oauth2_applications = Manage OAuth2 Applications edit_oauth2_application = Edit OAuth2 Application oauth2_applications_desc = OAuth2 applications enables your third-party application to securely authenticate users at this Gitea instance. remove_oauth2_application = Remove OAuth2 Application -remove_oauth2_application_desc = Removing an OAuth2 application will revoke access to all signed access tokes. Continue? +remove_oauth2_application_desc = Removing an OAuth2 application will revoke access to all signed access tokens. Continue? remove_oauth2_application_success = The application has been deleted. create_oauth2_application = Create a new OAuth2 Application create_oauth2_application_button = Create Application @@ -620,7 +620,7 @@ migrate.permission_denied = You are not allowed to import local repositories. migrate.invalid_local_path = "The local path is invalid. It does not exist or is not a directory." migrate.failed = Migration failed: %v migrate.lfs_mirror_unsupported = Mirroring LFS objects is not supported - use 'git lfs fetch --all' and 'git lfs push --all' instead. -migrate.migrate_items_options = When you are migrating from github and inputed username, the migration options will be display. +migrate.migrate_items_options = When migrating from github, input a username and migration options will be displayed. mirror_from = mirror of forked_from = forked from @@ -1307,14 +1307,14 @@ settings.archive.button = Archive Repo settings.archive.header = Archive This Repo settings.archive.text = Archiving the repo will make it entirely read-only. It is hidden from the dashboard, cannot be committed to and no issues or pull-requests can be created. settings.archive.success = The repo was successfully archived. -settings.archive.error = An error occured while trying to archive the repo. See the log for more details. +settings.archive.error = An error occurred while trying to archive the repo. See the log for more details. settings.archive.error_ismirror = You cannot archive a mirrored repo. settings.archive.branchsettings_unavailable = Branch settings are not available if the repo is archived. settings.unarchive.button = Un-Archive Repo settings.unarchive.header = Un-Archive This Repo -settings.unarchive.text = Un-Archiving the repo will restore its ability to recieve commits and pushes, as well as new issues and pull-requests. +settings.unarchive.text = Un-Archiving the repo will restore its ability to receive commits and pushes, as well as new issues and pull-requests. settings.unarchive.success = The repo was successfully un-archived. -settings.unarchive.error = An error occured while trying to un-archive the repo. See the log for more details. +settings.unarchive.error = An error occurred while trying to un-archive the repo. See the log for more details. settings.update_avatar_success = The repository avatar has been updated. diff.browse_source = Browse Source From a6fed1542c851e874484392a7bef14118ca19928 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Wed, 5 Jun 2019 17:24:09 +0100 Subject: [PATCH 089/220] add docs for #6847 (#7132) --- docs/content/doc/usage/command-line.en-us.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index ab52109e93..516e46ff0b 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -62,6 +62,7 @@ Admin operations: - `--password value`: Password. Required. - `--email value`: Email. Required. - `--admin`: If provided, this makes the user an admin. Optional. + - `--access-token`: If provided, an access token will be created for the user. Optional. (default: false). - `--must-change-password`: If provided, the created user will be required to choose a newer password after the initial login. Optional. (default: true). - ``--random-password``: If provided, a randomly generated password will be used as the password of From 59e6a7b97f503c12ef2a6096ca7f127f81521b7a Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 5 Jun 2019 16:26:53 +0000 Subject: [PATCH 090/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 4 --- options/locale/locale_de-DE.ini | 5 --- options/locale/locale_fr-FR.ini | 7 ++-- options/locale/locale_ja-JP.ini | 5 --- options/locale/locale_lv-LV.ini | 3 -- options/locale/locale_pt-BR.ini | 5 --- options/locale/locale_ru-RU.ini | 64 ++++++++++++++++++++++++++++++++- options/locale/locale_zh-CN.ini | 5 --- 8 files changed, 65 insertions(+), 33 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index bd503ac561..13bb4f9c05 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -478,7 +478,6 @@ manage_oauth2_applications=Spravovat OAuth2 aplikace edit_oauth2_application=Upravit OAuth2 aplikaci oauth2_applications_desc=OAuth2 aplikace umožní aplikacím třetích stran bezpečně ověřit uživatele v této instanci Gitea. remove_oauth2_application=Odstranit OAuth2 aplikaci -remove_oauth2_application_desc=Odstraněním OAuth2 aplikace odeberete přístup všem podepsaným přístupovým poukázkám. Pokračovat? remove_oauth2_application_success=Aplikace byla odstraněna. create_oauth2_application=Vytvořit novou OAuth2 aplikaci create_oauth2_application_button=Vytvořit aplikaci @@ -1258,14 +1257,11 @@ settings.archive.button=Archivovat repozitář settings.archive.header=Archivovat tento repozitář settings.archive.text=Archivní repozitář bude kompletně jen pro čtení. Nezobrazuje se v přehledu, nelze přidávat revize ani nové úkoly a požadavky na natažení. settings.archive.success=Repozitář byl úspěšně archivován. -settings.archive.error=Nastala chyba při archivování repozitáře. Prohlédněte si záznam pro více detailů. settings.archive.error_ismirror=Nemůžete archivovat zrcadlený repozitář. settings.archive.branchsettings_unavailable=Nastavení větví není dostupné, pokud je repozitář archivovaný. settings.unarchive.button=Obnovit repozitář settings.unarchive.header=Obnovit tento repozitář -settings.unarchive.text=Obnovení repozitáře vrátí možnost přijímání revizí a nahrávání. Stejně tak se obnoví i možnost zadávání nových úkolů a požadavků na natažení. settings.unarchive.success=Repozitář byl úspěšně obnoven. -settings.unarchive.error=Nastala chyba při obnovování repozitáře. Prohlédněte si záznam pro více detailů. diff.browse_source=Procházet zdrojové kódy diff.parent=rodič diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 7c24abefab..7a0b61d2ee 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -487,7 +487,6 @@ manage_oauth2_applications=OAuth2 Anwendungen verwalten edit_oauth2_application=OAuth2 Anwendung bearbeiten oauth2_applications_desc=OAuth2-Anwendungen ermöglichen die sichere Authentifizierung von Benutzern dieser Gitea-Instanz für deine Drittanwendung. remove_oauth2_application=OAuth2-Anwendung entfernen -remove_oauth2_application_desc=Wenn du diese OAuth2 Anwendung entfernst, werden auch alle davon ausgestellte Access Tokens ungültig. Möchtest du fortfahren? remove_oauth2_application_success=Die Anwendung wurde gelöscht. create_oauth2_application=Neue OAuth2 Anwendung erstellen create_oauth2_application_button=Anwendung erstellen @@ -619,7 +618,6 @@ migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Rep migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner. migrate.failed=Fehler bei der Migration: %v migrate.lfs_mirror_unsupported=Spiegeln von LFS-Objekten wird nicht unterstützt - nutze stattdessen 'git lfs fetch --all' und 'git lfs push --all'. -migrate.migrate_items_options=Wenn du von GitHub migrierst und einen Benutzernamen eingegeben hast, werden die Migrationsoptionen angezeigt. mirror_from=Mirror von forked_from=geforkt von @@ -1306,14 +1304,11 @@ settings.archive.button=Repo archivieren settings.archive.header=Dieses Repo archivieren settings.archive.text=Durch die Archivierung des Repos wird es vollständig schreibgeschützt. Es wird auf dem Dashboard versteckt, nimmt keine Commits an und es können keine Issues oder Pull-Requests erstellt werden. settings.archive.success=Das Repo wurde erfolgreich archiviert. -settings.archive.error=Beim Archivieren des Repos trat ein Fehler auf. In den Logs befinden sich mehr Details. settings.archive.error_ismirror=Du kannst keinen Repo-Mirror archivieren. settings.archive.branchsettings_unavailable=Branch-Einstellungen sind nicht verfügbar wenn das Repo archiviert ist. settings.unarchive.button=Archivieren rückgängig machen settings.unarchive.header=Archivieren dieses Repos rückgängig machen -settings.unarchive.text=Das Rückgängig machen dieses Repo-Archivs stellt seine Fähigkeit wieder her, Commits und Pushes anzunehmen, sowie neue Issues und Pull-Requests zu erstellen. settings.unarchive.success=Die Archivierung des Repos wurde erfolgreich wieder rückgängig gemacht. -settings.unarchive.error=Beim Rückgängig machen dieses Repo-Archivs trat ein Fehler auf. In den Logs befinden sich mehr Details. settings.update_avatar_success=Der Repository-Avatar wurde aktualisiert. diff.browse_source=Quellcode durchsuchen diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 45e6dbf20b..0b077d931d 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -487,7 +487,6 @@ manage_oauth2_applications=Gérer les applications OAuth2 edit_oauth2_application=Modifier l'application OAuth2 oauth2_applications_desc=Les applications OAuth2 permettent à votre application tiers d'authentifier en toute sécurité les utilisateurs de cette instance Gitea. remove_oauth2_application=Supprimer l'application OAuth2 -remove_oauth2_application_desc=Supprimer une application OAuth2 révoquera l'accès à tous les points d'accès signés. Continuer ? remove_oauth2_application_success=L'application a été supprimée. create_oauth2_application=Créer une nouvelle application OAuth2 create_oauth2_application_button=Créer une application @@ -619,7 +618,6 @@ migrate.permission_denied=Vous n'êtes pas autorisé à importer des dépôts lo migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas un dossier. migrate.failed=Echec de migration: %v migrate.lfs_mirror_unsupported=La synchronisation des objets LFS n'est pas supportée - veuillez utiliser 'git lfs fetch --all' et 'git lfs push --all' à la place. -migrate.migrate_items_options=Quand vous migrez depuis github, une fois le nom d'utilisateur saisi, des options de migration supplémentaires seront affichées. mirror_from=miroir de forked_from=bifurqué depuis @@ -1306,14 +1304,11 @@ settings.archive.button=Archiver ce dépôt settings.archive.header=Archiver ce dépôt settings.archive.text=Archiver ce dépôt le rendra en lecture seule. Il sera caché du tableau de bord et vous ne pourrez plus envoyer de révision ni créer de ticket ou demande d'ajout. settings.archive.success=Ce dépôt a été archivé avec succès. -settings.archive.error=Une erreur s'est produite durant l'archivage. Referez-vous au journal pour plus de détails. settings.archive.error_ismirror=Vous ne pouvez pas archiver un dépôt en miroir. settings.archive.branchsettings_unavailable=Le paramétrage des branches n'est pas disponible quand le dépôt est archivé. settings.unarchive.button=Désarchiver ce dépôt settings.unarchive.header=Désarchiver ce dépôt -settings.unarchive.text=Désarchiver le dépôt lui permettra de recevoir des révisions, ainsi que des nouveaux tickets ou demandes d'ajout. settings.unarchive.success=Ce dépôt a été désarchivé avec succès. -settings.unarchive.error=Une erreur s'est produite durant le désarchivage. Referez-vous au journal pour plus de détails. settings.update_avatar_success=L'avatar du dépôt a été mis à jour. diff.browse_source=Parcourir la source @@ -1521,6 +1516,8 @@ dashboard.delete_repo_archives=Supprimer toutes les archives du dépôt dashboard.delete_repo_archives_success=Toutes les archives du dépôt ont été supprimées. dashboard.delete_missing_repos=Supprimer tous les dépôts dont les fichiers Git sont manquants dashboard.delete_missing_repos_success=Tous les dépôts dont les fichiers Git sont manquants ont été supprimés. +dashboard.delete_generated_repository_avatars=Supprimer les avatars de dépôt générés +dashboard.delete_generated_repository_avatars_success=Les avatars de dépôt générés ont été supprimés. dashboard.git_gc_repos=Collecter les déchets des dépôts dashboard.git_gc_repos_success=Les déchets de tous les dépôts ont été collectés. dashboard.resync_all_sshkeys=Ajouter les clefs SSH Gitea au fichier ".ssh/authorized_keys". (Inutile si vous utilisez le serveur SSH intégré). diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 033f78c1f1..9dfad59f57 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -487,7 +487,6 @@ manage_oauth2_applications=OAuth2アプリケーションの管理 edit_oauth2_application=OAuth2アプリケーションの編集 oauth2_applications_desc=OAuth2はGiteaインスタンスでのサードパーティアプリケーションによる安全な認証を可能にします。 remove_oauth2_application=OAuth2アプリケーションの削除 -remove_oauth2_application_desc=OAuth2アプリケーションを削除すると、すべての署名済みアクセストークンへのアクセス権を取り消します。 続行しますか? remove_oauth2_application_success=アプリケーションを削除しました。 create_oauth2_application=新しいOAuth2アプリケーションの作成 create_oauth2_application_button=アプリケーション作成 @@ -619,7 +618,6 @@ migrate.permission_denied=ローカルリポジトリをインポートする権 migrate.invalid_local_path=ローカルパスが無効です。 存在しないかディレクトリではありません。 migrate.failed=移行に失敗しました: %v migrate.lfs_mirror_unsupported=LFSオブジェクトのミラーはサポートされていません。 代わりに 'git lfs fetch --all' と 'git lfs push --all' を使ってください。 -migrate.migrate_items_options=移行元がGitHubの場合は、ユーザー名を入力すると移行オプションが表示されます。 mirror_from=ミラー元 forked_from=フォーク元 @@ -1306,14 +1304,11 @@ settings.archive.button=アーカイブ settings.archive.header=このリポジトリをアーカイブ settings.archive.text=リポジトリをアーカイブすると、リポジトリ全体が読み出し専用となります。 ダッシュボードには表示されなくなり、コミットも、課題やプルリクエストの作成もできません。 settings.archive.success=リポジトリをアーカイブしました。 -settings.archive.error=リポジトリのアーカイブ設定でエラーが発生しました。 詳細はログを確認してください。 settings.archive.error_ismirror=ミラーのリポジトリはアーカイブできません。 settings.archive.branchsettings_unavailable=ブランチ設定は、アーカイブリポジトリでは使用できません。 settings.unarchive.button=アーカイブ解除 settings.unarchive.header=このリポジトリをアーカイブ解除 -settings.unarchive.text=リポジトリのアーカイブを解除すると、コミット、プッシュ、新規の課題やプルリクエストを受け付けるよう元に戻されます。 settings.unarchive.success=リポジトリのアーカイブを解除しました。 -settings.unarchive.error=リポジトリのアーカイブ解除でエラーが発生しました。 詳細はログを確認してください。 settings.update_avatar_success=リポジトリのアバターを更新しました。 diff.browse_source=ソースを参照 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 87df76d789..0aa31361e5 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -1233,14 +1233,11 @@ settings.archive.button=Arhivēt settings.archive.header=Arhivēt repozitoriju settings.archive.text=Arhivējot repozitoriju, tas paliks tikai skatīšanās režīmā. Tas netiks attēlots infopanelī, tam nevarēs iesūtīt jaunas izmaiņas, kā arī pieteikt jaunas problēmas un veidot jaunus izmaiņu pieprasījumus. settings.archive.success=Repozitorijs veiksmīgi arhivēts. -settings.archive.error=Arhivējot repozitoriju radās neparedzēta kļūda. Pārbaudiet kļūdu žurnālu, lai uzzinātu sīkāk. settings.archive.error_ismirror=Nav iespējams arhivēt spoguļotus repozitorijus. settings.archive.branchsettings_unavailable=Atzaru iestatījumi nav pieejami, ja repozitorijs ir arhivēts. settings.unarchive.button=Atcelt arhivāciju settings.unarchive.header=Atcelt repozitorija arhivāciju -settings.unarchive.text=Atceļot repozitoriju arhivāciju, tam atkal varēs iesūtīt jaunas izmaiņas, kā arī pieteikt problēmas un veidot izmaiņu pieprasījumus. settings.unarchive.success=Repozitorijam veiksmīgi atcelta arhivācija. -settings.unarchive.error=Atceļot repozitorija arhivāciju radās neparedzēta kļūda. Pārbaudiet kļūdu žurnālu, lai uzzinātu sīkāk. diff.browse_source=Pārlūkot izejas kodu diff.parent=vecāks diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 011b9f9e54..f68098b2f8 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -487,7 +487,6 @@ manage_oauth2_applications=Gerenciar aplicativos OAuth2 edit_oauth2_application=Editar aplicativo OAuth2 oauth2_applications_desc=Aplicativos OAuth2 permitem que seus aplicativos de terceiros autentiquem com segurança usuários nesta instância do Gitea. remove_oauth2_application=Remover aplicativo OAuth2 -remove_oauth2_application_desc=Remover um aplicativo OAuth2 irá revogar o acesso a todos os tokens de acesso assinados. Continuar? remove_oauth2_application_success=O aplicativo foi excluído. create_oauth2_application=Criar um novo aplicativo OAuth2 create_oauth2_application_button=Criar aplicativo @@ -619,7 +618,6 @@ migrate.permission_denied=Você não pode importar repositórios locais. migrate.invalid_local_path=O caminho local é inválido. Ele não existe ou não é um diretório. migrate.failed=Migração falhou: %v migrate.lfs_mirror_unsupported=Espelhamento de objetos Git LFS não é suportado; ao invés use 'git lfs fetch --all' e 'git lfs push --all'. -migrate.migrate_items_options=Quando você estiver migrando do github e com nome de usuário inserido, as opções de migração serão exibidas. mirror_from=espelhamento de forked_from=feito fork de @@ -1306,14 +1304,11 @@ settings.archive.button=Arquivar repositório settings.archive.header=Arquivar este repositório settings.archive.text=Arquivando um repositório fará com que o mesmo fique inteiramente em modo somente leitura. Ele ficará oculto no painel, não poderá receber commits e nem será possível criar issues e pull requests. settings.archive.success=O repositório foi arquivado com sucesso. -settings.archive.error=Um erro ocorreu enquanto estava sendo arquivado o repositório. Veja o log para mais detalhes. settings.archive.error_ismirror=Você não pode arquivar um repositório espelhado. settings.archive.branchsettings_unavailable=Configurações do branch não estão disponíveis quando o repositório está arquivado. settings.unarchive.button=Desarquivar repositório settings.unarchive.header=Desarquivar este repositório -settings.unarchive.text=Desarquivando um repositório irá restaurar a capacidade do mesmo receber commits, pushs, assim como novas issues e pull requests. settings.unarchive.success=O repositório foi desarquivado com sucesso. -settings.unarchive.error=Um erro ocorreu enquanto estava sendo desarquivado o repositório. Veja o log para mais detalhes. settings.update_avatar_success=O avatar do repositório foi atualizado. diff.browse_source=Ver código fonte diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index b1e2508db5..b544b78d30 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -86,12 +86,18 @@ host=Хост user=Имя пользователя password=Пароль db_name=Имя базы данных +db_helper=Для пользователей MySQL: пожалуйста, используйте движок InnoDB, и если вы используете "utf8mb4" - ваша версия InnoDB должна быть старше 5.6 . ssl_mode=SSL +charset=Кодировка path=Путь sqlite_helper=Путь к файлу базы данных SQLite3.
    Введите абсолютный путь, если вы запускаете Gitea как службу. err_empty_db_path=Путь к базе данных SQLite3 не может быть пустым. no_admin_and_disable_registration=Вы не можете отключить регистрацию до создания учётной записи администратора. err_empty_admin_password=Пароль администратора не может быть пустым. +err_empty_admin_email=Email администратора не может быть пустым. +err_admin_name_is_reserved=Неверное имя администратора, это имя зарезервировано +err_admin_name_pattern_not_allowed=Неверное имя администратора, данный шаблон имени не допускается +err_admin_name_is_invalid=Неверное имя администратора general_title=Основные настройки app_name=Название сайта @@ -205,6 +211,7 @@ sign_up_successful=Учётная запись была успешно созд confirmation_mail_sent_prompt=Новое письмо для подтверждения было направлено на %s, пожалуйста, проверьте ваш почтовый ящик в течение %s для завершения регистрации. must_change_password=Обновить пароль allow_password_change=Требовать смену пароля пользователем (рекомендуется) +reset_password_mail_sent_prompt=Письмо с подтверждением было отправлено на %s. Пожалуйста, проверьте входящую почту в течение %s, чтобы завершить процесс восстановления аккаунта. active_your_account=Активируйте свой аккаунт account_activated=Учётная запись была активирована prohibit_login=Вход запрещен @@ -213,7 +220,11 @@ resent_limit_prompt=Извините, вы уже запросили актив has_unconfirmed_mail=Здравствуйте, %s! У вас есть неподтвержденный адрес электронной почты (%s). Если вам не приходило письмо с подтверждением или нужно выслать новое письмо, нажмите на кнопку ниже. resend_mail=Нажмите здесь, чтобы переотправить активационное письмо email_not_associate=Этот адрес электронной почты не связан ни с одной учетной записью. +send_reset_mail=Отправить письмо для восстановления аккаунта +reset_password=Восстановление аккаунта invalid_code=Этот код подтверждения недействителен или истек. +reset_password_helper=Восстановить аккаунт +reset_password_wrong_user=Вы вошли как %s, но ссылка для восстановления аккаунта %s password_too_short=Длина пароля не может быть меньше, чем %d символов. non_local_account=Нелокальные аккаунты не могут изменить пароль через Gitea. verify=Проверить @@ -224,6 +235,7 @@ twofa_passcode_incorrect=Ваш пароль неверен. Если вы по twofa_scratch_token_incorrect=Неверный scratch-код. login_userpass=Вход login_openid=OpenID +oauth_signup_tab=Зарегистрировать новый аккаунт oauth_signin_submit=Привязать учетную запись openid_connect_submit=Подключить openid_connect_title=Подключение к существующей учетной записи @@ -231,14 +243,19 @@ openid_connect_desc=Выбранный OpenID URI неизвестен. Свяж openid_register_title=Создать новый аккаунт openid_register_desc=Выбранный OpenID URI неизвестен. Свяжите с новой учетной записью здесь. openid_signin_desc=Введите свой OpenID URI. Например: https://anne.me, bob.openid.org.cn или gnusocial.net/carry. +disable_forgot_password_mail=Восстановление аккаунта отключено. Пожалуйста, свяжитесь с администратором сайта. authorize_application=Авторизация приложения +authroize_redirect_notice=Вы будете перенаправлены на %s, если вы авторизуете это приложение. authorize_application_created_by=Это приложение было создано %s. +authorize_application_description=Если вы предоставите доступ, оно сможет получить доступ и редактировать любую информацию о вашей учетной записи, включая содержимое частных репозиториев и организаций. authorize_title=Разрешить «%s» доступ к вашей учетной записи? authorization_failed=Ошибка авторизации +authorization_failed_desc=Ошибка авторизации, обнаружен неверный запрос. Пожалуйста, свяжитесь с автором приложения, которое вы пытались авторизовать. [mail] activate_account=Пожалуйста активируйте свой аккаунт activate_email=Подтвердите адрес своей электронной почты +reset_password=Восстановить учетную запись register_success=Регистрация прошла успешно register_notify=Добро пожаловать на Gitea @@ -283,6 +300,8 @@ password_not_match=Пароли не совпадают. username_been_taken=Имя пользователя уже занято. repo_name_been_taken=Имя репозитория уже используется. +visit_rate_limit=Удаленный вход отклонён в связи с ограничением количества попыток в секунду. +2fa_auth_required=Удаленный вход требует двухфакторную аутентификацию. org_name_been_taken=Название организации уже занято. team_name_been_taken=Название команды уже занято. team_no_units_error=Разрешите доступ хотя бы к одному разделу репозитория. @@ -364,6 +383,7 @@ choose_new_avatar=Выбрать новый аватар update_avatar=Обновить аватар delete_current_avatar=Удалить текущий аватар uploaded_avatar_not_a_image=Загружаемый файл не является изображением. +uploaded_avatar_is_too_big=Загруженный файл превысил максимальный размер. update_avatar_success=Ваш аватар был изменен. change_password=Обновить пароль @@ -379,6 +399,7 @@ manage_emails=Управление Email адресами manage_themes=Выберите тему по умолчанию manage_openid=Управление OpenID email_desc=Ваш основной адрес электронной почты будет использован для уведомлений и других операций. +theme_desc=Это будет темой по умолчанию для всего сайта. primary=Основной primary_email=Сделать основным delete_email=Удалить @@ -458,7 +479,26 @@ access_token_deletion_desc=Удаление токена отменит дост delete_token_success=Токен удалён. Приложения, использующие его, больше не имеют доступа к вашему аккаунту. manage_oauth2_applications=Управление приложениями OAuth2 +remove_oauth2_application=Удалить OAuth2 приложение +remove_oauth2_application_success=Приложение было удалено. +create_oauth2_application_button=Создать приложение +create_oauth2_application_success=Вы успешно создали новое приложение OAuth2. +update_oauth2_application_success=Изменения настроек приложения OAuth2 успешно применены. +oauth2_application_name=Имя приложения +oauth2_select_type=Какой тип приложения подходит? +oauth2_type_web=Веб (например: Node.JS, Tomcat, Go) +oauth2_type_native=Нативный (например: телефон, ПК, браузер) +oauth2_redirect_uri=URI переадресации +save_application=Сохранить +oauth2_client_secret=Клиентский ключ +oauth2_regenerate_secret=Сгенерировать новый ключ +oauth2_regenerate_secret_hint=Потеряли свой ключ? +oauth2_client_secret_hint=Секретный ключ не будет показан, если вы повторно откроете эту страницу. Пожалуйста сохраните секретный ключ. +authorized_oauth2_applications=Авторизованные приложения OAuth2 +revoke_key=Отозвать +revoke_oauth2_grant=Отозвать доступ +revoke_oauth2_grant_success=Вы успешно отозвали доступ. twofa_desc=Двухфакторная проверка подлинности повышает уровень безопасности вашей учётной записи. twofa_is_enrolled=Ваша учётная запись в настоящее время использует двухфакторную аутентификацию. @@ -546,6 +586,12 @@ form.name_pattern_not_allowed=Шаблон имени репозитория '%s need_auth=Требуется авторизация migrate_type=Тип миграции migrate_type_helper=Этот репозиторий будет зеркалом +migrate_items_wiki=Вики +migrate_items_milestones=Этапы +migrate_items_labels=Метки +migrate_items_issues=Задачи +migrate_items_pullrequests=Запросы на слияние +migrate_items_releases=Релизы migrate_repo=Перенос репозитория migrate.clone_address=Перенос / Клонирование по URL migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT адрес или локальный путь существующего репозитория на сервере. @@ -627,11 +673,14 @@ editor.create_new_branch=Создайте новую ветку editor.new_branch_name_desc=Новое название ветки… editor.cancel=Отмена editor.filename_cannot_be_empty=Имя файла не может быть пустым. +editor.filename_is_invalid=Недопустимое имя файла: '%s'. +editor.branch_does_not_exist=Ветка '%s' отсутствует в этом репозитории. editor.branch_already_exists=Ветка «%s» уже существует в этом репозитории. editor.directory_is_a_file=Имя каталога '%s' уже используется в качестве имени файла в этом репозитории. editor.file_is_a_symlink='%s' является символической ссылкой. Символические ссылки нельзя редактировать в веб-редакторе editor.filename_is_a_directory=Имя файла '%s' уже используется в качестве имени каталога в этом репозитории. editor.file_editing_no_longer_exists=Редактируемый файл '%s' больше не существует в этом репозитории. +editor.file_deleting_no_longer_exists=Удаляемый файл '%s' больше не существует в этом репозитории. editor.file_changed_while_editing=Содержимое файла изменилось с момента начала редактирования.
    Нажмите здесь, чтобы увидеть, что было изменено, или Зафиксировать изменения снова, чтобы заменить их. editor.file_already_exists=Файл с именем '%s' уже существует в репозитории. editor.no_changes_to_show=Нет изменений. @@ -643,6 +692,7 @@ editor.cannot_commit_to_protected_branch=Нельзя коммитить в за commits.desc=Просмотр истории изменений исходного кода. commits.commits=коммитов +commits.no_commits=Ничего общего в коммитах. '%s' и '%s' имеют совершенно разные истории. commits.search=Поиск коммитов… commits.find=Поиск commits.search_all=Все ветки @@ -712,6 +762,8 @@ issues.filter_sort.recentupdate=Недавно обновленные issues.filter_sort.leastupdate=Давно обновленные issues.filter_sort.mostcomment=Больше комментариев issues.filter_sort.leastcomment=Меньше комментариев +issues.filter_sort.nearduedate=Ближайшее по дате завершения +issues.filter_sort.farduedate=Удалённое по дате завершения issues.filter_sort.moststars=Больше звезд issues.filter_sort.feweststars=Меньше звезд issues.filter_sort.mostforks=Больше форков @@ -727,6 +779,7 @@ issues.opened_by=открыта %[1]s %[3]s pulls.merged_by=принят %[1]s %[3]s issues.closed_by=закрыта %[1]s %[3]s issues.opened_by_fake=%[1]s открыта %[2]s +issues.closed_by_fake=%[1]s закрыта пользователем %[2]s issues.previous=Предыдущая страница issues.next=Следующая страница issues.open_title=Открыто @@ -906,6 +959,7 @@ milestones.no_due_date=Срок не указан milestones.open=Открыть milestones.close=Закрыть milestones.new_subheader=Создавайте этапы для организации ваших задач. +milestones.completeness=%d%% выполнено milestones.create=Создать этап milestones.title=Заголовок milestones.desc=Описание @@ -992,6 +1046,7 @@ activity.title.releases_1=%d релиз activity.title.releases_n=%d релизов activity.title.releases_published_by=%s опубликованы %s activity.published_release_label=Опубликовано +activity.no_git_activity=В этот период не было новых коммитов. search=Поиск search.search_repo=Поиск по репозиторию @@ -1102,6 +1157,7 @@ settings.githook_content=Перехватить содержание settings.update_githook=Обновить Hook settings.add_webhook_desc=Gitea будет оправлять POST запросы на указанный URL адрес, с информацией о происходящих событиях. Подробности на странице инструкции по использованию webhooks. settings.payload_url=URL обработчика +settings.http_method=Метод HTTP settings.content_type=Тип содержимого settings.secret=Секретный ключ settings.slack_username=Имя пользователя @@ -1145,6 +1201,8 @@ settings.slack_domain=Домен settings.slack_channel=Канал settings.add_discord_hook_desc=Добавить уведомления о событиях через Discord. settings.add_dingtalk_hook_desc=Добавить интеграцию с Dingtalk в ваш репозиторий. +settings.add_telegram_hook_desc=Добавить интеграцию с Telegram в ваш репозиторий. +settings.add_msteams_hook_desc=Добавить интеграцию с Microsoft Teams в ваш репозиторий. settings.deploy_keys=Ключи развертывания settings.add_deploy_key=Добавить ключ развертывания settings.deploy_key_desc=Ключи развёртывания доступны только для чтения. Это не то же самое что и SSH-ключи аккаунта. @@ -1166,7 +1224,9 @@ settings.protected_branch_can_push_yes=Вы можете выполнять push settings.protected_branch_can_push_no=Вы не можете выполнять push settings.branch_protection=Защита ветки %s settings.protect_this_branch=Защитить эту ветку +settings.protect_this_branch_desc=Запретить push в ветку и защитить от удаления. settings.protect_whitelist_committers=Белый список тех, кто может делать push в эту ветку +settings.protect_whitelist_committers_desc=Разрешить push в эту ветку пользователям или командам из «белого» списка (но не принудительный push). settings.protect_whitelist_users=Пользователи, которые могут делать push в эту ветку: settings.protect_whitelist_search_users=Поиск пользователей… settings.protect_whitelist_teams=Команды, члены которых могут делать push в эту ветку: @@ -1190,6 +1250,8 @@ settings.choose_branch=Выберите ветку… settings.no_protected_branch=Нет защищённых веток. settings.edit_protected_branch=Редактировать settings.protected_branch_required_approvals_min=Число необходимых одобрений не может быть отрицательным. +settings.bot_token=Токен для бота +settings.chat_id=ID чата settings.archive.button=Архивировать репозиторий settings.archive.header=Архивировать этот репозиторий settings.archive.text=Архивация репозитория переведет его в режим read-only. Он будет скрыт из панели управления, создание задач, запросов на слияние, или создание коммитов будут запрещены. @@ -1198,7 +1260,7 @@ settings.archive.error_ismirror=Вы не можете поместить зер settings.unarchive.button=Разархивировать settings.unarchive.header=Разархивировать этот репозиторий settings.unarchive.success=Репозиторий был успешно разархивирован. -settings.unarchive.error=Ошибка при попытке разархивировать репозиторий. Смотрите логи для получения подробностей. +settings.update_avatar_success=Аватар репозитория обновлен. diff.browse_source=Просмотр исходного кода diff.parent=Родитель diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 1a2ed9fc1f..da23f30fb6 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -480,7 +480,6 @@ manage_oauth2_applications=管理 OAuth2 应用程序 edit_oauth2_application=编辑 OAuth2 应用程序 oauth2_applications_desc=OAuth2 应用允许第三方应用程序在此 Gitea 实例中安全验证用户。 remove_oauth2_application=删除 OAuth2 应用程序 -remove_oauth2_application_desc=删除 OAuth2 应用将撤销所有签名访问令牌。继续吗? remove_oauth2_application_success=该应用已被删除。 create_oauth2_application=创建新的 OAuth2 应用程序 create_oauth2_application_button=创建应用 @@ -612,7 +611,6 @@ migrate.permission_denied=您没有获得导入本地仓库的权限。 migrate.invalid_local_path=无效的本地路径,不存在或不是一个目录! migrate.failed=迁移失败:%v migrate.lfs_mirror_unsupported=不支持镜像 LFS 对象 - 使用 'git lfs fetch --all' 和 'git lfs push --all' 替代。 -migrate.migrate_items_options=当您正在从 github 迁移并且输入了用户名时,迁移选项将会显示。 mirror_from=镜像自地址 forked_from=派生自 @@ -1299,14 +1297,11 @@ settings.archive.button=归档仓库 settings.archive.header=归档此仓库 settings.archive.text=归档后仓库将只有只读权限,并在仪表盘中被隐藏。你将不能再对其建立提交、创建工单或建立合并请求。 settings.archive.success=仓库已成功归档。 -settings.archive.error=仓库在归档时出现异常。请通过日志获取详细信息。 settings.archive.error_ismirror=请不要对镜像仓库归档,谢谢! settings.archive.branchsettings_unavailable=已归档仓库无法进行分支设置。 settings.unarchive.button=撤销仓库归档 settings.unarchive.header=撤销此仓库归档 -settings.unarchive.text=取消存档将恢复仓库接收提交,推送,新工单和合并请求。 settings.unarchive.success=仓库已成功取消归档。 -settings.unarchive.error=仓库在撤销归档时出现异常。请通过日志获取详细信息。 diff.browse_source=浏览代码 diff.parent=父节点 From de6539fc8c37485afcd6f30092a9ccbc3cae7de5 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Thu, 6 Jun 2019 01:37:45 +0100 Subject: [PATCH 091/220] Add state param to milestone listing API (#7131) * Support state params * update tests * fix tests * add state=all support * update tests * update swagger * update swagger --- models/fixtures/milestone.yml | 8 +++++++ models/fixtures/repository.yml | 5 +++-- models/issue_milestone.go | 22 ++++++++++++++++--- models/issue_milestone_test.go | 37 ++++++++++++++++++++++++++------ modules/structs/issue.go | 2 ++ routers/api/v1/repo/milestone.go | 8 +++++-- routers/repo/issue.go | 3 ++- templates/swagger/v1_json.tmpl | 6 ++++++ 8 files changed, 76 insertions(+), 15 deletions(-) diff --git a/models/fixtures/milestone.yml b/models/fixtures/milestone.yml index 8192c4fbe1..15f422fc3b 100644 --- a/models/fixtures/milestone.yml +++ b/models/fixtures/milestone.yml @@ -13,3 +13,11 @@ content: content2 is_closed: false num_issues: 0 + +- + id: 3 + repo_id: 1 + name: milestone3 + content: content3 + is_closed: true + num_issues: 0 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 083182e2bc..609f421a90 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -8,7 +8,8 @@ num_closed_issues: 1 num_pulls: 2 num_closed_pulls: 0 - num_milestones: 2 + num_milestones: 3 + num_closed_milestones: 1 num_watches: 3 - @@ -495,4 +496,4 @@ num_stars: 0 num_forks: 0 num_issues: 0 - is_mirror: false \ No newline at end of file + is_mirror: false diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 3bde4b558c..f279dda195 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -190,10 +190,26 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 { } // GetMilestonesByRepoID returns all opened milestones of a repository. -func GetMilestonesByRepoID(repoID int64) (MilestoneList, error) { +func GetMilestonesByRepoID(repoID int64, state api.StateType) (MilestoneList, error) { + + sess := x.Where("repo_id = ?", repoID) + + switch state { + case api.StateClosed: + sess = sess.And("is_closed = ?", true) + + case api.StateAll: + break + + case api.StateOpen: + fallthrough + + default: + sess = sess.And("is_closed = ?", false) + } + miles := make([]*Milestone, 0, 10) - return miles, x.Where("repo_id = ? AND is_closed = ?", repoID, false). - Asc("deadline_unix").Asc("id").Find(&miles) + return miles, sess.Asc("deadline_unix").Asc("id").Find(&miles) } // GetMilestones returns a list of milestones of given repository and status. diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go index fb1ee8b7a5..f9e51aff31 100644 --- a/models/issue_milestone_test.go +++ b/models/issue_milestone_test.go @@ -69,20 +69,43 @@ func TestGetMilestoneByRepoID(t *testing.T) { func TestGetMilestonesByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - test := func(repoID int64) { + test := func(repoID int64, state api.StateType) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) - milestones, err := GetMilestonesByRepoID(repo.ID) + milestones, err := GetMilestonesByRepoID(repo.ID, state) assert.NoError(t, err) - assert.Len(t, milestones, repo.NumMilestones) + + var n int + + switch state { + case api.StateClosed: + n = repo.NumClosedMilestones + + case api.StateAll: + n = repo.NumMilestones + + case api.StateOpen: + fallthrough + + default: + n = repo.NumOpenMilestones + } + + assert.Len(t, milestones, n) for _, milestone := range milestones { assert.EqualValues(t, repoID, milestone.RepoID) } } - test(1) - test(2) - test(3) + test(1, api.StateOpen) + test(1, api.StateAll) + test(1, api.StateClosed) + test(2, api.StateOpen) + test(2, api.StateAll) + test(2, api.StateClosed) + test(3, api.StateOpen) + test(3, api.StateClosed) + test(3, api.StateAll) - milestones, err := GetMilestonesByRepoID(NonexistentID) + milestones, err := GetMilestonesByRepoID(NonexistentID, api.StateOpen) assert.NoError(t, err) assert.Len(t, milestones, 0) } diff --git a/modules/structs/issue.go b/modules/structs/issue.go index af6aa6e541..6d7517bdc7 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -16,6 +16,8 @@ const ( StateOpen StateType = "open" // StateClosed pr is closed StateClosed StateType = "closed" + // StateAll is all + StateAll StateType = "all" ) // PullRequestMeta PR info if an issue is a PR diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go index 1d01093306..14030a2186 100644 --- a/routers/api/v1/repo/milestone.go +++ b/routers/api/v1/repo/milestone.go @@ -14,7 +14,7 @@ import ( api "code.gitea.io/gitea/modules/structs" ) -// ListMilestones list all the opened milestones for a repository +// ListMilestones list milestones for a repository func ListMilestones(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/milestones issue issueGetMilestonesList // --- @@ -32,10 +32,14 @@ func ListMilestones(ctx *context.APIContext) { // description: name of the repo // type: string // required: true + // - name: state + // in: query + // description: Milestone state, Recognised values are open, closed and all. Defaults to "open" + // type: string // responses: // "200": // "$ref": "#/responses/MilestoneList" - milestones, err := models.GetMilestonesByRepoID(ctx.Repo.Repository.ID) + milestones, err := models.GetMilestonesByRepoID(ctx.Repo.Repository.ID, api.StateType(ctx.Query("state"))) if err != nil { ctx.Error(500, "GetMilestonesByRepoID", err) return diff --git a/routers/repo/issue.go b/routers/repo/issue.go index c2749fcb47..f6030c9823 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" @@ -305,7 +306,7 @@ func Issues(ctx *context.Context) { var err error // Get milestones. - ctx.Data["Milestones"], err = models.GetMilestonesByRepoID(ctx.Repo.Repository.ID) + ctx.Data["Milestones"], err = models.GetMilestonesByRepoID(ctx.Repo.Repository.ID, api.StateType(ctx.Query("state"))) if err != nil { ctx.ServerError("GetAllRepoMilestones", err) return diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 77515bb139..0bd85fbb6e 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -3892,6 +3892,12 @@ "name": "repo", "in": "path", "required": true + }, + { + "type": "string", + "description": "Milestone state, Recognised values are open, closed and all. Defaults to \"open\"", + "name": "state", + "in": "query" } ], "responses": { From dadc03f5ff07b0aa857ceccaa655bb4fb6e41494 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 6 Jun 2019 00:40:56 +0000 Subject: [PATCH 092/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 9 +++++---- options/locale/locale_pt-BR.ini | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 28a3952bfa..d620ebaddd 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -27,10 +27,11 @@ password=Contraseña re_type=Vuelva a escribir la contraseña captcha=CAPTCHA twofa=Autenticación de doble factor +twofa_scratch=Código de autenticación de doble factor de un sólo uso passcode=Contraseña u2f_insert_key=Inserte su clave de seguridad -u2f_use_twofa=Use un código de dos factores de su celular +u2f_use_twofa=Use un código de doble factor de su celular u2f_reload=Recargar repository=Repositorio @@ -91,7 +92,7 @@ disable_gravatar=Desactivar Gravatar federated_avatar_lookup_popup=Habilitar búsqueda de avatares federador para usar el servicio federado de código abierto basado en libravatar. enable_captcha=Activar CAPTCHA enable_captcha_popup=Requerir CAPTCHA para auto-registro de usuario. -require_sign_in_view=Debes iniciar sesión para ver las páginas +require_sign_in_view=Requerir inicio de sesión para ver páginas admin_password=Contraseña confirm_password=Confirmar Contraseña admin_email=Correo electrónico @@ -107,7 +108,7 @@ invalid_log_root_path=La ruta para los registros no es válida: %v default_keep_email_private=Ocultar direcciones de correo electrónico por defecto default_keep_email_private_popup=Ocultar direcciones de correo electrónico de nuevas cuentas de usuario por defecto. default_allow_create_organization=Permitir la creación de organizaciones por defecto -default_allow_create_organization_popup=Permitir crear organizaciones a las nuevas cuentas de usuario de forma predeterminada. +default_allow_create_organization_popup=Permitir que las nuevas cuentas de usuario creen organizaciones por defecto. default_enable_timetracking=Activar el seguimiento de tiempo por defecto default_enable_timetracking_popup=Activar el seguimiento de tiempo para nuevos repositorios por defecto. no_reply_address=Dominio de correos electrónicos ocultos @@ -345,7 +346,7 @@ unwatch=Dejar de seguir watch=Seguir unstar=Eliminar de favoritos star=Destacar -fork=Bifurcar +fork=Fork no_desc=Sin descripción quick_guide=Guía rápida diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index f68098b2f8..435b51552e 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -487,6 +487,7 @@ manage_oauth2_applications=Gerenciar aplicativos OAuth2 edit_oauth2_application=Editar aplicativo OAuth2 oauth2_applications_desc=Aplicativos OAuth2 permitem que seus aplicativos de terceiros autentiquem com segurança usuários nesta instância do Gitea. remove_oauth2_application=Remover aplicativo OAuth2 +remove_oauth2_application_desc=Remover um aplicativo OAuth2 irá revogar o acesso a todos os tokens de acesso assinados. Continuar? remove_oauth2_application_success=O aplicativo foi excluído. create_oauth2_application=Criar um novo aplicativo OAuth2 create_oauth2_application_button=Criar aplicativo @@ -618,6 +619,7 @@ migrate.permission_denied=Você não pode importar repositórios locais. migrate.invalid_local_path=O caminho local é inválido. Ele não existe ou não é um diretório. migrate.failed=Migração falhou: %v migrate.lfs_mirror_unsupported=Espelhamento de objetos Git LFS não é suportado; ao invés use 'git lfs fetch --all' e 'git lfs push --all'. +migrate.migrate_items_options=Ao migrar do github, insira um nome de usuário e as opções de migração serão exibidas. mirror_from=espelhamento de forked_from=feito fork de @@ -1304,11 +1306,14 @@ settings.archive.button=Arquivar repositório settings.archive.header=Arquivar este repositório settings.archive.text=Arquivando um repositório fará com que o mesmo fique inteiramente em modo somente leitura. Ele ficará oculto no painel, não poderá receber commits e nem será possível criar issues e pull requests. settings.archive.success=O repositório foi arquivado com sucesso. +settings.archive.error=Um erro ocorreu enquanto estava sendo arquivado o repositório. Veja o log para mais detalhes. settings.archive.error_ismirror=Você não pode arquivar um repositório espelhado. settings.archive.branchsettings_unavailable=Configurações do branch não estão disponíveis quando o repositório está arquivado. settings.unarchive.button=Desarquivar repositório settings.unarchive.header=Desarquivar este repositório +settings.unarchive.text=Desarquivando um repositório irá restaurar a capacidade do mesmo receber commits, pushs, assim como novas issues e pull requests. settings.unarchive.success=O repositório foi desarquivado com sucesso. +settings.unarchive.error=Um erro ocorreu enquanto estava sendo desarquivado o repositório. Veja o log para mais detalhes. settings.update_avatar_success=O avatar do repositório foi atualizado. diff.browse_source=Ver código fonte From bd55f6ff36d40503bfa3407225780d0ab7d37930 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 6 Jun 2019 06:54:25 +0100 Subject: [PATCH 093/220] Detect noreply email address as user (#7133) --- models/user.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/models/user.go b/models/user.go index 9ee27ddfbd..e29cf5b32a 100644 --- a/models/user.go +++ b/models/user.go @@ -1334,6 +1334,19 @@ func GetUserByEmail(email string) (*User, error) { return GetUserByID(emailAddress.UID) } + // Finally, if email address is the protected email address: + if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { + username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) + user := &User{LowerName: username} + has, err := x.Get(user) + if err != nil { + return nil, err + } + if has { + return user, nil + } + } + return nil, ErrUserNotExist{0, email, 0} } From 311ce2d1d06c26d0d5a3b745493995813e2ea6f2 Mon Sep 17 00:00:00 2001 From: Mario Lubenka Date: Fri, 7 Jun 2019 22:29:29 +0200 Subject: [PATCH 094/220] Compare branches, commits and tags with each other (#6991) * Supports tags when comparing commits or branches Signed-off-by: Mario Lubenka * Hide headline when only comparing and don't load unused data Signed-off-by: Mario Lubenka * Merges compare logics to allow comparing branches, commits and tags with eachother Signed-off-by: Mario Lubenka * Display branch or tag instead of commit when used for comparing Signed-off-by: Mario Lubenka * Show pull request form after click on button Signed-off-by: Mario Lubenka * Transfers relevant pull.go changes from master to compare.go Signed-off-by: Mario Lubenka * Fixes error when comparing forks against a commit or tag Signed-off-by: Mario Lubenka * Removes console.log from JavaScript file Signed-off-by: Mario Lubenka * Show icon next to commit reference when comparing branch or tag Signed-off-by: Mario Lubenka * Updates css file Signed-off-by: Mario Lubenka * Fixes import order * Renames template variable * Update routers/repo/compare.go Co-Authored-By: zeripath * Update from master Signed-off-by: Mario Lubenka * Allow short-shas in compare * Renames prInfo to compareInfo Signed-off-by: Mario Lubenka * Check PR permissions only if compare is pull request Signed-off-by: Mario Lubenka * Adjusts comment Signed-off-by: Mario Lubenka * Use compareInfo instead of prInfo --- models/pull.go | 3 +- modules/git/repo_commit.go | 10 + modules/git/{repo_pull.go => repo_compare.go} | 54 +-- ...repo_pull_test.go => repo_compare_test.go} | 0 public/css/index.css | 1 + public/js/index.js | 9 +- public/less/_repository.less | 3 + routers/api/v1/repo/pull.go | 14 +- routers/repo/commit.go | 59 +-- routers/repo/compare.go | 337 ++++++++++++++++++ routers/repo/pull.go | 278 +-------------- routers/routes/routes.go | 9 +- templates/repo/commit_page.tmpl | 89 +++++ templates/repo/commits_table.tmpl | 8 +- templates/repo/diff/compare.tmpl | 74 ++++ templates/repo/diff/page.tmpl | 94 ----- templates/repo/pulls/compare.tmpl | 69 ---- 17 files changed, 584 insertions(+), 527 deletions(-) rename modules/git/{repo_pull.go => repo_compare.go} (55%) rename modules/git/{repo_pull_test.go => repo_compare_test.go} (100%) create mode 100644 routers/repo/compare.go create mode 100644 templates/repo/commit_page.tmpl create mode 100644 templates/repo/diff/compare.tmpl delete mode 100644 templates/repo/diff/page.tmpl delete mode 100644 templates/repo/pulls/compare.tmpl diff --git a/models/pull.go b/models/pull.go index fe18765fc0..5ac1126314 100644 --- a/models/pull.go +++ b/models/pull.go @@ -1144,8 +1144,7 @@ func (pr *PullRequest) UpdatePatch() (err error) { defer func() { headGitRepo.RemoveRemote(tmpRemote) }() - remoteBranch := "remotes/" + tmpRemote + "/" + pr.BaseBranch - pr.MergeBase, err = headGitRepo.GetMergeBase(remoteBranch, pr.HeadBranch) + pr.MergeBase, err = headGitRepo.GetMergeBase(tmpRemote, pr.BaseBranch, pr.HeadBranch) if err != nil { return fmt.Errorf("GetMergeBase: %v", err) } else if err = pr.Update(); err != nil { diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index b631f9341e..501ea88e40 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -27,6 +27,16 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) { return ref.Hash().String(), nil } +// IsCommitExist returns true if given commit exists in current repository. +func (repo *Repository) IsCommitExist(name string) bool { + hash := plumbing.NewHash(name) + _, err := repo.gogitRepo.CommitObject(hash) + if err != nil { + return false + } + return true +} + // GetBranchCommitID returns last commit ID string of given branch. func (repo *Repository) GetBranchCommitID(name string) (string, error) { return repo.GetRefCommitID(BranchPrefix + name) diff --git a/modules/git/repo_pull.go b/modules/git/repo_compare.go similarity index 55% rename from modules/git/repo_pull.go rename to modules/git/repo_compare.go index 65c5414551..e7a1d72a85 100644 --- a/modules/git/repo_pull.go +++ b/modules/git/repo_compare.go @@ -1,4 +1,5 @@ // Copyright 2015 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -14,55 +15,66 @@ import ( "time" ) -// PullRequestInfo represents needed information for a pull request. -type PullRequestInfo struct { +// CompareInfo represents needed information for comparing references. +type CompareInfo struct { MergeBase string Commits *list.List NumFiles int } // GetMergeBase checks and returns merge base of two branches. -func (repo *Repository) GetMergeBase(base, head string) (string, error) { +func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (string, error) { + if tmpRemote == "" { + tmpRemote = "origin" + } + + if tmpRemote != "origin" { + tmpBaseName := "refs/remotes/" + tmpRemote + "/tmp_" + base + // Fetch commit into a temporary branch in order to be able to handle commits and tags + _, err := NewCommand("fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path) + if err == nil { + base = tmpBaseName + } + } + stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path) return strings.TrimSpace(stdout), err } -// GetPullRequestInfo generates and returns pull request information -// between base and head branches of repositories. -func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch string) (_ *PullRequestInfo, err error) { - var remoteBranch string +// GetCompareInfo generates and returns compare information between base and head branches of repositories. +func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string) (_ *CompareInfo, err error) { + var ( + remoteBranch string + tmpRemote string + ) // We don't need a temporary remote for same repository. if repo.Path != basePath { // Add a temporary remote - tmpRemote := strconv.FormatInt(time.Now().UnixNano(), 10) + tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10) if err = repo.AddRemote(tmpRemote, basePath, true); err != nil { return nil, fmt.Errorf("AddRemote: %v", err) } defer repo.RemoveRemote(tmpRemote) - - remoteBranch = "remotes/" + tmpRemote + "/" + baseBranch - } else { - remoteBranch = baseBranch } - prInfo := new(PullRequestInfo) - prInfo.MergeBase, err = repo.GetMergeBase(remoteBranch, headBranch) + compareInfo := new(CompareInfo) + compareInfo.MergeBase, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch) if err == nil { // We have a common base - logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) + logs, err := NewCommand("log", compareInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) if err != nil { return nil, err } - prInfo.Commits, err = repo.parsePrettyFormatLogToList(logs) + compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs) if err != nil { return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) } } else { - prInfo.Commits = list.New() - prInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch) + compareInfo.Commits = list.New() + compareInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch) if err != nil { - prInfo.MergeBase = remoteBranch + compareInfo.MergeBase = remoteBranch } } @@ -71,9 +83,9 @@ func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch stri if err != nil { return nil, err } - prInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1 + compareInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1 - return prInfo, nil + return compareInfo, nil } // GetPatch generates and returns patch data between given revisions. diff --git a/modules/git/repo_pull_test.go b/modules/git/repo_compare_test.go similarity index 100% rename from modules/git/repo_pull_test.go rename to modules/git/repo_compare_test.go diff --git a/public/css/index.css b/public/css/index.css index 8950cc7038..d192f43d15 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -591,6 +591,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .milestone.list>.item .content{padding-top:10px} .repository.new.milestone textarea{height:200px} .repository.new.milestone #deadline{width:150px} +.repository.compare.pull .show-form-container{text-align:left} .repository.compare.pull .choose.branch .octicon{padding-right:10px} .repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none} .repository.compare.pull .comment.form .content:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} diff --git a/public/js/index.js b/public/js/index.js index ed3198594a..28023e1061 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -959,8 +959,15 @@ function initRepository() { }); // Pull request - if ($('.repository.compare.pull').length > 0) { + var $repoComparePull = $('.repository.compare.pull'); + if ($repoComparePull.length > 0) { initFilterSearchDropdown('.choose.branch .dropdown'); + // show pull request form + $repoComparePull.find('button.show-form').on('click', function(e) { + e.preventDefault(); + $repoComparePull.find('.pullrequest-form').show(); + $(this).parent().hide(); + }); } // Branches diff --git a/public/less/_repository.less b/public/less/_repository.less index 9956bbce74..fcc153e31e 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -1109,6 +1109,9 @@ } &.compare.pull { + .show-form-container { + text-align: left; + } .choose.branch { .octicon { padding-right: 10px; diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index f53ab4b8f3..0e1db144b1 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -188,7 +188,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption ) // Get repo/branch information - headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := parseCompareInfo(ctx, form) + headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := parseCompareInfo(ctx, form) if ctx.Written() { return } @@ -240,7 +240,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption milestoneID = milestone.ID } - patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch) + patch, err := headGitRepo.GetPatch(compareInfo.MergeBase, headBranch) if err != nil { ctx.Error(500, "GetPatch", err) return @@ -277,7 +277,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption BaseBranch: baseBranch, HeadRepo: headRepo, BaseRepo: repo, - MergeBase: prInfo.MergeBase, + MergeBase: compareInfo.MergeBase, Type: models.PullRequestGitea, } @@ -600,7 +600,7 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) { ctx.Status(200) } -func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) { +func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) { baseRepo := ctx.Repo.Repository // Get compared branches information @@ -712,11 +712,11 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) return nil, nil, nil, nil, "", "" } - prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch) + compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch) if err != nil { - ctx.Error(500, "GetPullRequestInfo", err) + ctx.Error(500, "GetCompareInfo", err) return nil, nil, nil, nil, "", "" } - return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch + return headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch } diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 870ff568f3..dde6d8f321 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -19,9 +19,9 @@ import ( ) const ( - tplCommits base.TplName = "repo/commits" - tplGraph base.TplName = "repo/graph" - tplDiff base.TplName = "repo/diff/page" + tplCommits base.TplName = "repo/commits" + tplGraph base.TplName = "repo/graph" + tplCommitPage base.TplName = "repo/commit_page" ) // RefCommits render commits page @@ -261,7 +261,7 @@ func Diff(ctx *context.Context) { } ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", commitID) ctx.Data["BranchName"], err = commit.GetBranchName() - ctx.HTML(200, tplDiff) + ctx.HTML(200, tplCommitPage) } // RawDiff dumps diff results of repository in given commit ID to io.Writer @@ -276,54 +276,3 @@ func RawDiff(ctx *context.Context) { return } } - -// CompareDiff show different from one commit to another commit -func CompareDiff(ctx *context.Context) { - ctx.Data["IsRepoToolbarCommits"] = true - ctx.Data["IsDiffCompare"] = true - userName := ctx.Repo.Owner.Name - repoName := ctx.Repo.Repository.Name - beforeCommitID := ctx.Params(":before") - afterCommitID := ctx.Params(":after") - - commit, err := ctx.Repo.GitRepo.GetCommit(afterCommitID) - if err != nil { - ctx.NotFound("GetCommit", err) - return - } - - diff, err := models.GetDiffRange(models.RepoPath(userName, repoName), beforeCommitID, - afterCommitID, setting.Git.MaxGitDiffLines, - setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) - if err != nil { - ctx.NotFound("GetDiffRange", err) - return - } - - commits, err := commit.CommitsBeforeUntil(beforeCommitID) - if err != nil { - ctx.ServerError("CommitsBeforeUntil", err) - return - } - commits = models.ValidateCommitsWithEmails(commits) - commits = models.ParseCommitsWithSignature(commits) - commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository) - - ctx.Data["CommitRepoLink"] = ctx.Repo.RepoLink - ctx.Data["Commits"] = commits - ctx.Data["CommitCount"] = commits.Len() - ctx.Data["BeforeCommitID"] = beforeCommitID - ctx.Data["AfterCommitID"] = afterCommitID - ctx.Data["Username"] = userName - ctx.Data["Reponame"] = repoName - ctx.Data["IsImageFile"] = commit.IsImageFile - ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID) + " · " + userName + "/" + repoName - ctx.Data["Commit"] = commit - ctx.Data["Diff"] = diff - ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 - ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", afterCommitID) - ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", beforeCommitID) - ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", afterCommitID) - ctx.Data["RequireHighlightJS"] = true - ctx.HTML(200, tplDiff) -} diff --git a/routers/repo/compare.go b/routers/repo/compare.go new file mode 100644 index 0000000000..a85084791d --- /dev/null +++ b/routers/repo/compare.go @@ -0,0 +1,337 @@ +// Copyright 2019 The Gitea 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 repo + +import ( + "path" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +const ( + tplCompare base.TplName = "repo/diff/compare" +) + +// ParseCompareInfo parse compare info between two commit for preparing comparing references +func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) { + baseRepo := ctx.Repo.Repository + + // Get compared branches information + // format: ...[:] + // base<-head: master...head:feature + // same repo: master...feature + + var ( + headUser *models.User + headBranch string + isSameRepo bool + infoPath string + err error + ) + infoPath = ctx.Params("*") + infos := strings.Split(infoPath, "...") + if len(infos) != 2 { + log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos) + ctx.NotFound("CompareAndPullRequest", nil) + return nil, nil, nil, nil, "", "" + } + + baseBranch := infos[0] + ctx.Data["BaseBranch"] = baseBranch + + // If there is no head repository, it means compare between same repository. + headInfos := strings.Split(infos[1], ":") + if len(headInfos) == 1 { + isSameRepo = true + headUser = ctx.Repo.Owner + headBranch = headInfos[0] + + } else if len(headInfos) == 2 { + headUser, err = models.GetUserByName(headInfos[0]) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.NotFound("GetUserByName", nil) + } else { + ctx.ServerError("GetUserByName", err) + } + return nil, nil, nil, nil, "", "" + } + headBranch = headInfos[1] + isSameRepo = headUser.ID == ctx.Repo.Owner.ID + } else { + ctx.NotFound("CompareAndPullRequest", nil) + return nil, nil, nil, nil, "", "" + } + ctx.Data["HeadUser"] = headUser + ctx.Data["HeadBranch"] = headBranch + ctx.Repo.PullRequest.SameRepo = isSameRepo + + // Check if base branch is valid. + baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(baseBranch) + baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(baseBranch) + baseIsTag := ctx.Repo.GitRepo.IsTagExist(baseBranch) + if !baseIsCommit && !baseIsBranch && !baseIsTag { + // Check if baseBranch is short sha commit hash + if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(baseBranch); baseCommit != nil { + baseBranch = baseCommit.ID.String() + ctx.Data["BaseBranch"] = baseBranch + baseIsCommit = true + } else { + ctx.NotFound("IsRefExist", nil) + return nil, nil, nil, nil, "", "" + } + } + ctx.Data["BaseIsCommit"] = baseIsCommit + ctx.Data["BaseIsBranch"] = baseIsBranch + ctx.Data["BaseIsTag"] = baseIsTag + + // Check if current user has fork of repository or in the same repository. + headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID) + if !has && !isSameRepo { + ctx.Data["PageIsComparePull"] = false + } + + var headGitRepo *git.Repository + if isSameRepo { + headRepo = ctx.Repo.Repository + headGitRepo = ctx.Repo.GitRepo + ctx.Data["BaseName"] = headUser.Name + } else { + headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name)) + ctx.Data["BaseName"] = baseRepo.OwnerName + if err != nil { + ctx.ServerError("OpenRepository", err) + return nil, nil, nil, nil, "", "" + } + } + + // user should have permission to read baseRepo's codes and pulls, NOT headRepo's + permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return nil, nil, nil, nil, "", "" + } + if !permBase.CanRead(models.UnitTypeCode) { + if log.IsTrace() { + log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in baseRepo has Permissions: %-+v", + ctx.User, + baseRepo, + permBase) + } + ctx.NotFound("ParseCompareInfo", nil) + return nil, nil, nil, nil, "", "" + } + + // user should have permission to read headrepo's codes + permHead, err := models.GetUserRepoPermission(headRepo, ctx.User) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return nil, nil, nil, nil, "", "" + } + if !permHead.CanRead(models.UnitTypeCode) { + if log.IsTrace() { + log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v", + ctx.User, + headRepo, + permHead) + } + ctx.NotFound("ParseCompareInfo", nil) + return nil, nil, nil, nil, "", "" + } + + // Check if head branch is valid. + headIsCommit := ctx.Repo.GitRepo.IsCommitExist(headBranch) + headIsBranch := headGitRepo.IsBranchExist(headBranch) + headIsTag := headGitRepo.IsTagExist(headBranch) + if !headIsCommit && !headIsBranch && !headIsTag { + // Check if headBranch is short sha commit hash + if headCommit, _ := ctx.Repo.GitRepo.GetCommit(headBranch); headCommit != nil { + headBranch = headCommit.ID.String() + ctx.Data["HeadBranch"] = headBranch + headIsCommit = true + } else { + ctx.NotFound("IsRefExist", nil) + return nil, nil, nil, nil, "", "" + } + } + ctx.Data["HeadIsCommit"] = headIsCommit + ctx.Data["HeadIsBranch"] = headIsBranch + ctx.Data["HeadIsTag"] = headIsTag + + // Treat as pull request if both references are branches + if ctx.Data["PageIsComparePull"] == nil { + ctx.Data["PageIsComparePull"] = headIsBranch && baseIsBranch + } + + if ctx.Data["PageIsComparePull"] == true && !permBase.CanReadIssuesOrPulls(true) { + if log.IsTrace() { + log.Trace("Permission Denied: User: %-v cannot create/read pull requests in Repo: %-v\nUser in baseRepo has Permissions: %-+v", + ctx.User, + baseRepo, + permBase) + } + ctx.NotFound("ParseCompareInfo", nil) + return nil, nil, nil, nil, "", "" + } + + compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch) + if err != nil { + ctx.ServerError("GetCompareInfo", err) + return nil, nil, nil, nil, "", "" + } + ctx.Data["BeforeCommitID"] = compareInfo.MergeBase + + return headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch +} + +// PrepareCompareDiff renders compare diff page +func PrepareCompareDiff( + ctx *context.Context, + headUser *models.User, + headRepo *models.Repository, + headGitRepo *git.Repository, + compareInfo *git.CompareInfo, + baseBranch, headBranch string) bool { + + var ( + repo = ctx.Repo.Repository + err error + title string + ) + + // Get diff information. + ctx.Data["CommitRepoLink"] = headRepo.Link() + + headCommitID := headBranch + if ctx.Data["HeadIsCommit"] == false { + if ctx.Data["HeadIsTag"] == true { + headCommitID, err = headGitRepo.GetTagCommitID(headBranch) + } else { + headCommitID, err = headGitRepo.GetBranchCommitID(headBranch) + } + if err != nil { + ctx.ServerError("GetRefCommitID", err) + return false + } + } + + ctx.Data["AfterCommitID"] = headCommitID + + if headCommitID == compareInfo.MergeBase { + ctx.Data["IsNothingToCompare"] = true + return true + } + + diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name), + compareInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines, + setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) + if err != nil { + ctx.ServerError("GetDiffRange", err) + return false + } + ctx.Data["Diff"] = diff + ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 + + headCommit, err := headGitRepo.GetCommit(headCommitID) + if err != nil { + ctx.ServerError("GetCommit", err) + return false + } + + compareInfo.Commits = models.ValidateCommitsWithEmails(compareInfo.Commits) + compareInfo.Commits = models.ParseCommitsWithSignature(compareInfo.Commits) + compareInfo.Commits = models.ParseCommitsWithStatus(compareInfo.Commits, headRepo) + ctx.Data["Commits"] = compareInfo.Commits + ctx.Data["CommitCount"] = compareInfo.Commits.Len() + if ctx.Data["CommitCount"] == 0 { + ctx.Data["PageIsComparePull"] = false + } + + if compareInfo.Commits.Len() == 1 { + c := compareInfo.Commits.Front().Value.(models.SignCommitWithStatuses) + title = strings.TrimSpace(c.UserCommit.Summary()) + + body := strings.Split(strings.TrimSpace(c.UserCommit.Message()), "\n") + if len(body) > 1 { + ctx.Data["content"] = strings.Join(body[1:], "\n") + } + } else { + title = headBranch + } + + ctx.Data["title"] = title + ctx.Data["Username"] = headUser.Name + ctx.Data["Reponame"] = headRepo.Name + ctx.Data["IsImageFile"] = headCommit.IsImageFile + + headTarget := path.Join(headUser.Name, repo.Name) + ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", headCommitID) + ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", compareInfo.MergeBase) + ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", headCommitID) + return false +} + +// CompareDiff show different from one commit to another commit +func CompareDiff(ctx *context.Context) { + headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := ParseCompareInfo(ctx) + if ctx.Written() { + return + } + + nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch) + if ctx.Written() { + return + } + + if ctx.Data["PageIsComparePull"] == true { + pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch) + if err != nil { + if !models.IsErrPullRequestNotExist(err) { + ctx.ServerError("GetUnmergedPullRequest", err) + return + } + } else { + ctx.Data["HasPullRequest"] = true + ctx.Data["PullRequest"] = pr + ctx.HTML(200, tplCompareDiff) + return + } + + if !nothingToCompare { + // Setup information for new form. + RetrieveRepoMetas(ctx, ctx.Repo.Repository) + if ctx.Written() { + return + } + } + + headBranches, err := headGitRepo.GetBranches() + if err != nil { + ctx.ServerError("GetBranches", err) + return + } + ctx.Data["HeadBranches"] = headBranches + } + beforeCommitID := ctx.Data["BeforeCommitID"].(string) + afterCommitID := ctx.Data["AfterCommitID"].(string) + + ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID) + + ctx.Data["IsRepoToolbarCommits"] = true + ctx.Data["IsDiffCompare"] = true + ctx.Data["RequireHighlightJS"] = true + ctx.Data["RequireTribute"] = true + ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes + setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates) + renderAttachmentSettings(ctx) + + ctx.HTML(200, tplCompare) +} diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 412750dd55..182f715545 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -28,7 +28,7 @@ import ( const ( tplFork base.TplName = "repo/pulls/fork" - tplComparePull base.TplName = "repo/pulls/compare" + tplCompareDiff base.TplName = "repo/diff/compare" tplPullCommits base.TplName = "repo/pulls/commits" tplPullFiles base.TplName = "repo/pulls/files" @@ -280,13 +280,13 @@ func setMergeTarget(ctx *context.Context, pull *models.PullRequest) { } // PrepareMergedViewPullInfo show meta information for a merged pull request view page -func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullRequestInfo { +func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.CompareInfo { pull := issue.PullRequest setMergeTarget(ctx, pull) ctx.Data["HasMerged"] = true - prInfo, err := ctx.Repo.GitRepo.GetPullRequestInfo(ctx.Repo.Repository.RepoPath(), + prInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), pull.MergeBase, pull.GetGitRefName()) if err != nil { @@ -298,7 +298,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.P return nil } - ctx.ServerError("GetPullRequestInfo", err) + ctx.ServerError("GetCompareInfo", err) return nil } ctx.Data["NumCommits"] = prInfo.Commits.Len() @@ -307,7 +307,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.P } // PrepareViewPullInfo show meta information for a pull request preview page -func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullRequestInfo { +func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.CompareInfo { repo := ctx.Repo.Repository pull := issue.PullRequest @@ -336,7 +336,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullReq return nil } - prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name), + prInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(repo.Owner.Name, repo.Name), pull.BaseBranch, pull.HeadBranch) if err != nil { if strings.Contains(err.Error(), "fatal: Not a valid object name") { @@ -347,7 +347,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullReq return nil } - ctx.ServerError("GetPullRequestInfo", err) + ctx.ServerError("GetCompareInfo", err) return nil } @@ -628,266 +628,6 @@ func stopTimerIfAvailable(user *models.User, issue *models.Issue) error { return nil } -// ParseCompareInfo parse compare info between two commit for preparing pull request -func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) { - baseRepo := ctx.Repo.Repository - - // Get compared branches information - // format: ...[:] - // base<-head: master...head:feature - // same repo: master...feature - - var ( - headUser *models.User - headBranch string - isSameRepo bool - infoPath string - err error - ) - infoPath = ctx.Params("*") - infos := strings.Split(infoPath, "...") - if len(infos) != 2 { - log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos) - ctx.NotFound("CompareAndPullRequest", nil) - return nil, nil, nil, nil, "", "" - } - - baseBranch := infos[0] - ctx.Data["BaseBranch"] = baseBranch - - // If there is no head repository, it means pull request between same repository. - headInfos := strings.Split(infos[1], ":") - if len(headInfos) == 1 { - isSameRepo = true - headUser = ctx.Repo.Owner - headBranch = headInfos[0] - - } else if len(headInfos) == 2 { - headUser, err = models.GetUserByName(headInfos[0]) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.NotFound("GetUserByName", nil) - } else { - ctx.ServerError("GetUserByName", err) - } - return nil, nil, nil, nil, "", "" - } - headBranch = headInfos[1] - isSameRepo = headUser.ID == ctx.Repo.Owner.ID - } else { - ctx.NotFound("CompareAndPullRequest", nil) - return nil, nil, nil, nil, "", "" - } - ctx.Data["HeadUser"] = headUser - ctx.Data["HeadBranch"] = headBranch - ctx.Repo.PullRequest.SameRepo = isSameRepo - - // Check if base branch is valid. - if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) { - ctx.NotFound("IsBranchExist", nil) - return nil, nil, nil, nil, "", "" - } - - // Check if current user has fork of repository or in the same repository. - headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID) - if !has && !isSameRepo { - log.Trace("ParseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID) - ctx.NotFound("ParseCompareInfo", nil) - return nil, nil, nil, nil, "", "" - } - - var headGitRepo *git.Repository - if isSameRepo { - headRepo = ctx.Repo.Repository - headGitRepo = ctx.Repo.GitRepo - ctx.Data["BaseName"] = headUser.Name - } else { - headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name)) - ctx.Data["BaseName"] = baseRepo.OwnerName - if err != nil { - ctx.ServerError("OpenRepository", err) - return nil, nil, nil, nil, "", "" - } - } - - // user should have permission to read baseRepo's codes and pulls, NOT headRepo's - permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User) - if err != nil { - ctx.ServerError("GetUserRepoPermission", err) - return nil, nil, nil, nil, "", "" - } - if !permBase.CanReadIssuesOrPulls(true) || !permBase.CanRead(models.UnitTypeCode) { - if log.IsTrace() { - log.Trace("Permission Denied: User: %-v cannot create/read pull requests or cannot read code in Repo: %-v\nUser in baseRepo has Permissions: %-+v", - ctx.User, - baseRepo, - permBase) - } - ctx.NotFound("ParseCompareInfo", nil) - return nil, nil, nil, nil, "", "" - } - - // user should have permission to read headrepo's codes - permHead, err := models.GetUserRepoPermission(headRepo, ctx.User) - if err != nil { - ctx.ServerError("GetUserRepoPermission", err) - return nil, nil, nil, nil, "", "" - } - if !permHead.CanRead(models.UnitTypeCode) { - if log.IsTrace() { - log.Trace("Permission Denied: User: %-v cannot read code requests in Repo: %-v\nUser in headRepo has Permissions: %-+v", - ctx.User, - headRepo, - permHead) - } - ctx.NotFound("ParseCompareInfo", nil) - return nil, nil, nil, nil, "", "" - } - - // Check if head branch is valid. - if !headGitRepo.IsBranchExist(headBranch) { - ctx.NotFound("IsBranchExist", nil) - return nil, nil, nil, nil, "", "" - } - - headBranches, err := headGitRepo.GetBranches() - if err != nil { - ctx.ServerError("GetBranches", err) - return nil, nil, nil, nil, "", "" - } - ctx.Data["HeadBranches"] = headBranches - - prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch) - if err != nil { - ctx.ServerError("GetPullRequestInfo", err) - return nil, nil, nil, nil, "", "" - } - ctx.Data["BeforeCommitID"] = prInfo.MergeBase - - return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch -} - -// PrepareCompareDiff render pull request preview diff page -func PrepareCompareDiff( - ctx *context.Context, - headUser *models.User, - headRepo *models.Repository, - headGitRepo *git.Repository, - prInfo *git.PullRequestInfo, - baseBranch, headBranch string) bool { - - var ( - repo = ctx.Repo.Repository - err error - title string - ) - - // Get diff information. - ctx.Data["CommitRepoLink"] = headRepo.Link() - - headCommitID, err := headGitRepo.GetBranchCommitID(headBranch) - if err != nil { - ctx.ServerError("GetBranchCommitID", err) - return false - } - ctx.Data["AfterCommitID"] = headCommitID - - if headCommitID == prInfo.MergeBase { - ctx.Data["IsNothingToCompare"] = true - return true - } - - diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name), - prInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines, - setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) - if err != nil { - ctx.ServerError("GetDiffRange", err) - return false - } - ctx.Data["Diff"] = diff - ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 - - headCommit, err := headGitRepo.GetCommit(headCommitID) - if err != nil { - ctx.ServerError("GetCommit", err) - return false - } - - prInfo.Commits = models.ValidateCommitsWithEmails(prInfo.Commits) - prInfo.Commits = models.ParseCommitsWithSignature(prInfo.Commits) - prInfo.Commits = models.ParseCommitsWithStatus(prInfo.Commits, headRepo) - ctx.Data["Commits"] = prInfo.Commits - ctx.Data["CommitCount"] = prInfo.Commits.Len() - - if prInfo.Commits.Len() == 1 { - c := prInfo.Commits.Front().Value.(models.SignCommitWithStatuses) - title = strings.TrimSpace(c.UserCommit.Summary()) - - body := strings.Split(strings.TrimSpace(c.UserCommit.Message()), "\n") - if len(body) > 1 { - ctx.Data["content"] = strings.Join(body[1:], "\n") - } - } else { - title = headBranch - } - - ctx.Data["title"] = title - ctx.Data["Username"] = headUser.Name - ctx.Data["Reponame"] = headRepo.Name - ctx.Data["IsImageFile"] = headCommit.IsImageFile - - headTarget := path.Join(headUser.Name, repo.Name) - ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", headCommitID) - ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", prInfo.MergeBase) - ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", headCommitID) - return false -} - -// CompareAndPullRequest render pull request preview page -func CompareAndPullRequest(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes") - ctx.Data["PageIsComparePull"] = true - ctx.Data["IsDiffCompare"] = true - ctx.Data["RequireHighlightJS"] = true - ctx.Data["RequireTribute"] = true - ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes - setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates) - renderAttachmentSettings(ctx) - - headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx) - if ctx.Written() { - return - } - - pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch) - if err != nil { - if !models.IsErrPullRequestNotExist(err) { - ctx.ServerError("GetUnmergedPullRequest", err) - return - } - } else { - ctx.Data["HasPullRequest"] = true - ctx.Data["PullRequest"] = pr - ctx.HTML(200, tplComparePull) - return - } - - nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch) - if ctx.Written() { - return - } - - if !nothingToCompare { - // Setup information for new form. - RetrieveRepoMetas(ctx, ctx.Repo.Repository) - if ctx.Written() { - return - } - } - - ctx.HTML(200, tplComparePull) -} - // CompareAndPullRequestPost response for creating pull request func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) { ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes") @@ -926,7 +666,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) return } - ctx.HTML(200, tplComparePull) + ctx.HTML(200, tplCompareDiff) return } @@ -936,7 +676,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) return } - ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplComparePull, form) + ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplCompareDiff, form) return } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index eb5f73768e..4c736f63ed 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -732,9 +732,9 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/milestone", func() { m.Get("/:id", repo.MilestoneIssuesAndPulls) }, reqRepoIssuesOrPullsReader, context.RepoRef()) - m.Combo("/compare/*", context.RepoMustNotBeArchived(), reqRepoCodeReader, reqRepoPullsReader, repo.MustAllowPulls, repo.SetEditorconfigIfExists). - Get(repo.SetDiffViewStyle, repo.CompareAndPullRequest). - Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost) + m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists). + Get(repo.SetDiffViewStyle, repo.CompareDiff). + Post(context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost) m.Group("", func() { m.Group("", func() { @@ -906,9 +906,6 @@ func RegisterRoutes(m *macaron.Macaron) { }, context.RepoRef(), reqRepoCodeReader) m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff) - - m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, - repo.SetDiffViewStyle, repo.MustBeNotEmpty, reqRepoCodeReader, repo.CompareDiff) }, ignSignIn, context.RepoAssignment(), context.UnitTypes()) m.Group("/:username/:reponame", func() { m.Get("/stars", repo.Stars) diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl new file mode 100644 index 0000000000..0cfdf5156d --- /dev/null +++ b/templates/repo/commit_page.tmpl @@ -0,0 +1,89 @@ +{{template "base/head" .}} +
    + {{template "repo/header" .}} +
    +
    + + {{.i18n.Tr "repo.diff.browse_source"}} + +

    {{RenderCommitMessage .Commit.Message $.RepoLink $.Repository.ComposeMetas}}{{template "repo/commit_status" .CommitStatus}}

    + {{if IsMultilineCommitMessage .Commit.Message}} +
    {{RenderCommitBody .Commit.Message $.RepoLink $.Repository.ComposeMetas}}
    + {{end}} + {{.BranchName}} +
    +
    +
    +
    + {{if .Author}} + + {{if .Author.FullName}} + {{.Author.FullName}} {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}} + {{else}} + {{.Commit.Author.Name}} {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}} + {{end}} + {{else}} + + {{.Commit.Author.Name}} + {{end}} + {{TimeSince .Commit.Author.When $.Lang}} +
    +
    +
    + {{if .Parents}} +
    + {{.i18n.Tr "repo.diff.parent"}} +
    +
    + {{range .Parents}} + {{ShortSha .}} + {{end}} +
    + {{end}} +
    +
    {{.i18n.Tr "repo.diff.commit"}}
    +
    {{ShortSha .CommitID}}
    +
    +
    +
    +
    + {{if .Commit.Signature}} + {{if .Verification.Verified }} +
    + + {{.i18n.Tr "repo.commits.signed_by"}}: + {{.Commit.Committer.Name}} <{{.Commit.Committer.Email}}> + {{.i18n.Tr "repo.commits.gpg_key_id"}}: {{.Verification.SigningKey.KeyID}} +
    + {{else}} +
    + + {{.i18n.Tr .Verification.Reason}} +
    + {{end}} + {{end}} + {{if .Note}} +
    + + {{.i18n.Tr "repo.diff.git-notes"}}: + {{if .NoteAuthor}} + + {{if .NoteAuthor.FullName}} + {{.NoteAuthor.FullName}} + {{else}} + {{.NoteCommit.Author.Name}} + {{end}} + + {{else}} + {{.NoteCommit.Author.Name}} + {{end}} + {{TimeSince .NoteCommit.Author.When $.Lang}} +
    +
    +
    {{RenderNote .Note $.RepoLink $.Repository.ComposeMetas}}
    +
    + {{end}} + {{template "repo/diff/box" .}} +
    +
    +{{template "base/footer" .}} diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index 66bfd0d831..10f4b60483 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -1,13 +1,13 @@

    -
    +
    {{if or .PageIsCommits (gt .CommitCount 0)}} {{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}} {{if .Branch}}({{.Branch}}){{end}} {{else}} {{.i18n.Tr "repo.commits.no_commits" $.BaseBranch $.HeadBranch }} {{if .Branch}}({{.Branch}}){{end}} {{end}}
    -
    + diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl new file mode 100644 index 0000000000..cc727422d7 --- /dev/null +++ b/templates/repo/diff/compare.tmpl @@ -0,0 +1,74 @@ +{{template "base/head" .}} +
    + {{template "repo/header" .}} +
    + + {{if .PageIsComparePull}} +

    + {{.i18n.Tr "repo.pulls.compare_changes"}} +
    {{.i18n.Tr "repo.pulls.compare_changes_desc"}}
    +

    +
    + + + ... + +
    + {{end}} + + {{if .IsNothingToCompare}} +
    {{.i18n.Tr "repo.pulls.nothing_to_compare"}}
    + {{else if .PageIsComparePull}} + {{if .HasPullRequest}} +
    + {{.i18n.Tr "repo.pulls.has_pull_request" $.RepoLink $.RepoRelPath .PullRequest.Index | Safe}} +
    + {{else}} +
    + +
    + + {{template "repo/commits_table" .}} + {{template "repo/diff/box" .}} + {{end}} + {{else}} + {{template "repo/commits_table" .}} + {{template "repo/diff/box" .}} + {{end}} +
    +
    +{{template "base/footer" .}} diff --git a/templates/repo/diff/page.tmpl b/templates/repo/diff/page.tmpl deleted file mode 100644 index c35e2a415b..0000000000 --- a/templates/repo/diff/page.tmpl +++ /dev/null @@ -1,94 +0,0 @@ -{{template "base/head" .}} -
    - {{template "repo/header" .}} -
    - {{if .IsDiffCompare }} - {{template "repo/commits_table" .}} - {{else}} -
    - - {{.i18n.Tr "repo.diff.browse_source"}} - -

    {{RenderCommitMessage .Commit.Message $.RepoLink $.Repository.ComposeMetas}}{{template "repo/commit_status" .CommitStatus}}

    - {{if IsMultilineCommitMessage .Commit.Message}} -
    {{RenderCommitBody .Commit.Message $.RepoLink $.Repository.ComposeMetas}}
    - {{end}} - {{.BranchName}} -
    -
    -
    -
    - {{if .Author}} - - {{if .Author.FullName}} - {{.Author.FullName}} {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}} - {{else}} - {{.Commit.Author.Name}} {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}} - {{end}} - {{else}} - - {{.Commit.Author.Name}} - {{end}} - {{TimeSince .Commit.Author.When $.Lang}} -
    -
    -
    - {{if .Parents}} -
    - {{.i18n.Tr "repo.diff.parent"}} -
    -
    - {{range .Parents}} - {{ShortSha .}} - {{end}} -
    - {{end}} -
    -
    {{.i18n.Tr "repo.diff.commit"}}
    -
    {{ShortSha .CommitID}}
    -
    -
    -
    -
    - {{if .Commit.Signature}} - {{if .Verification.Verified }} -
    - - {{.i18n.Tr "repo.commits.signed_by"}}: - {{.Commit.Committer.Name}} <{{.Commit.Committer.Email}}> - {{.i18n.Tr "repo.commits.gpg_key_id"}}: {{.Verification.SigningKey.KeyID}} -
    - {{else}} -
    - - {{.i18n.Tr .Verification.Reason}} -
    - {{end}} - {{end}} - {{if .Note}} -
    - - {{.i18n.Tr "repo.diff.git-notes"}}: - {{if .NoteAuthor}} - - {{if .NoteAuthor.FullName}} - {{.NoteAuthor.FullName}} - {{else}} - {{.NoteCommit.Author.Name}} - {{end}} - - {{else}} - {{.NoteCommit.Author.Name}} - {{end}} - {{TimeSince .NoteCommit.Author.When $.Lang}} -
    -
    -
    {{RenderNote .Note $.RepoLink $.Repository.ComposeMetas}}
    -
    - {{end}} - {{end}} - - {{template "repo/diff/box" .}} -
    -
    -{{template "base/footer" .}} diff --git a/templates/repo/pulls/compare.tmpl b/templates/repo/pulls/compare.tmpl deleted file mode 100644 index 2296acf1df..0000000000 --- a/templates/repo/pulls/compare.tmpl +++ /dev/null @@ -1,69 +0,0 @@ -{{template "base/head" .}} -
    - {{template "repo/header" .}} -
    -
    -

    - {{.i18n.Tr "repo.pulls.compare_changes"}} -
    {{.i18n.Tr "repo.pulls.compare_changes_desc"}}
    -

    -
    - - - ... - -
    - - {{if .IsNothingToCompare}} -
    - {{.i18n.Tr "repo.pulls.nothing_to_compare"}} -
    - {{else if .HasPullRequest}} -
    - {{.i18n.Tr "repo.pulls.has_pull_request" $.RepoLink $.RepoRelPath .PullRequest.Index | Safe}} -
    - {{else if eq .CommitCount 0 }} - {{template "repo/commits_table" .}} - {{template "repo/diff/box" .}} - {{else}} - {{template "repo/issue/new_form" .}} - {{template "repo/commits_table" .}} - {{template "repo/diff/box" .}} - {{end}} -
    - -
    -
    -{{template "base/footer" .}} From ca58eee6bfcaab9970391a7a3d57391cb5bf2d87 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 7 Jun 2019 20:32:49 +0000 Subject: [PATCH 095/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 9dfad59f57..c5028af841 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -487,6 +487,7 @@ manage_oauth2_applications=OAuth2アプリケーションの管理 edit_oauth2_application=OAuth2アプリケーションの編集 oauth2_applications_desc=OAuth2はGiteaインスタンスでのサードパーティアプリケーションによる安全な認証を可能にします。 remove_oauth2_application=OAuth2アプリケーションの削除 +remove_oauth2_application_desc=OAuth2アプリケーションを削除すると、すべての署名済みアクセストークンが利用できなくなります。 続行しますか? remove_oauth2_application_success=アプリケーションを削除しました。 create_oauth2_application=新しいOAuth2アプリケーションの作成 create_oauth2_application_button=アプリケーション作成 @@ -618,6 +619,7 @@ migrate.permission_denied=ローカルリポジトリをインポートする権 migrate.invalid_local_path=ローカルパスが無効です。 存在しないかディレクトリではありません。 migrate.failed=移行に失敗しました: %v migrate.lfs_mirror_unsupported=LFSオブジェクトのミラーはサポートされていません。 代わりに 'git lfs fetch --all' と 'git lfs push --all' を使ってください。 +migrate.migrate_items_options=移行元がGitHubの場合は、ユーザー名を入力すると移行オプションが表示されます。 mirror_from=ミラー元 forked_from=フォーク元 @@ -1304,11 +1306,14 @@ settings.archive.button=アーカイブ settings.archive.header=このリポジトリをアーカイブ settings.archive.text=リポジトリをアーカイブすると、リポジトリ全体が読み出し専用となります。 ダッシュボードには表示されなくなり、コミットも、課題やプルリクエストの作成もできません。 settings.archive.success=リポジトリをアーカイブしました。 +settings.archive.error=リポジトリのアーカイブ設定でエラーが発生しました。 詳細はログを確認してください。 settings.archive.error_ismirror=ミラーのリポジトリはアーカイブできません。 settings.archive.branchsettings_unavailable=ブランチ設定は、アーカイブリポジトリでは使用できません。 settings.unarchive.button=アーカイブ解除 settings.unarchive.header=このリポジトリをアーカイブ解除 +settings.unarchive.text=リポジトリのアーカイブを解除すると、コミット、プッシュ、新規の課題やプルリクエストを受け付けるよう元に戻されます。 settings.unarchive.success=リポジトリのアーカイブを解除しました。 +settings.unarchive.error=リポジトリのアーカイブ解除でエラーが発生しました。 詳細はログを確認してください。 settings.update_avatar_success=リポジトリのアバターを更新しました。 diff.browse_source=ソースを参照 From 6fb31a54610d319fbcb6c930d2c4457c8be82c96 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 8 Jun 2019 19:47:46 +0800 Subject: [PATCH 096/220] fix GCArgs load from ini (#7156) --- modules/setting/git.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setting/git.go b/modules/setting/git.go index 673bff207e..4163f1039d 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -20,7 +20,7 @@ var ( MaxGitDiffLines int MaxGitDiffLineCharacters int MaxGitDiffFiles int - GCArgs []string `delim:" "` + GCArgs []string `ini:"GC_ARGS" delim:" "` EnableAutoGitWireProtocol bool Timeout struct { Default int From 23a2ee3510ad1b1e7e89edc526ed394c71a8ba24 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 8 Jun 2019 21:53:45 +0800 Subject: [PATCH 097/220] Add command to convert mysql database from utf8 to utf8mb4 (#7144) * add command to convert mysql database from utf8 to utf8mb4 * Update cmd/convert.go Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> * Update cmd/convert.go Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> * Update cmd/convert.go Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> * Update models/convert.go Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> * Update models/convert.go Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> * Update cmd/convert.go Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> * Update cmd/convert.go Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> --- cmd/convert.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++ main.go | 1 + models/convert.go | 27 ++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 cmd/convert.go create mode 100644 models/convert.go diff --git a/cmd/convert.go b/cmd/convert.go new file mode 100644 index 0000000000..cb0510c722 --- /dev/null +++ b/cmd/convert.go @@ -0,0 +1,49 @@ +// Copyright 2019 The Gitea 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 cmd + +import ( + "fmt" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/urfave/cli" +) + +// CmdConvert represents the available convert sub-command. +var CmdConvert = cli.Command{ + Name: "convert", + Usage: "Convert the database", + Description: "A command to convert an existing MySQL database from utf8 to utf8mb4", + Action: runConvert, +} + +func runConvert(ctx *cli.Context) error { + if err := initDB(); err != nil { + return err + } + + log.Trace("AppPath: %s", setting.AppPath) + log.Trace("AppWorkPath: %s", setting.AppWorkPath) + log.Trace("Custom path: %s", setting.CustomPath) + log.Trace("Log path: %s", setting.LogRootPath) + models.LoadConfigs() + + if models.DbCfg.Type != "mysql" { + fmt.Println("This command can only be used with a MySQL database") + return nil + } + + if err := models.ConvertUtf8ToUtf8mb4(); err != nil { + log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err) + return err + } + + fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4") + + return nil +} diff --git a/main.go b/main.go index d8c37fee2f..79c9b01114 100644 --- a/main.go +++ b/main.go @@ -67,6 +67,7 @@ arguments - which can alternatively be run by running the subcommand web.` cmd.CmdGenerate, cmd.CmdMigrate, cmd.CmdKeys, + cmd.CmdConvert, } // Now adjust these commands to add our global configuration options diff --git a/models/convert.go b/models/convert.go new file mode 100644 index 0000000000..c34be973c6 --- /dev/null +++ b/models/convert.go @@ -0,0 +1,27 @@ +// Copyright 2019 The Gitea 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 models + +import "fmt" + +// ConvertUtf8ToUtf8mb4 converts database and tables from utf8 to utf8mb4 if it's mysql +func ConvertUtf8ToUtf8mb4() error { + _, err := x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", DbCfg.Name)) + if err != nil { + return err + } + + tables, err := x.DBMetas() + if err != nil { + return err + } + for _, table := range tables { + if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;", table.Name)); err != nil { + return err + } + } + + return nil +} From 8de0b0a3f06fe7879fb014d2624209e0e48455a0 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Sat, 8 Jun 2019 10:31:11 -0400 Subject: [PATCH 098/220] Fixes #2738 - Adds the /git/tags API endpoint (#7138) * Fixes #2738 - /git/tags API * proper URLs * Adds function comments * Updates swagger * Removes newline from tag message * Removes trailing newline from commit message * Adds integration test * Removed debugging * Adds tests * Fixes bug where multiple tags of same commit show wrong tag name * Fix formatting * Removes unused varaible * Fix to annotated tag function names and response * Update modules/git/repo_tag.go Co-Authored-By: Lauris BH * Uses TagPrefix * Changes per review, better error handling for getting tag and commit IDs * Fix to getting commit ID * Fix to getting commit ID * Fix to getting commit ID * Fix to getting commit ID --- integrations/api_repo_file_create_test.go | 4 +- integrations/api_repo_file_update_test.go | 8 +- integrations/api_repo_git_tags_test.go | 59 +++++++++ integrations/api_repo_tags_test.go | 7 +- models/repo_tag.go | 2 +- modules/git/repo_ref.go | 12 +- modules/git/repo_tag.go | 147 ++++++++++++++++++++-- modules/git/repo_tag_test.go | 80 +++++++++++- modules/git/tag.go | 3 +- modules/structs/repo_tag.go | 30 +++-- routers/api/v1/api.go | 2 + routers/api/v1/convert/convert.go | 98 ++++++++++----- routers/api/v1/repo/git_ref.go | 3 +- routers/api/v1/repo/tag.go | 45 +++++++ routers/api/v1/swagger/repo.go | 16 ++- templates/swagger/v1_json.tmpl | 120 ++++++++++++++++-- 16 files changed, 551 insertions(+), 85 deletions(-) create mode 100644 integrations/api_repo_git_tags_test.go diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index 28097179a0..3bb2ecb812 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -146,8 +146,8 @@ func TestAPICreateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf" - expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/new/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/new/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index 37438339bb..eab7090df6 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -136,8 +136,8 @@ func TestAPIUpdateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/update/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/update/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) @@ -155,8 +155,8 @@ func TestAPIUpdateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &fileResponse) expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/master/rename/update/file%d.txt", fileID) - expectedDownloadURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) + expectedHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/blob/master/rename/update/file%d.txt", fileID) + expectedDownloadURL = fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) diff --git a/integrations/api_repo_git_tags_test.go b/integrations/api_repo_git_tags_test.go new file mode 100644 index 0000000000..ae519249e0 --- /dev/null +++ b/integrations/api_repo_git_tags_test.go @@ -0,0 +1,59 @@ +// Copyright 2018 The Gitea 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 integrations + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" +) + +func TestAPIGitTags(t *testing.T) { + prepareTestEnv(t) + user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) + repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + // Login as User2. + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session) + + // Set up git config for the tagger + git.NewCommand("config", "user.name", user.Name).RunInDir(repo.RepoPath()) + git.NewCommand("config", "user.email", user.Email).RunInDir(repo.RepoPath()) + + gitRepo, _ := git.OpenRepository(repo.RepoPath()) + commit, _ := gitRepo.GetBranchCommit("master") + lTagName := "lightweightTag" + gitRepo.CreateTag(lTagName, commit.ID.String()) + + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + gitRepo.CreateAnnotatedTag(aTagName, aTagMessage, commit.ID.String()) + aTag, _ := gitRepo.GetTag(aTagName) + + // SHOULD work for annotated tags + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, aTag.ID.String(), token) + res := session.MakeRequest(t, req, http.StatusOK) + + var tag *api.AnnotatedTag + DecodeJSON(t, res, &tag) + + assert.Equal(t, aTagName, tag.Tag) + assert.Equal(t, aTag.ID.String(), tag.SHA) + assert.Equal(t, commit.ID.String(), tag.Object.SHA) + assert.Equal(t, aTagMessage, tag.Message) + assert.Equal(t, user.Name, tag.Tagger.Name) + assert.Equal(t, user.Email, tag.Tagger.Email) + assert.Equal(t, util.URLJoin(repo.APIURL(), "git/tags", aTag.ID.String()), tag.URL) + + // Should NOT work for lightweight tags + badReq := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, commit.ID.String(), token) + session.MakeRequest(t, badReq, http.StatusBadRequest) +} diff --git a/integrations/api_repo_tags_test.go b/integrations/api_repo_tags_test.go index 13b446fb96..252037bd4a 100644 --- a/integrations/api_repo_tags_test.go +++ b/integrations/api_repo_tags_test.go @@ -6,7 +6,6 @@ package integrations import ( "net/http" - "path" "testing" "code.gitea.io/gitea/models" @@ -32,7 +31,7 @@ func TestAPIReposGetTags(t *testing.T) { assert.EqualValues(t, 1, len(tags)) assert.Equal(t, "v1.1", tags[0].Name) assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.SHA) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d"), tags[0].Commit.URL) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/archive/v1.1.zip"), tags[0].ZipballURL) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/archive/v1.1.tar.gz"), tags[0].TarballURL) + assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL) + assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL) + assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL) } diff --git a/models/repo_tag.go b/models/repo_tag.go index fa3f19bb29..3864b7a12a 100644 --- a/models/repo_tag.go +++ b/models/repo_tag.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/modules/git" ) -// GetTagsByPath returns repo tags by it's path +// GetTagsByPath returns repo tags by its path func GetTagsByPath(path string) ([]*git.Tag, error) { gitRepo, err := git.OpenRepository(path) if err != nil { diff --git a/modules/git/repo_ref.go b/modules/git/repo_ref.go index e1ab46e090..95a6c2ae69 100644 --- a/modules/git/repo_ref.go +++ b/modules/git/repo_ref.go @@ -31,15 +31,19 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) { if err = refsIter.ForEach(func(ref *plumbing.Reference) error { if ref.Name() != plumbing.HEAD && !ref.Name().IsRemote() && (pattern == "" || strings.HasPrefix(ref.Name().String(), pattern)) { + refType := string(ObjectCommit) + if ref.Name().IsTag() { + // tags can be of type `commit` (lightweight) or `tag` (annotated) + if tagType, _ := repo.GetTagType(SHA1(ref.Hash())); err == nil { + refType = tagType + } + } r := &Reference{ Name: ref.Name().String(), Object: SHA1(ref.Hash()), - Type: string(ObjectCommit), + Type: refType, repo: repo, } - if ref.Name().IsTag() { - r.Type = string(ObjectTag) - } refs = append(refs, r) } return nil diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 8c72528933..08d66262c1 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -6,6 +6,7 @@ package git import ( + "fmt" "strings" "github.com/mcuadros/go-version" @@ -35,34 +36,78 @@ func (repo *Repository) CreateTag(name, revision string) error { return err } +// CreateAnnotatedTag create one annotated tag in the repository +func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error { + _, err := NewCommand("tag", "-a", "-m", message, name, revision).RunInDir(repo.Path) + return err +} + func (repo *Repository) getTag(id SHA1) (*Tag, error) { t, ok := repo.tagCache.Get(id.String()) if ok { log("Hit cache: %s", id) - return t.(*Tag), nil + tagClone := *t.(*Tag) + return &tagClone, nil } - // Get tag type - tp, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path) + // Get tag name + name, err := repo.GetTagNameBySHA(id.String()) if err != nil { return nil, err } - tp = strings.TrimSpace(tp) - // Tag is a commit. + tp, err := repo.GetTagType(id) + if err != nil { + return nil, err + } + + // Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object + commitIDStr, err := repo.GetTagCommitID(name) + if err != nil { + // every tag should have a commit ID so return all errors + return nil, err + } + commitID, err := NewIDFromString(commitIDStr) + if err != nil { + return nil, err + } + + // tagID defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) + tagID := commitID + if tagIDStr, err := repo.GetTagID(name); err != nil { + // if the err is NotExist then we can ignore and just keep tagID as ID (is lightweight tag) + // all other errors we return + if !IsErrNotExist(err) { + return nil, err + } + } else { + tagID, err = NewIDFromString(tagIDStr) + if err != nil { + return nil, err + } + } + + // If type is "commit, the tag is a lightweight tag if ObjectType(tp) == ObjectCommit { + commit, err := repo.GetCommit(id.String()) + if err != nil { + return nil, err + } tag := &Tag{ - ID: id, - Object: id, - Type: string(ObjectCommit), - repo: repo, + Name: name, + ID: tagID, + Object: commitID, + Type: string(ObjectCommit), + Tagger: commit.Committer, + Message: commit.Message(), + repo: repo, } repo.tagCache.Set(id.String(), tag) return tag, nil } - // Tag with message. + // The tag is an annotated tag with a message. data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path) if err != nil { return nil, err @@ -73,16 +118,57 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } + tag.Name = name tag.ID = id tag.repo = repo + tag.Type = tp repo.tagCache.Set(id.String(), tag) return tag, nil } +// GetTagNameBySHA returns the name of a tag from its tag object SHA or commit SHA +func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { + if len(sha) < 5 { + return "", fmt.Errorf("SHA is too short: %s", sha) + } + + stdout, err := NewCommand("show-ref", "--tags", "-d").RunInDir(repo.Path) + if err != nil { + return "", err + } + + tagRefs := strings.Split(stdout, "\n") + for _, tagRef := range tagRefs { + if len(strings.TrimSpace(tagRef)) > 0 { + fields := strings.Fields(tagRef) + if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], TagPrefix) { + name := fields[1][len(TagPrefix):] + // annotated tags show up twice, their name for commit ID is suffixed with ^{} + name = strings.TrimSuffix(name, "^{}") + return name, nil + } + } + } + return "", ErrNotExist{ID: sha} +} + +// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA) +func (repo *Repository) GetTagID(name string) (string, error) { + stdout, err := NewCommand("show-ref", name).RunInDir(repo.Path) + if err != nil { + return "", err + } + fields := strings.Fields(stdout) + if len(fields) != 2 { + return "", ErrNotExist{ID: name} + } + return fields[0], nil +} + // GetTag returns a Git tag by given name. func (repo *Repository) GetTag(name string) (*Tag, error) { - idStr, err := repo.GetTagCommitID(name) + idStr, err := repo.GetTagID(name) if err != nil { return nil, err } @@ -96,7 +182,6 @@ func (repo *Repository) GetTag(name string) (*Tag, error) { if err != nil { return nil, err } - tag.Name = name return tag, nil } @@ -108,7 +193,7 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) { return nil, err } - tagNames := strings.Split(stdout, "\n") + tagNames := strings.Split(strings.TrimRight(stdout, "\n"), "\n") var tags = make([]*Tag, 0, len(tagNames)) for _, tagName := range tagNames { tagName = strings.TrimSpace(tagName) @@ -120,6 +205,7 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) { if err != nil { return nil, err } + tag.Name = tagName tags = append(tags, tag) } sortTagsByTime(tags) @@ -150,3 +236,38 @@ func (repo *Repository) GetTags() ([]string, error) { return tagNames, nil } + +// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) +func (repo *Repository) GetTagType(id SHA1) (string, error) { + // Get tag type + stdout, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path) + if err != nil { + return "", err + } + if len(stdout) == 0 { + return "", ErrNotExist{ID: id.String()} + } + return strings.TrimSpace(stdout), nil +} + +// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag +func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) { + id, err := NewIDFromString(sha) + if err != nil { + return nil, err + } + + // Tag type must be "tag" (annotated) and not a "commit" (lightweight) tag + if tagType, err := repo.GetTagType(id); err != nil { + return nil, err + } else if ObjectType(tagType) != ObjectTag { + // not an annotated tag + return nil, ErrNotExist{ID: id.String()} + } + + tag, err := repo.getTag(id) + if err != nil { + return nil, err + } + return tag, nil +} diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index ccb2d57ac2..4f727c6c66 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -21,8 +21,8 @@ func TestRepository_GetTags(t *testing.T) { assert.NoError(t, err) assert.Len(t, tags, 1) assert.EqualValues(t, "test", tags[0].Name) - assert.EqualValues(t, "37991dec2c8e592043f47155ce4808d4580f9123", tags[0].ID.String()) - assert.EqualValues(t, "commit", tags[0].Type) + assert.EqualValues(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[0].ID.String()) + assert.EqualValues(t, "tag", tags[0].Type) } func TestRepository_GetTag(t *testing.T) { @@ -35,10 +35,78 @@ func TestRepository_GetTag(t *testing.T) { bareRepo1, err := OpenRepository(clonedPath) assert.NoError(t, err) - tag, err := bareRepo1.GetTag("test") + lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" + lTagName := "lightweightTag" + bareRepo1.CreateTag(lTagName, lTagCommitID) + + aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) + aTagID, _ := bareRepo1.GetTagID(aTagName) + + lTag, err := bareRepo1.GetTag(lTagName) + lTag.repo = nil + assert.NoError(t, err) + assert.NotNil(t, lTag) + assert.EqualValues(t, lTagName, lTag.Name) + assert.EqualValues(t, lTagCommitID, lTag.ID.String()) + assert.EqualValues(t, lTagCommitID, lTag.Object.String()) + assert.EqualValues(t, "commit", lTag.Type) + + aTag, err := bareRepo1.GetTag(aTagName) + assert.NoError(t, err) + assert.NotNil(t, aTag) + assert.EqualValues(t, aTagName, aTag.Name) + assert.EqualValues(t, aTagID, aTag.ID.String()) + assert.NotEqual(t, aTagID, aTag.Object.String()) + assert.EqualValues(t, aTagCommitID, aTag.Object.String()) + assert.EqualValues(t, "tag", aTag.Type) +} + +func TestRepository_GetAnnotatedTag(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") + + clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestRepository_GetTag") + assert.NoError(t, err) + defer os.RemoveAll(clonedPath) + + bareRepo1, err := OpenRepository(clonedPath) + assert.NoError(t, err) + + lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" + lTagName := "lightweightTag" + bareRepo1.CreateTag(lTagName, lTagCommitID) + + aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) + aTagID, _ := bareRepo1.GetTagID(aTagName) + + // Try an annotated tag + tag, err := bareRepo1.GetAnnotatedTag(aTagID) assert.NoError(t, err) assert.NotNil(t, tag) - assert.EqualValues(t, "test", tag.Name) - assert.EqualValues(t, "37991dec2c8e592043f47155ce4808d4580f9123", tag.ID.String()) - assert.EqualValues(t, "commit", tag.Type) + assert.EqualValues(t, aTagName, tag.Name) + assert.EqualValues(t, aTagID, tag.ID.String()) + assert.EqualValues(t, "tag", tag.Type) + + // Annotated tag's Commit ID should fail + tag2, err := bareRepo1.GetAnnotatedTag(aTagCommitID) + assert.Error(t, err) + assert.True(t, IsErrNotExist(err)) + assert.Nil(t, tag2) + + // Annotated tag's name should fail + tag3, err := bareRepo1.GetAnnotatedTag(aTagName) + assert.Error(t, err) + assert.Errorf(t, err, "Length must be 40: %d", len(aTagName)) + assert.Nil(t, tag3) + + // Lightweight Tag should fail + tag4, err := bareRepo1.GetAnnotatedTag(lTagCommitID) + assert.Error(t, err) + assert.True(t, IsErrNotExist(err)) + assert.Nil(t, tag4) } diff --git a/modules/git/tag.go b/modules/git/tag.go index 500fd27491..c97f574fa6 100644 --- a/modules/git/tag.go +++ b/modules/git/tag.go @@ -7,6 +7,7 @@ package git import ( "bytes" "sort" + "strings" ) // Tag represents a Git tag. @@ -59,7 +60,7 @@ l: } nextline += eol + 1 case eol == 0: - tag.Message = string(data[nextline+1:]) + tag.Message = strings.TrimRight(string(data[nextline+1:]), "\n") break l default: break l diff --git a/modules/structs/repo_tag.go b/modules/structs/repo_tag.go index 6294a8099d..b62395cac4 100644 --- a/modules/structs/repo_tag.go +++ b/modules/structs/repo_tag.go @@ -6,11 +6,27 @@ package structs // Tag represents a repository tag type Tag struct { - Name string `json:"name"` - Commit struct { - SHA string `json:"sha"` - URL string `json:"url"` - } `json:"commit"` - ZipballURL string `json:"zipball_url"` - TarballURL string `json:"tarball_url"` + Name string `json:"name"` + ID string `json:"id"` + Commit *CommitMeta `json:"commit"` + ZipballURL string `json:"zipball_url"` + TarballURL string `json:"tarball_url"` +} + +// AnnotatedTag represents an annotated tag +type AnnotatedTag struct { + Tag string `json:"tag"` + SHA string `json:"sha"` + URL string `json:"url"` + Message string `json:"message"` + Tagger *CommitUser `json:"tagger"` + Object *AnnotatedTagObject `json:"object"` + Verification *PayloadCommitVerification `json:"verification"` +} + +// AnnotatedTagObject contains meta information of the tag object +type AnnotatedTagObject struct { + Type string `json:"type"` + URL string `json:"url"` + SHA string `json:"sha"` } diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index c1561200cd..2268c1be38 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -751,6 +751,7 @@ func RegisterRoutes(m *macaron.Macaron) { Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus) }, reqRepoReader(models.UnitTypeCode)) m.Group("/commits/:ref", func() { + // TODO: Add m.Get("") for single commit (https://developer.github.com/v3/repos/commits/#get-a-single-commit) m.Get("/status", repo.GetCombinedCommitStatusByRef) m.Get("/statuses", repo.GetCommitStatusesByRef) }, reqRepoReader(models.UnitTypeCode)) @@ -762,6 +763,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/refs/*", repo.GetGitRefs) m.Get("/trees/:sha", context.RepoRef(), repo.GetTree) m.Get("/blobs/:sha", context.RepoRef(), repo.GetBlob) + m.Get("/tags/:sha", context.RepoRef(), repo.GetTag) }, reqRepoReader(models.UnitTypeCode)) m.Group("/contents", func() { m.Get("/*", repo.GetFileContents) diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index ba61c7e46c..a982cb8d37 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -6,6 +6,7 @@ package convert import ( "fmt" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" @@ -26,7 +27,7 @@ func ToEmail(email *models.EmailAddress) *api.Email { } } -// ToBranch convert a commit and branch to an api.Branch +// ToBranch convert a git.Commit and git.Branch to an api.Branch func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit) *api.Branch { return &api.Branch{ Name: b.Name, @@ -34,23 +35,18 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit) *api.Branch } } -// ToTag convert a tag to an api.Tag +// ToTag convert a git.Tag to an api.Tag func ToTag(repo *models.Repository, t *git.Tag) *api.Tag { return &api.Tag{ - Name: t.Name, - Commit: struct { - SHA string `json:"sha"` - URL string `json:"url"` - }{ - SHA: t.ID.String(), - URL: util.URLJoin(repo.Link(), "commit", t.ID.String()), - }, - ZipballURL: util.URLJoin(repo.Link(), "archive", t.Name+".zip"), - TarballURL: util.URLJoin(repo.Link(), "archive", t.Name+".tar.gz"), + Name: t.Name, + ID: t.ID.String(), + Commit: ToCommitMeta(repo, t), + ZipballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".zip"), + TarballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".tar.gz"), } } -// ToCommit convert a commit to api.PayloadCommit +// ToCommit convert a git.Commit to api.PayloadCommit func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { authorUsername := "" if author, err := models.GetUserByEmail(c.Author.Email); err == nil { @@ -66,17 +62,10 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { log.Error("GetUserByEmail: %v", err) } - verif := models.ParseCommitWithSignature(c) - var signature, payload string - if c.Signature != nil { - signature = c.Signature.Signature - payload = c.Signature.Payload - } - return &api.PayloadCommit{ ID: c.ID.String(), Message: c.Message(), - URL: util.URLJoin(repo.Link(), "commit", c.ID.String()), + URL: util.URLJoin(repo.HTMLURL(), "commit", c.ID.String()), Author: &api.PayloadUser{ Name: c.Author.Name, Email: c.Author.Email, @@ -87,13 +76,24 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { Email: c.Committer.Email, UserName: committerUsername, }, - Timestamp: c.Author.When, - Verification: &api.PayloadCommitVerification{ - Verified: verif.Verified, - Reason: verif.Reason, - Signature: signature, - Payload: payload, - }, + Timestamp: c.Author.When, + Verification: ToVerification(c), + } +} + +// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification +func ToVerification(c *git.Commit) *api.PayloadCommitVerification { + verif := models.ParseCommitWithSignature(c) + var signature, payload string + if c.Signature != nil { + signature = c.Signature.Signature + payload = c.Signature.Payload + } + return &api.PayloadCommitVerification{ + Verified: verif.Verified, + Reason: verif.Reason, + Signature: signature, + Payload: payload, } } @@ -242,3 +242,45 @@ func ToUser(user *models.User, signed, admin bool) *api.User { } return result } + +// ToAnnotatedTag convert git.Tag to api.AnnotatedTag +func ToAnnotatedTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag { + return &api.AnnotatedTag{ + Tag: t.Name, + SHA: t.ID.String(), + Object: ToAnnotatedTagObject(repo, c), + Message: t.Message, + URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()), + Tagger: ToCommitUser(t.Tagger), + Verification: ToVerification(c), + } +} + +// ToAnnotatedTagObject convert a git.Commit to an api.AnnotatedTagObject +func ToAnnotatedTagObject(repo *models.Repository, commit *git.Commit) *api.AnnotatedTagObject { + return &api.AnnotatedTagObject{ + SHA: commit.ID.String(), + Type: string(git.ObjectCommit), + URL: util.URLJoin(repo.APIURL(), "git/commits", commit.ID.String()), + } +} + +// ToCommitUser convert a git.Signature to an api.CommitUser +func ToCommitUser(sig *git.Signature) *api.CommitUser { + return &api.CommitUser{ + Identity: api.Identity{ + Name: sig.Name, + Email: sig.Email, + }, + Date: sig.When.UTC().Format(time.RFC3339), + } +} + +// ToCommitMeta convert a git.Tag to an api.CommitMeta +func ToCommitMeta(repo *models.Repository, tag *git.Tag) *api.CommitMeta { + return &api.CommitMeta{ + SHA: tag.ID.String(), + // TODO: Add the /commits API endpoint and use it here (https://developer.github.com/v3/repos/commits/#get-a-single-commit) + URL: util.URLJoin(repo.APIURL(), "git/commits", tag.ID.String()), + } +} diff --git a/routers/api/v1/repo/git_ref.go b/routers/api/v1/repo/git_ref.go index 2ec8749058..e15f699a1d 100644 --- a/routers/api/v1/repo/git_ref.go +++ b/routers/api/v1/repo/git_ref.go @@ -100,8 +100,7 @@ func getGitRefsInternal(ctx *context.APIContext, filter string) { Object: &api.GitObject{ SHA: refs[i].Object.String(), Type: refs[i].Type, - // TODO: Add commit/tag info URL - //URL: ctx.Repo.Repository.APIURL() + "/git/" + refs[i].Type + "s/" + refs[i].Object.String(), + URL: ctx.Repo.Repository.APIURL() + "/git/" + refs[i].Type + "s/" + refs[i].Object.String(), }, } } diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index dd1b5aa7c1..ecf580e1b0 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -7,6 +7,7 @@ package repo import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/convert" + "net/http" api "code.gitea.io/gitea/modules/structs" ) @@ -45,3 +46,47 @@ func ListTags(ctx *context.APIContext) { ctx.JSON(200, &apiTags) } + +// GetTag get the tag of a repository. +func GetTag(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/git/tags/{sha} repository GetTag + // --- + // summary: Gets the tag of a repository. + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: sha + // in: path + // description: sha of the tag + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/AnnotatedTag" + + sha := ctx.Params("sha") + if len(sha) == 0 { + ctx.Error(http.StatusBadRequest, "", "SHA not provided") + return + } + + if tag, err := ctx.Repo.GitRepo.GetAnnotatedTag(sha); err != nil { + ctx.Error(http.StatusBadRequest, "GetTag", err) + } else { + commit, err := tag.Commit() + if err != nil { + ctx.Error(http.StatusBadRequest, "GetTag", err) + } + ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx.Repo.Repository, tag, commit)) + } +} diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index e7df0b8f71..25354b3d66 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -38,11 +38,25 @@ type swaggerResponseBranchList struct { // TagList // swagger:response TagList -type swaggerReponseTagList struct { +type swaggerResponseTagList struct { // in:body Body []api.Tag `json:"body"` } +// Tag +// swagger:response Tag +type swaggerResponseTag struct { + // in:body + Body api.Tag `json:"body"` +} + +// AnnotatedTag +// swagger:response AnnotatedTag +type swaggerResponseAnnotatedTag struct { + // in:body + Body api.AnnotatedTag `json:"body"` +} + // Reference // swagger:response Reference type swaggerResponseReference struct { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0bd85fbb6e..2b40c89791 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2036,6 +2036,46 @@ } } }, + "/repos/{owner}/{repo}/git/tags/{sha}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Gets the tag of a repository.", + "operationId": "GetTag", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "sha of the tag", + "name": "sha", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/AnnotatedTag" + } + } + } + }, "/repos/{owner}/{repo}/git/trees/{sha}": { "get": { "produces": [ @@ -6762,6 +6802,57 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "AnnotatedTag": { + "description": "AnnotatedTag represents an annotated tag", + "type": "object", + "properties": { + "message": { + "type": "string", + "x-go-name": "Message" + }, + "object": { + "$ref": "#/definitions/AnnotatedTagObject" + }, + "sha": { + "type": "string", + "x-go-name": "SHA" + }, + "tag": { + "type": "string", + "x-go-name": "Tag" + }, + "tagger": { + "$ref": "#/definitions/CommitUser" + }, + "url": { + "type": "string", + "x-go-name": "URL" + }, + "verification": { + "$ref": "#/definitions/PayloadCommitVerification" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, + "AnnotatedTagObject": { + "description": "AnnotatedTagObject contains meta information of the tag object", + "type": "object", + "properties": { + "sha": { + "type": "string", + "x-go-name": "SHA" + }, + "type": { + "type": "string", + "x-go-name": "Type" + }, + "url": { + "type": "string", + "x-go-name": "URL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Attachment": { "description": "Attachment a generic attachment", "type": "object", @@ -9458,18 +9549,11 @@ "type": "object", "properties": { "commit": { - "type": "object", - "properties": { - "sha": { - "type": "string", - "x-go-name": "SHA" - }, - "url": { - "type": "string", - "x-go-name": "URL" - } - }, - "x-go-name": "Commit" + "$ref": "#/definitions/CommitMeta" + }, + "id": { + "type": "string", + "x-go-name": "ID" }, "name": { "type": "string", @@ -9735,6 +9819,12 @@ "AccessTokenList": { "description": "AccessTokenList represents a list of API access token." }, + "AnnotatedTag": { + "description": "AnnotatedTag", + "schema": { + "$ref": "#/definitions/AnnotatedTag" + } + }, "Attachment": { "description": "Attachment", "schema": { @@ -10056,6 +10146,12 @@ } } }, + "Tag": { + "description": "Tag", + "schema": { + "$ref": "#/definitions/Tag" + } + }, "TagList": { "description": "TagList", "schema": { From 3e05661d8d52315d6dbb601950df2354428ac119 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Mon, 10 Jun 2019 02:02:42 +0100 Subject: [PATCH 099/220] archived repos can be starred and watched (#7163) --- routers/routes/routes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 4c736f63ed..f7ccfc43d2 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -674,7 +674,7 @@ func RegisterRoutes(m *macaron.Macaron) { }) }, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef()) - m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), context.RepoMustNotBeArchived(), repo.Action) + m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) m.Group("/:username/:reponame", func() { m.Group("/issues", func() { From b1be6fd31f6f9f1512de16cd93d30775319b3c75 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 10 Jun 2019 01:06:14 +0000 Subject: [PATCH 100/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 4 ++++ options/locale/locale_zh-CN.ini | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 7a0b61d2ee..7176b23f56 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -618,6 +618,7 @@ migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Rep migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner. migrate.failed=Fehler bei der Migration: %v migrate.lfs_mirror_unsupported=Spiegeln von LFS-Objekten wird nicht unterstützt - nutze stattdessen 'git lfs fetch --all' und 'git lfs push --all'. +migrate.migrate_items_options=Wenn du von GitHub migrierst und einen Benutzernamen eingegeben hast, werden die Migrationsoptionen angezeigt. mirror_from=Mirror von forked_from=geforkt von @@ -1304,11 +1305,14 @@ settings.archive.button=Repo archivieren settings.archive.header=Dieses Repo archivieren settings.archive.text=Durch die Archivierung des Repos wird es vollständig schreibgeschützt. Es wird auf dem Dashboard versteckt, nimmt keine Commits an und es können keine Issues oder Pull-Requests erstellt werden. settings.archive.success=Das Repo wurde erfolgreich archiviert. +settings.archive.error=Beim Versuch, das Repository zu archivieren, ist ein Fehler aufgetreten. Weitere Details finden sich im Log. settings.archive.error_ismirror=Du kannst keinen Repo-Mirror archivieren. settings.archive.branchsettings_unavailable=Branch-Einstellungen sind nicht verfügbar wenn das Repo archiviert ist. settings.unarchive.button=Archivieren rückgängig machen settings.unarchive.header=Archivieren dieses Repos rückgängig machen +settings.unarchive.text=Durch das Aufheben der Archivierung kann das Repo wieder Commits und Pushes sowie neue Issues und Pull-Requests empfangen. settings.unarchive.success=Die Archivierung des Repos wurde erfolgreich wieder rückgängig gemacht. +settings.unarchive.error=Beim Versuch, die Archivierung des Repos aufzuheben, ist ein Fehler aufgetreten. Weitere Details finden sich im Log. settings.update_avatar_success=Der Repository-Avatar wurde aktualisiert. diff.browse_source=Quellcode durchsuchen diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index da23f30fb6..6b495bee87 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -86,12 +86,18 @@ host=数据库主机 user=用户名 password=数据库用户密码 db_name=数据库名称 +db_helper=MySQL 用户注意:请使用InnoDB 存储引擎,如果您使用“utf8mb4”,您的 InnoDB 版本必须大于5.6。 ssl_mode=SSL +charset=字符集 path=数据库文件路径 sqlite_helper=SQLite3 数据库的文件路径。
    如果以服务的方式运行 Gitea,请输入绝对路径。 err_empty_db_path=SQLite 数据库文件路径不能为空。 no_admin_and_disable_registration=您不能够在未创建管理员用户的情况下禁止注册。 err_empty_admin_password=管理员密码不能为空。 +err_empty_admin_email=管理员电子邮件不能为空。 +err_admin_name_is_reserved=管理员用户名无效,用户名是保留的 +err_admin_name_pattern_not_allowed=管理员用户名无效,用户名不符合要求 +err_admin_name_is_invalid=管理员用户名无效 general_title=一般设置 app_name=站点名称 @@ -382,6 +388,7 @@ choose_new_avatar=选择新的头像 update_avatar=更新头像 delete_current_avatar=删除当前头像 uploaded_avatar_not_a_image=上传的文件不是一张图片。 +uploaded_avatar_is_too_big=上传的文件超过了最大大小。 update_avatar_success=您的头像已更新。 change_password=更新密码 @@ -480,6 +487,7 @@ manage_oauth2_applications=管理 OAuth2 应用程序 edit_oauth2_application=编辑 OAuth2 应用程序 oauth2_applications_desc=OAuth2 应用允许第三方应用程序在此 Gitea 实例中安全验证用户。 remove_oauth2_application=删除 OAuth2 应用程序 +remove_oauth2_application_desc=删除 OAuth2 应用将撤销所有签名的访问令牌。继续吗? remove_oauth2_application_success=该应用已被删除。 create_oauth2_application=创建新的 OAuth2 应用程序 create_oauth2_application_button=创建应用 @@ -611,6 +619,7 @@ migrate.permission_denied=您没有获得导入本地仓库的权限。 migrate.invalid_local_path=无效的本地路径,不存在或不是一个目录! migrate.failed=迁移失败:%v migrate.lfs_mirror_unsupported=不支持镜像 LFS 对象 - 使用 'git lfs fetch --all' 和 'git lfs push --all' 替代。 +migrate.migrate_items_options=当从 github 迁移并且输入了用户名时,迁移选项将会显示。 mirror_from=镜像自地址 forked_from=派生自 @@ -923,7 +932,7 @@ issues.dependency.add_error_cannot_create_circular=您不能创建依赖, 使得 issues.dependency.add_error_dep_not_same_repo=这两个工单必须在同一仓库。 issues.review.self.approval=您不能批准您自己的合并请求。 issues.review.self.rejection=您不能请求对您自己的合并请求进行更改。 -issues.review.approve=已批准这些更改 %s +issues.review.approve=已于 %s 批准这些更改 issues.review.comment=评审于 %s issues.review.content.empty=您需要留下一个注释,表明需要的更改。 issues.review.reject=请求变更 %s @@ -1297,15 +1306,20 @@ settings.archive.button=归档仓库 settings.archive.header=归档此仓库 settings.archive.text=归档后仓库将只有只读权限,并在仪表盘中被隐藏。你将不能再对其建立提交、创建工单或建立合并请求。 settings.archive.success=仓库已成功归档。 +settings.archive.error=仓库在归档时出现异常。请通过日志获取详细信息。 settings.archive.error_ismirror=请不要对镜像仓库归档,谢谢! settings.archive.branchsettings_unavailable=已归档仓库无法进行分支设置。 settings.unarchive.button=撤销仓库归档 settings.unarchive.header=撤销此仓库归档 +settings.unarchive.text=取消存档将恢复仓库接收提交,推送,新工单和合并请求。 settings.unarchive.success=仓库已成功取消归档。 +settings.unarchive.error=仓库在撤销归档时出现异常。请通过日志获取详细信息。 +settings.update_avatar_success=仓库头像已经更新。 diff.browse_source=浏览代码 diff.parent=父节点 diff.commit=当前提交 +diff.git-notes=Notes diff.data_not_available=比较内容不可用 diff.show_diff_stats=显示文件统计 diff.show_split_view=分列视图 @@ -1507,6 +1521,8 @@ dashboard.delete_repo_archives=删除所有仓库存档 dashboard.delete_repo_archives_success=所有仓库存档清除成功! dashboard.delete_missing_repos=删除所有丢失 Git 文件的仓库 dashboard.delete_missing_repos_success=所有丢失对应 Git 文件的仓库已被删除。 +dashboard.delete_generated_repository_avatars=删除生成的仓库头像 +dashboard.delete_generated_repository_avatars_success=生成的仓库头像已删除。 dashboard.git_gc_repos=对仓库进行垃圾回收 dashboard.git_gc_repos_success=所有仓库已完成执行垃圾回收。 dashboard.resync_all_sshkeys=重新生成 '.ssh/authorized_keys' 文件。(仅对非内置SSH服务有效) From d93e6232e829a1ade1f9540a701061967aa7d61d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 10 Jun 2019 19:35:13 +0800 Subject: [PATCH 101/220] Move PushUpdate dependency from models to repofiles (#6763) * remove push_update * move models.PushUpdate to repofiles.PushUpdate --- models/update.go | 4 --- modules/repofiles/delete.go | 5 ++- modules/repofiles/update.go | 18 +++++++++-- modules/repofiles/upload.go | 4 +-- routers/private/hook.go | 11 ++++++- routers/private/push_update.go | 56 ++++++++++++++++++++++++++++++++++ routers/repo/branch.go | 21 +++++++------ 7 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 routers/private/push_update.go diff --git a/models/update.go b/models/update.go index 1492d6c0d3..0883cb0e01 100644 --- a/models/update.go +++ b/models/update.go @@ -263,10 +263,6 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { commits = ListToPushCommits(l) } - if opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { - UpdateRepoIndexer(repo) - } - if err := CommitRepoAction(CommitRepoActionOptions{ PusherName: opts.PusherName, RepoOwnerID: owner.ID, diff --git a/modules/repofiles/delete.go b/modules/repofiles/delete.go index ccf90f43b3..09a4dbb44c 100644 --- a/modules/repofiles/delete.go +++ b/modules/repofiles/delete.go @@ -183,7 +183,8 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo if err = repo.GetOwner(); err != nil { return nil, fmt.Errorf("GetOwner: %v", err) } - err = models.PushUpdate( + err = PushUpdate( + repo, opts.NewBranch, models.PushUpdateOptions{ PusherID: doer.ID, @@ -199,8 +200,6 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo return nil, fmt.Errorf("PushUpdate: %v", err) } - // FIXME: Should we UpdateRepoIndexer(repo) here? - file, err := GetFileResponseFromCommit(repo, commit, opts.NewBranch, treePath) if err != nil { return nil, err diff --git a/modules/repofiles/update.go b/modules/repofiles/update.go index 66e3f2babc..569c89ac51 100644 --- a/modules/repofiles/update.go +++ b/modules/repofiles/update.go @@ -394,7 +394,8 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up if err = repo.GetOwner(); err != nil { return nil, fmt.Errorf("GetOwner: %v", err) } - err = models.PushUpdate( + err = PushUpdate( + repo, opts.NewBranch, models.PushUpdateOptions{ PusherID: doer.ID, @@ -409,7 +410,6 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up if err != nil { return nil, fmt.Errorf("PushUpdate: %v", err) } - models.UpdateRepoIndexer(repo) commit, err = t.GetCommit(commitHash) if err != nil { @@ -422,3 +422,17 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up } return file, nil } + +// PushUpdate must be called for any push actions in order to +// generates necessary push action history feeds and other operations +func PushUpdate(repo *models.Repository, branch string, opts models.PushUpdateOptions) error { + err := models.PushUpdate(branch, opts) + if err != nil { + return fmt.Errorf("PushUpdate: %v", err) + } + + if opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { + models.UpdateRepoIndexer(repo) + } + return nil +} diff --git a/modules/repofiles/upload.go b/modules/repofiles/upload.go index ed6a9438c7..5f428c3139 100644 --- a/modules/repofiles/upload.go +++ b/modules/repofiles/upload.go @@ -188,7 +188,8 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep if err = repo.GetOwner(); err != nil { return fmt.Errorf("GetOwner: %v", err) } - err = models.PushUpdate( + err = PushUpdate( + repo, opts.NewBranch, models.PushUpdateOptions{ PusherID: doer.ID, @@ -203,7 +204,6 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep if err != nil { return fmt.Errorf("PushUpdate: %v", err) } - // FIXME: Should we models.UpdateRepoIndexer(repo) here? return models.DeleteUploads(uploads...) } diff --git a/routers/private/hook.go b/routers/private/hook.go index 700c8bf332..a5985f161e 100644 --- a/routers/private/hook.go +++ b/routers/private/hook.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/repofiles" "code.gitea.io/gitea/modules/util" macaron "gopkg.in/macaron.v1" @@ -117,7 +118,15 @@ func HookPostReceive(ctx *macaron.Context) { // or other less-standard refs spaces are ignored since there // may be a very large number of them). if strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) { - if err := models.PushUpdate(branch, models.PushUpdateOptions{ + repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + if err != nil { + log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + if err := repofiles.PushUpdate(repo, branch, models.PushUpdateOptions{ RefFullName: refFullName, OldCommitID: oldCommitID, NewCommitID: newCommitID, diff --git a/routers/private/push_update.go b/routers/private/push_update.go new file mode 100644 index 0000000000..733490ce1c --- /dev/null +++ b/routers/private/push_update.go @@ -0,0 +1,56 @@ +// Copyright 2017 The Gitea 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 private + +import ( + "encoding/json" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/repofiles" + + macaron "gopkg.in/macaron.v1" +) + +// PushUpdate update public key updates +func PushUpdate(ctx *macaron.Context) { + var opt models.PushUpdateOptions + if err := json.NewDecoder(ctx.Req.Request.Body).Decode(&opt); err != nil { + ctx.JSON(500, map[string]interface{}{ + "err": err.Error(), + }) + return + } + + branch := strings.TrimPrefix(opt.RefFullName, git.BranchPrefix) + if len(branch) == 0 || opt.PusherID <= 0 { + ctx.Error(404) + log.Trace("PushUpdate: branch or secret is empty, or pusher ID is not valid") + return + } + + repo, err := models.GetRepositoryByOwnerAndName(opt.RepoUserName, opt.RepoName) + if err != nil { + ctx.JSON(500, map[string]interface{}{ + "err": err.Error(), + }) + return + } + + err = repofiles.PushUpdate(repo, branch, opt) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.Error(404) + } else { + ctx.JSON(500, map[string]interface{}{ + "err": err.Error(), + }) + } + return + } + ctx.Status(202) +} diff --git a/routers/repo/branch.go b/routers/repo/branch.go index ae87aa5b3a..05d64fb4c8 100644 --- a/routers/repo/branch.go +++ b/routers/repo/branch.go @@ -131,15 +131,18 @@ func deleteBranch(ctx *context.Context, branchName string) error { } // Don't return error below this - if err := models.PushUpdate(branchName, models.PushUpdateOptions{ - RefFullName: git.BranchPrefix + branchName, - OldCommitID: commit.ID.String(), - NewCommitID: git.EmptySHA, - PusherID: ctx.User.ID, - PusherName: ctx.User.Name, - RepoUserName: ctx.Repo.Owner.Name, - RepoName: ctx.Repo.Repository.Name, - }); err != nil { + if err := repofiles.PushUpdate( + ctx.Repo.Repository, + branchName, + models.PushUpdateOptions{ + RefFullName: git.BranchPrefix + branchName, + OldCommitID: commit.ID.String(), + NewCommitID: git.EmptySHA, + PusherID: ctx.User.ID, + PusherName: ctx.User.Name, + RepoUserName: ctx.Repo.Owner.Name, + RepoName: ctx.Repo.Repository.Name, + }); err != nil { log.Error("Update: %v", err) } From 7162fbf3d6adf0a1f5b7ce95df5603d995b35d85 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 10 Jun 2019 22:16:02 +0800 Subject: [PATCH 102/220] if milestone id is zero don't get it from database (#7169) --- routers/repo/issue.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index f6030c9823..cd384da0d6 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -426,12 +426,14 @@ func NewIssue(ctx *context.Context) { ctx.Data["BodyQuery"] = body milestoneID := ctx.QueryInt64("milestone") - milestone, err := models.GetMilestoneByID(milestoneID) - if err != nil { - log.Error("GetMilestoneByID: %d: %v", milestoneID, err) - } else { - ctx.Data["milestone_id"] = milestoneID - ctx.Data["Milestone"] = milestone + if milestoneID > 0 { + milestone, err := models.GetMilestoneByID(milestoneID) + if err != nil { + log.Error("GetMilestoneByID: %d: %v", milestoneID, err) + } else { + ctx.Data["milestone_id"] = milestoneID + ctx.Data["Milestone"] = milestone + } } setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates) From 835b53fc259c82f38945a3e107a4eb51478967d5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 10 Jun 2019 23:20:49 +0800 Subject: [PATCH 103/220] make modules/structs as a spereate go mod (#7127) --- modules/structs/attachment.go | 1 + modules/structs/go.mod | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 modules/structs/go.mod diff --git a/modules/structs/attachment.go b/modules/structs/attachment.go index 954956f328..7becd94335 100644 --- a/modules/structs/attachment.go +++ b/modules/structs/attachment.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. package structs // import "code.gitea.io/gitea/modules/structs" + import ( "time" ) diff --git a/modules/structs/go.mod b/modules/structs/go.mod new file mode 100644 index 0000000000..96826f2f07 --- /dev/null +++ b/modules/structs/go.mod @@ -0,0 +1,3 @@ +module code.gitea.io/gitea/modules/structs + +go 1.12 From b3b468444b1dcc6c4353df232b6a74b2017e83db Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 11 Jun 2019 03:55:58 +0800 Subject: [PATCH 104/220] Revert "make modules/structs as a spereate go mod (#7127)" (#7175) This reverts commit 835b53fc259c82f38945a3e107a4eb51478967d5. --- modules/structs/attachment.go | 1 - modules/structs/go.mod | 3 --- 2 files changed, 4 deletions(-) delete mode 100644 modules/structs/go.mod diff --git a/modules/structs/attachment.go b/modules/structs/attachment.go index 7becd94335..954956f328 100644 --- a/modules/structs/attachment.go +++ b/modules/structs/attachment.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. package structs // import "code.gitea.io/gitea/modules/structs" - import ( "time" ) diff --git a/modules/structs/go.mod b/modules/structs/go.mod deleted file mode 100644 index 96826f2f07..0000000000 --- a/modules/structs/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module code.gitea.io/gitea/modules/structs - -go 1.12 From 74690f64514424ac643a8007828de1a785705793 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 11 Jun 2019 09:13:24 +0800 Subject: [PATCH 105/220] fix pusher name via ssh push (#7167) --- cmd/serv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/serv.go b/cmd/serv.go index 0b0a4e8efb..c0cb3cd50f 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -209,7 +209,7 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki)) os.Setenv(models.EnvRepoName, results.RepoName) os.Setenv(models.EnvRepoUsername, results.OwnerName) - os.Setenv(models.EnvPusherName, username) + os.Setenv(models.EnvPusherName, results.UserName) os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10)) From 499a8a1cdd815cc25554371598140f5fb01e216f Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 11 Jun 2019 21:27:38 +0200 Subject: [PATCH 106/220] Various fixes for issue mail notifications (#7165) - Send individual mails for actions and comments - Send mail for new issues/prs without a comment - Use correct sender for reopen/close actions - Hopefully fixed all bugs related to missing mails Fixes: https://github.com/go-gitea/gitea/issues/7124 Fixes: https://github.com/go-gitea/gitea/issues/5977 --- models/issue_comment.go | 19 +++++++++++----- models/issue_mail.go | 37 ++++++++++++++++++++++--------- modules/notification/mail/mail.go | 6 ++--- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/models/issue_comment.go b/models/issue_comment.go index 60fb5b0420..0d2e917f85 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -403,16 +403,23 @@ func (c *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue) (e return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err) } - content := c.Content + if len(c.Content) > 0 { + if err = mailIssueCommentToParticipants(e, issue, c.Poster, c.Content, c, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } + } switch opType { case ActionCloseIssue: - content = fmt.Sprintf("Closed #%d", issue.Index) + ct := fmt.Sprintf("Closed #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, c.Poster, ct, c, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } case ActionReopenIssue: - content = fmt.Sprintf("Reopened #%d", issue.Index) - } - if err = mailIssueCommentToParticipants(e, issue, c.Poster, content, c, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) + ct := fmt.Sprintf("Reopened #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, c.Poster, ct, c, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } } return nil diff --git a/models/issue_mail.go b/models/issue_mail.go index 16f85ba378..01a12b16d2 100644 --- a/models/issue_mail.go +++ b/models/issue_mail.go @@ -118,26 +118,41 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content // MailParticipants sends new issue thread created emails to repository watchers // and mentioned people. -func (issue *Issue) MailParticipants(opType ActionType) (err error) { - return issue.mailParticipants(x, opType) +func (issue *Issue) MailParticipants(doer *User, opType ActionType) (err error) { + return issue.mailParticipants(x, doer, opType) } -func (issue *Issue) mailParticipants(e Engine, opType ActionType) (err error) { +func (issue *Issue) mailParticipants(e Engine, doer *User, opType ActionType) (err error) { mentions := markup.FindAllMentions(issue.Content) + if err = UpdateIssueMentions(e, issue.ID, mentions); err != nil { return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err) } - var content = issue.Content - switch opType { - case ActionCloseIssue, ActionClosePullRequest: - content = fmt.Sprintf("Closed #%d", issue.Index) - case ActionReopenIssue, ActionReopenPullRequest: - content = fmt.Sprintf("Reopened #%d", issue.Index) + if len(issue.Content) > 0 { + if err = mailIssueCommentToParticipants(e, issue, doer, issue.Content, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } } - if err = mailIssueCommentToParticipants(e, issue, issue.Poster, content, nil, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) + switch opType { + case ActionCreateIssue, ActionCreatePullRequest: + if len(issue.Content) == 0 { + ct := fmt.Sprintf("Created #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } + } + case ActionCloseIssue, ActionClosePullRequest: + ct := fmt.Sprintf("Closed #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } + case ActionReopenIssue, ActionReopenPullRequest: + ct := fmt.Sprintf("Reopened #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } } return nil diff --git a/modules/notification/mail/mail.go b/modules/notification/mail/mail.go index 9689f4d4ab..9d0db4f415 100644 --- a/modules/notification/mail/mail.go +++ b/modules/notification/mail/mail.go @@ -42,7 +42,7 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models. } func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) { - if err := issue.MailParticipants(models.ActionCreateIssue); err != nil { + if err := issue.MailParticipants(issue.Poster, models.ActionCreateIssue); err != nil { log.Error("MailParticipants: %v", err) } } @@ -63,13 +63,13 @@ func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models. } } - if err := issue.MailParticipants(actionType); err != nil { + if err := issue.MailParticipants(doer, actionType); err != nil { log.Error("MailParticipants: %v", err) } } func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest) { - if err := pr.Issue.MailParticipants(models.ActionCreatePullRequest); err != nil { + if err := pr.Issue.MailParticipants(pr.Issue.Poster, models.ActionCreatePullRequest); err != nil { log.Error("MailParticipants: %v", err) } } From 1608f63e396c78bcbea3605b812556ddf441a6c4 Mon Sep 17 00:00:00 2001 From: Mario Lubenka Date: Wed, 12 Jun 2019 01:32:08 +0200 Subject: [PATCH 107/220] Fixes diff on merged pull requests (#7171) --- models/pull.go | 2 +- modules/git/repo_compare.go | 8 ++++---- routers/repo/pull.go | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/models/pull.go b/models/pull.go index 5ac1126314..1f03dd9b0f 100644 --- a/models/pull.go +++ b/models/pull.go @@ -1144,7 +1144,7 @@ func (pr *PullRequest) UpdatePatch() (err error) { defer func() { headGitRepo.RemoveRemote(tmpRemote) }() - pr.MergeBase, err = headGitRepo.GetMergeBase(tmpRemote, pr.BaseBranch, pr.HeadBranch) + pr.MergeBase, _, err = headGitRepo.GetMergeBase(tmpRemote, pr.BaseBranch, pr.HeadBranch) if err != nil { return fmt.Errorf("GetMergeBase: %v", err) } else if err = pr.Update(); err != nil { diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go index e7a1d72a85..42f0b9ad0c 100644 --- a/modules/git/repo_compare.go +++ b/modules/git/repo_compare.go @@ -22,8 +22,8 @@ type CompareInfo struct { NumFiles int } -// GetMergeBase checks and returns merge base of two branches. -func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (string, error) { +// GetMergeBase checks and returns merge base of two branches and the reference used as base. +func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (string, string, error) { if tmpRemote == "" { tmpRemote = "origin" } @@ -38,7 +38,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin } stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path) - return strings.TrimSpace(stdout), err + return strings.TrimSpace(stdout), base, err } // GetCompareInfo generates and returns compare information between base and head branches of repositories. @@ -59,7 +59,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string) } compareInfo := new(CompareInfo) - compareInfo.MergeBase, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch) + compareInfo.MergeBase, remoteBranch, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch) if err == nil { // We have a common base logs, err := NewCommand("log", compareInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 182f715545..71c684356d 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -286,7 +286,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C setMergeTarget(ctx, pull) ctx.Data["HasMerged"] = true - prInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), + compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), pull.MergeBase, pull.GetGitRefName()) if err != nil { @@ -301,9 +301,9 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C ctx.ServerError("GetCompareInfo", err) return nil } - ctx.Data["NumCommits"] = prInfo.Commits.Len() - ctx.Data["NumFiles"] = prInfo.NumFiles - return prInfo + ctx.Data["NumCommits"] = compareInfo.Commits.Len() + ctx.Data["NumFiles"] = compareInfo.NumFiles + return compareInfo } // PrepareViewPullInfo show meta information for a pull request preview page @@ -336,7 +336,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare return nil } - prInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(repo.Owner.Name, repo.Name), + compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(repo.Owner.Name, repo.Name), pull.BaseBranch, pull.HeadBranch) if err != nil { if strings.Contains(err.Error(), "fatal: Not a valid object name") { @@ -361,9 +361,9 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare ctx.Data["ConflictedFiles"] = pull.ConflictedFiles } - ctx.Data["NumCommits"] = prInfo.Commits.Len() - ctx.Data["NumFiles"] = prInfo.NumFiles - return prInfo + ctx.Data["NumCommits"] = compareInfo.Commits.Len() + ctx.Data["NumFiles"] = compareInfo.NumFiles + return compareInfo } // ViewPullCommits show commits for a pull request From 5832f8d90df2d72cb38698c3e9050f2b29717dc7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 12 Jun 2019 08:12:13 +0800 Subject: [PATCH 108/220] Fix database lock when use random repository fallback image (#7166) * fix database lock when use random repository fallback image * remove unused function --- models/repo.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/models/repo.go b/models/repo.go index d5eca3d225..a855c84939 100644 --- a/models/repo.go +++ b/models/repo.go @@ -331,7 +331,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) AllowRebase: allowRebase, AllowRebaseMerge: allowRebaseMerge, AllowSquash: allowSquash, - AvatarURL: repo.AvatarLink(), + AvatarURL: repo.avatarLink(e), } } @@ -2528,11 +2528,7 @@ func (repo *Repository) CustomAvatarPath() string { return filepath.Join(setting.RepositoryAvatarUploadPath, repo.Avatar) } -// GenerateRandomAvatar generates a random avatar for repository. -func (repo *Repository) GenerateRandomAvatar() error { - return repo.generateRandomAvatar(x) -} - +// generateRandomAvatar generates a random avatar for repository. func (repo *Repository) generateRandomAvatar(e Engine) error { idToString := fmt.Sprintf("%d", repo.ID) @@ -2585,7 +2581,10 @@ func RemoveRandomAvatars() error { // RelAvatarLink returns a relative link to the repository's avatar. func (repo *Repository) RelAvatarLink() string { + return repo.relAvatarLink(x) +} +func (repo *Repository) relAvatarLink(e Engine) string { // If no avatar - path is empty avatarPath := repo.CustomAvatarPath() if len(avatarPath) <= 0 || !com.IsFile(avatarPath) { @@ -2593,8 +2592,8 @@ func (repo *Repository) RelAvatarLink() string { case "image": return setting.RepositoryAvatarFallbackImage case "random": - if err := repo.GenerateRandomAvatar(); err != nil { - log.Error("GenerateRandomAvatar: %v", err) + if err := repo.generateRandomAvatar(e); err != nil { + log.Error("generateRandomAvatar: %v", err) } default: // default behaviour: do not display avatar @@ -2604,9 +2603,9 @@ func (repo *Repository) RelAvatarLink() string { return setting.AppSubURL + "/repo-avatars/" + repo.Avatar } -// AvatarLink returns user avatar absolute link. -func (repo *Repository) AvatarLink() string { - link := repo.RelAvatarLink() +// avatarLink returns user avatar absolute link. +func (repo *Repository) avatarLink(e Engine) string { + link := repo.relAvatarLink(e) // link may be empty! if len(link) > 0 { if link[0] == '/' && link[1] != '/' { From f9ec2f89f2265bc1371a6c62359de9816534fa6b Mon Sep 17 00:00:00 2001 From: kolaente Date: Wed, 12 Jun 2019 21:41:28 +0200 Subject: [PATCH 109/220] Add golangci (#6418) --- .drone.yml | 6 +- .golangci.yml | 97 ++++++++++++++ Makefile | 11 ++ cmd/admin.go | 2 +- cmd/cert.go | 21 ++- cmd/serv.go | 7 +- cmd/web.go | 9 +- contrib/pr/checkout.go | 3 +- integrations/branches_test.go | 2 +- integrations/editor_test.go | 6 +- integrations/integration_test.go | 11 +- integrations/lfs_getobject_test.go | 2 +- integrations/migration-test/migration_test.go | 15 --- integrations/testlogger.go | 2 +- main.go | 6 +- models/access_test.go | 7 - models/branches.go | 8 +- models/git_blame.go | 4 +- models/git_diff.go | 13 +- models/git_diff_test.go | 6 - models/issue.go | 11 +- models/issue_comment.go | 17 +-- models/issue_comment_list.go | 38 +++--- models/issue_label.go | 8 -- models/issue_list.go | 125 ++++++++++++------ models/log.go | 17 ++- models/login_source.go | 21 +-- models/mail.go | 7 +- models/migrations/migrations.go | 8 +- models/migrations/v27.go | 4 +- models/migrations/v78.go | 3 + models/migrations/v85.go | 3 + models/models.go | 9 +- models/notification.go | 5 +- models/oauth2.go | 5 +- models/oauth2_application.go | 7 +- models/org.go | 17 ++- models/org_team.go | 31 ++++- models/org_test.go | 6 +- models/pull.go | 25 +++- models/pull_test.go | 6 +- models/release.go | 14 +- models/repo.go | 32 ++--- models/repo_activity.go | 2 +- models/repo_branch.go | 12 +- models/repo_collaboration.go | 2 +- models/repo_list.go | 26 ++-- models/repo_redirect.go | 15 ++- models/ssh_key.go | 10 +- models/status.go | 12 +- models/token_test.go | 4 +- models/update.go | 4 +- models/user.go | 29 ++-- models/user_mail.go | 2 +- models/user_openid_test.go | 4 +- models/webhook.go | 8 +- models/webhook_discord.go | 2 +- models/wiki.go | 12 +- modules/auth/auth.go | 12 +- modules/auth/oauth2/oauth2.go | 3 +- modules/auth/openid/discovery_cache_test.go | 2 +- modules/auth/user_form.go | 2 +- modules/base/tool.go | 28 ++-- modules/base/tool_test.go | 15 +-- modules/cache/cache.go | 12 +- modules/context/context.go | 3 +- modules/context/pagination.go | 2 +- modules/context/repo.go | 14 +- modules/git/blob.go | 6 +- modules/git/commit.go | 7 +- modules/git/commit_info.go | 10 -- modules/git/repo.go | 12 +- modules/git/repo_branch.go | 7 +- modules/git/repo_commit.go | 5 +- modules/git/repo_compare.go | 8 +- modules/git/repo_tag.go | 7 +- modules/git/utils.go | 8 -- modules/gzip/gzip.go | 6 +- modules/httplib/httplib.go | 35 +++-- modules/indexer/indexer.go | 17 --- modules/indexer/issues/indexer.go | 13 +- modules/indexer/issues/queue_channel.go | 6 +- modules/indexer/issues/queue_disk.go | 4 +- modules/indexer/issues/queue_redis.go | 4 +- modules/lfs/locks.go | 17 +-- modules/lfs/server.go | 12 +- modules/log/colors.go | 8 +- modules/log/conn.go | 5 +- modules/log/conn_test.go | 1 - modules/log/event.go | 4 +- modules/log/file.go | 4 +- modules/log/file_test.go | 8 +- modules/log/flags.go | 2 +- modules/log/log.go | 2 +- modules/log/smtp.go | 4 - modules/log/writer.go | 5 +- modules/mailer/mailer.go | 15 +-- modules/markup/html.go | 34 +---- modules/markup/html_internal_test.go | 5 - modules/notification/ui/ui.go | 9 +- modules/pprof/pprof.go | 12 +- modules/repofiles/delete.go | 10 +- modules/repofiles/file.go | 4 +- modules/repofiles/tree.go | 11 +- modules/repofiles/update.go | 14 +- modules/repofiles/upload.go | 8 +- modules/repofiles/verification.go | 6 +- modules/session/virtual.go | 6 +- modules/setting/log.go | 12 +- modules/setting/setting.go | 7 +- modules/ssh/ssh.go | 50 +++++-- modules/structs/user_search.go | 5 - modules/structs/utils.go | 6 - modules/templates/dynamic.go | 10 +- modules/templates/helper.go | 2 +- modules/user/user_test.go | 2 +- modules/validation/binding_test.go | 6 - routers/admin/admin.go | 4 - routers/api/v1/misc/markdown.go | 27 +++- routers/api/v1/repo/pull.go | 12 +- routers/api/v1/repo/repo.go | 9 -- routers/api/v1/user/gpg_key.go | 5 - routers/init.go | 2 +- routers/org/teams.go | 7 +- routers/private/hook.go | 1 - routers/private/serv.go | 2 - routers/repo/blame.go | 2 +- routers/repo/commit.go | 3 + routers/repo/download.go | 20 ++- routers/repo/editor.go | 12 +- routers/repo/http.go | 57 ++++---- routers/repo/issue.go | 11 +- routers/repo/issue_label.go | 1 - routers/repo/milestone.go | 3 +- routers/repo/pull.go | 4 +- routers/repo/setting.go | 5 +- routers/repo/view.go | 4 +- routers/repo/webhook.go | 14 +- routers/routes/routes.go | 35 ++--- routers/user/auth.go | 113 +++++++++++----- routers/user/auth_openid.go | 32 ++++- routers/user/oauth.go | 36 ++++- routers/user/profile.go | 1 - routers/user/setting/profile.go | 8 +- routers/user/setting/security_twofa.go | 28 +++- routers/user/setting/security_u2f.go | 7 +- templates/user/meta/stars.tmpl | 0 147 files changed, 1046 insertions(+), 774 deletions(-) create mode 100644 .golangci.yml delete mode 100644 modules/structs/user_search.go delete mode 100644 templates/user/meta/stars.tmpl diff --git a/.drone.yml b/.drone.yml index 0b8c8422b6..ec90c158b1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -74,12 +74,10 @@ pipeline: commands: - make clean - make generate - - make vet - - make lint - - make fmt-check + - make golangci-lint + - make revive - make swagger-check - make swagger-validate - - make misspell-check - make test-vendor - make build when: diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000000..82d0e46694 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,97 @@ +linters: + enable: + - gosimple + - deadcode + - typecheck + - govet + - errcheck + - staticcheck + - unused + - structcheck + - varcheck + - golint + - dupl + #- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. + - gofmt + - misspell + - gocritic + enable-all: false + disable-all: true + fast: false + +linters-settings: + gocritic: + disabled-checks: + - ifElseChain + - singleCaseSwitch # Every time this occured in the code, there was no other way. + +issues: + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + - unparam + - staticcheck + - path: models/migrations/v + linters: + - gocyclo + - errcheck + - dupl + - gosec + - linters: + - dupl + text: "webhook" + - linters: + - gocritic + text: "`ID' should not be capitalized" + - path: modules/templates/helper.go + linters: + - gocritic + - linters: + - unused + - deadcode + text: "swagger" + - path: contrib/pr/checkout.go + linters: + - errcheck + - path: models/issue.go + linters: + - errcheck + - path: models/migrations/ + linters: + - errcheck + - path: modules/log/ + linters: + - errcheck + - path: routers/routes/routes.go + linters: + - dupl + - path: routers/repo/view.go + linters: + - dupl + - path: models/migrations/ + linters: + - unused + - linters: + - staticcheck + text: "argument x is overwritten before first use" + - path: modules/httplib/httplib.go + linters: + - staticcheck + # Enabling this would require refactoring the methods and how they are called. + - path: models/issue_comment_list.go + linters: + - dupl + # "Destroy" is misspelled in github.com/go-macaron/session/session.go:213 so it's not our responsability to fix it + - path: modules/session/virtual.go + linters: + - misspell + text: '`Destory` is a misspelling of `Destroy`' + - path: modules/session/memory.go + linters: + - misspell + text: '`Destory` is a misspelling of `Destroy`' diff --git a/Makefile b/Makefile index f175b95ae1..d7f27a8a94 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,10 @@ errcheck: .PHONY: lint lint: + @echo 'make lint is depricated. Use "make revive" if you want to use the old lint tool, or "make golangci-lint" to run a complete code check.' + +.PHONY: revive +revive: @hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GO) get -u github.com/mgechev/revive; \ fi @@ -461,3 +465,10 @@ generate-images: .PHONY: pr pr: $(GO) run contrib/pr/checkout.go $(PR) + +.PHONY: golangci-lint +golangci-lint: + @hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.16.0; \ + fi + golangci-lint run diff --git a/cmd/admin.go b/cmd/admin.go index ecb4eb48a6..6234ab828d 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -481,7 +481,7 @@ func runUpdateOauth(c *cli.Context) error { } // update custom URL mapping - var customURLMapping *oauth2.CustomURLMapping + var customURLMapping = &oauth2.CustomURLMapping{} if oAuth2Config.CustomURLMapping != nil { customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL diff --git a/cmd/cert.go b/cmd/cert.go index 46473c0042..b62319f808 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -170,17 +170,28 @@ func runCert(c *cli.Context) error { if err != nil { log.Fatalf("Failed to open cert.pem for writing: %v", err) } - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - certOut.Close() + err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + if err != nil { + log.Fatalf("Failed to encode certificate: %v", err) + } + err = certOut.Close() + if err != nil { + log.Fatalf("Failed to write cert: %v", err) + } log.Println("Written cert.pem") keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Fatalf("Failed to open key.pem for writing: %v", err) } - pem.Encode(keyOut, pemBlockForKey(priv)) - keyOut.Close() + err = pem.Encode(keyOut, pemBlockForKey(priv)) + if err != nil { + log.Fatalf("Failed to encode key: %v", err) + } + err = keyOut.Close() + if err != nil { + log.Fatalf("Failed to write key: %v", err) + } log.Println("Written key.pem") - return nil } diff --git a/cmd/serv.go b/cmd/serv.go index c0cb3cd50f..c1c8fd3a97 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -30,7 +30,6 @@ import ( ) const ( - accessDenied = "Repository does not exist or you do not have access" lfsAuthenticateVerb = "git-lfs-authenticate" ) @@ -67,7 +66,7 @@ func checkLFSVersion() { } func setup(logPath string) { - log.DelLogger("console") + _ = log.DelLogger("console") setting.NewContext() checkLFSVersion() } @@ -112,7 +111,9 @@ func runServ(c *cli.Context) error { } if len(c.Args()) < 1 { - cli.ShowSubcommandHelp(c) + if err := cli.ShowSubcommandHelp(c); err != nil { + fmt.Printf("error showing subcommand help: %v\n", err) + } return nil } diff --git a/cmd/web.go b/cmd/web.go index e6d0300a15..e211674b4d 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -178,11 +178,16 @@ func runWeb(ctx *cli.Context) error { } err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m)) case setting.FCGI: - listener, err := net.Listen("tcp", listenAddr) + var listener net.Listener + listener, err = net.Listen("tcp", listenAddr) if err != nil { log.Fatal("Failed to bind %s: %v", listenAddr, err) } - defer listener.Close() + defer func() { + if err := listener.Close(); err != nil { + log.Fatal("Failed to stop server: %v", err) + } + }() err = fcgi.Serve(listener, context2.ClearHandler(m)) case setting.UnixSocket: if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) { diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 880c029510..a837cb5812 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -91,8 +91,7 @@ func runPR() { routers.NewServices() //x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared") - var helper testfixtures.Helper - helper = &testfixtures.SQLite{} + var helper testfixtures.Helper = &testfixtures.SQLite{} models.NewEngine(func(_ *xorm.Engine) error { return nil }) diff --git a/integrations/branches_test.go b/integrations/branches_test.go index 01c6dd2a4b..e74f338aa2 100644 --- a/integrations/branches_test.go +++ b/integrations/branches_test.go @@ -62,7 +62,7 @@ func branchAction(t *testing.T, button string) (*HTMLDoc, string) { req = NewRequestWithValues(t, "POST", link, map[string]string{ "_csrf": getCsrf(t, htmlDoc.doc), }) - resp = session.MakeRequest(t, req, http.StatusOK) + session.MakeRequest(t, req, http.StatusOK) url, err := url.Parse(link) assert.NoError(t, err) diff --git a/integrations/editor_test.go b/integrations/editor_test.go index 8e6effe7eb..a46712293e 100644 --- a/integrations/editor_test.go +++ b/integrations/editor_test.go @@ -34,7 +34,7 @@ func TestCreateFile(t *testing.T) { "content": "Content", "commit_choice": "direct", }) - resp = session.MakeRequest(t, req, http.StatusFound) + session.MakeRequest(t, req, http.StatusFound) }) } @@ -48,7 +48,7 @@ func TestCreateFileOnProtectedBranch(t *testing.T) { "_csrf": csrf, "protected": "on", }) - resp := session.MakeRequest(t, req, http.StatusFound) + session.MakeRequest(t, req, http.StatusFound) // Check if master branch has been locked successfully flashCookie := session.GetCookie("macaron_flash") assert.NotNil(t, flashCookie) @@ -56,7 +56,7 @@ func TestCreateFileOnProtectedBranch(t *testing.T) { // Request editor page req = NewRequest(t, "GET", "/user2/repo1/_new/master/") - resp = session.MakeRequest(t, req, http.StatusOK) + resp := session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) lastCommit := doc.GetInputValueByName("last_commit") diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 80a42efb5c..e9b46ffcb9 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -42,7 +42,7 @@ type NilResponseRecorder struct { } func (n *NilResponseRecorder) Write(b []byte) (int, error) { - n.Length = n.Length + len(b) + n.Length += len(b) return len(b), nil } @@ -141,8 +141,7 @@ func initIntegrationTest() { if err != nil { log.Fatalf("sql.Open: %v", err) } - rows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", - models.DbCfg.Name)) + rows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", models.DbCfg.Name)) if err != nil { log.Fatalf("db.Query: %v", err) } @@ -210,7 +209,7 @@ func (s *TestSession) MakeRequest(t testing.TB, req *http.Request, expectedStatu resp := MakeRequest(t, req, expectedStatus) ch := http.Header{} - ch.Add("Cookie", strings.Join(resp.HeaderMap["Set-Cookie"], ";")) + ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) cr := http.Request{Header: ch} s.jar.SetCookies(baseURL, cr.Cookies()) @@ -226,7 +225,7 @@ func (s *TestSession) MakeRequestNilResponseRecorder(t testing.TB, req *http.Req resp := MakeRequestNilResponseRecorder(t, req, expectedStatus) ch := http.Header{} - ch.Add("Cookie", strings.Join(resp.HeaderMap["Set-Cookie"], ";")) + ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) cr := http.Request{Header: ch} s.jar.SetCookies(baseURL, cr.Cookies()) @@ -266,7 +265,7 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession resp = MakeRequest(t, req, http.StatusFound) ch := http.Header{} - ch.Add("Cookie", strings.Join(resp.HeaderMap["Set-Cookie"], ";")) + ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) cr := http.Request{Header: ch} session := emptyTestSession(t) diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go index 8f01d712a3..567cf13b45 100644 --- a/integrations/lfs_getobject_test.go +++ b/integrations/lfs_getobject_test.go @@ -45,7 +45,7 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: int64(len(*content)), RepositoryID: repositoryID} } - lfsID = lfsID + 1 + lfsID++ lfsMetaObject, err = models.NewLFSMetaObject(lfsMetaObject) assert.NoError(t, err) contentStore := &lfs.ContentStore{BasePath: setting.LFS.ContentPath} diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index f168424865..15b086c6e6 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -57,21 +57,6 @@ func initMigrationTest(t *testing.T) { setting.NewLogServices(true) } -func getDialect() string { - dialect := "sqlite" - switch { - case setting.UseSQLite3: - dialect = "sqlite" - case setting.UseMySQL: - dialect = "mysql" - case setting.UsePostgreSQL: - dialect = "pgsql" - case setting.UseMSSQL: - dialect = "mssql" - } - return dialect -} - func availableVersions() ([]string, error) { migrationsDir, err := os.Open("integrations/migration-test") if err != nil { diff --git a/integrations/testlogger.go b/integrations/testlogger.go index c50daead9b..43a1471f66 100644 --- a/integrations/testlogger.go +++ b/integrations/testlogger.go @@ -73,7 +73,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) { _, filename, line, _ := runtime.Caller(actualSkip) if log.CanColorStdout { - fmt.Fprintf(os.Stdout, "=== %s (%s:%d)\n", log.NewColoredValue(t.Name()), strings.TrimPrefix(filename, prefix), line) + fmt.Fprintf(os.Stdout, "=== %s (%s:%d)\n", fmt.Formatter(log.NewColoredValue(t.Name())), strings.TrimPrefix(filename, prefix), line) } else { fmt.Fprintf(os.Stdout, "=== %s (%s:%d)\n", t.Name(), strings.TrimPrefix(filename, prefix), line) } diff --git a/main.go b/main.go index 79c9b01114..30dbf27662 100644 --- a/main.go +++ b/main.go @@ -42,7 +42,7 @@ var ( func init() { setting.AppVer = Version - setting.AppBuiltWith = formatBuiltWith(Tags) + setting.AppBuiltWith = formatBuiltWith() // Grab the original help templates originalAppHelpTemplate = cli.AppHelpTemplate @@ -56,7 +56,7 @@ func main() { app.Usage = "A painless self-hosted Git service" app.Description = `By default, gitea will start serving using the webserver with no arguments - which can alternatively be run by running the subcommand web.` - app.Version = Version + formatBuiltWith(Tags) + app.Version = Version + formatBuiltWith() app.Commands = []cli.Command{ cmd.CmdWeb, cmd.CmdServ, @@ -179,7 +179,7 @@ DEFAULT CONFIGURATION: `, originalTemplate, setting.CustomPath, overrided, setting.CustomConf, setting.AppPath, setting.AppWorkPath) } -func formatBuiltWith(makeTags string) string { +func formatBuiltWith() string { var version = runtime.Version() if len(MakeVersion) > 0 { version = MakeVersion + ", " + runtime.Version() diff --git a/models/access_test.go b/models/access_test.go index d6a1c92b90..db6f655a67 100644 --- a/models/access_test.go +++ b/models/access_test.go @@ -10,13 +10,6 @@ import ( "github.com/stretchr/testify/assert" ) -var accessModes = []AccessMode{ - AccessModeRead, - AccessModeWrite, - AccessModeAdmin, - AccessModeOwner, -} - func TestAccessLevel(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) diff --git a/models/branches.go b/models/branches.go index abefa60f48..df3b69aa21 100644 --- a/models/branches.go +++ b/models/branches.go @@ -126,14 +126,14 @@ func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) } // GetProtectedBranchByRepoID getting protected branch by repo ID -func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) { +func GetProtectedBranchByRepoID(repoID int64) ([]*ProtectedBranch, error) { protectedBranches := make([]*ProtectedBranch, 0) - return protectedBranches, x.Where("repo_id = ?", RepoID).Desc("updated_unix").Find(&protectedBranches) + return protectedBranches, x.Where("repo_id = ?", repoID).Desc("updated_unix").Find(&protectedBranches) } // GetProtectedBranchBy getting protected branch by ID/Name -func GetProtectedBranchBy(repoID int64, BranchName string) (*ProtectedBranch, error) { - rel := &ProtectedBranch{RepoID: repoID, BranchName: BranchName} +func GetProtectedBranchBy(repoID int64, branchName string) (*ProtectedBranch, error) { + rel := &ProtectedBranch{RepoID: repoID, BranchName: branchName} has, err := x.Get(rel) if err != nil { return nil, err diff --git a/models/git_blame.go b/models/git_blame.go index 7b4fb64a70..2b439a23b9 100644 --- a/models/git_blame.go +++ b/models/git_blame.go @@ -40,7 +40,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) { scanner := r.scanner if r.lastSha != nil { - blamePart = &BlamePart{*r.lastSha, make([]string, 0, 0)} + blamePart = &BlamePart{*r.lastSha, make([]string, 0)} } for scanner.Scan() { @@ -56,7 +56,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) { sha1 := lines[1] if blamePart == nil { - blamePart = &BlamePart{sha1, make([]string, 0, 0)} + blamePart = &BlamePart{sha1, make([]string, 0)} } if blamePart.Sha != sha1 { diff --git a/models/git_diff.go b/models/git_diff.go index ac2a5f90d7..a6ea7306d4 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -384,13 +384,9 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi // headers + hunk header newHunk := make([]string, headerLines) // transfer existing headers - for idx, lof := range hunk[:headerLines] { - newHunk[idx] = lof - } + copy(newHunk, hunk[:headerLines]) // transfer last n lines - for _, lof := range hunk[len(hunk)-numbersOfLine-1:] { - newHunk = append(newHunk, lof) - } + newHunk = append(newHunk, hunk[len(hunk)-numbersOfLine-1:]...) // calculate newBegin, ... by counting lines for i := len(hunk) - 1; i >= len(hunk)-numbersOfLine; i-- { switch hunk[i][0] { @@ -582,7 +578,10 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D diff.Files = append(diff.Files, curFile) if len(diff.Files) >= maxFiles { diff.IsIncomplete = true - io.Copy(ioutil.Discard, reader) + _, err := io.Copy(ioutil.Discard, reader) + if err != nil { + return nil, fmt.Errorf("Copy: %v", err) + } break } curFileLinesCount = 0 diff --git a/models/git_diff_test.go b/models/git_diff_test.go index 2111e9044f..deca7c8d4a 100644 --- a/models/git_diff_test.go +++ b/models/git_diff_test.go @@ -17,12 +17,6 @@ func assertEqual(t *testing.T, s1 string, s2 template.HTML) { } } -func assertLineEqual(t *testing.T, d1 *DiffLine, d2 *DiffLine) { - if d1 != d2 { - t.Errorf("%v should be equal %v", d1, d2) - } -} - func TestDiffToHTML(t *testing.T) { assertEqual(t, "+foo bar biz", diffToHTML([]dmp.Diff{ {Type: dmp.DiffEqual, Text: "foo "}, diff --git a/models/issue.go b/models/issue.go index 999bd2f7a9..27298b8a86 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1330,7 +1330,7 @@ func sortIssuesSession(sess *xorm.Session, sortType string) { } } -func (opts *IssuesOptions) setupSession(sess *xorm.Session) error { +func (opts *IssuesOptions) setupSession(sess *xorm.Session) { if opts.Page >= 0 && opts.PageSize > 0 { var start int if opts.Page == 0 { @@ -1389,7 +1389,6 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) error { fmt.Sprintf("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d", i, labelID)) } } - return nil } // CountIssuesByRepo map from repoID to number of issues matching the options @@ -1397,9 +1396,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) { sess := x.NewSession() defer sess.Close() - if err := opts.setupSession(sess); err != nil { - return nil, err - } + opts.setupSession(sess) countsSlice := make([]*struct { RepoID int64 @@ -1424,9 +1421,7 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { sess := x.NewSession() defer sess.Close() - if err := opts.setupSession(sess); err != nil { - return nil, err - } + opts.setupSession(sess) sortIssuesSession(sess, opts.SortType) issues := make([]*Issue, 0, setting.UI.IssuePagingNum) diff --git a/models/issue_comment.go b/models/issue_comment.go index 0d2e917f85..d75d9d7db1 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -171,17 +171,6 @@ func (c *Comment) loadPoster(e Engine) (err error) { return err } -func (c *Comment) loadAttachments(e Engine) (err error) { - if len(c.Attachments) > 0 { - return - } - c.Attachments, err = getAttachmentsByCommentID(e, c.ID) - if err != nil { - log.Error("getAttachmentsByCommentID[%d]: %v", c.ID, err) - } - return err -} - // AfterDelete is invoked from XORM after the object is deleted. func (c *Comment) AfterDelete() { if c.ID <= 0 { @@ -463,7 +452,7 @@ func (c *Comment) LoadReview() error { return c.loadReview(x) } -func (c *Comment) checkInvalidation(e Engine, doer *User, repo *git.Repository, branch string) error { +func (c *Comment) checkInvalidation(doer *User, repo *git.Repository, branch string) error { // FIXME differentiate between previous and proposed line commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine())) if err != nil { @@ -479,7 +468,7 @@ func (c *Comment) checkInvalidation(e Engine, doer *User, repo *git.Repository, // CheckInvalidation checks if the line of code comment got changed by another commit. // If the line got changed the comment is going to be invalidated. func (c *Comment) CheckInvalidation(repo *git.Repository, doer *User, branch string) error { - return c.checkInvalidation(x, doer, repo, branch) + return c.checkInvalidation(doer, repo, branch) } // DiffSide returns "previous" if Comment.Line is a LOC of the previous changes and "proposed" if it is a LOC of the proposed changes. @@ -915,7 +904,7 @@ func CreateCodeComment(doer *User, repo *Repository, issue *Issue, content, tree commit, err := gitRepo.LineBlame(pr.GetGitRefName(), gitRepo.Path, treePath, uint(line)) if err == nil { commitID = commit.ID.String() - } else if err != nil && !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") { + } else if !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") { return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err) } } diff --git a/models/issue_comment_list.go b/models/issue_comment_list.go index a8c8123280..ae2a89a01a 100644 --- a/models/issue_comment_list.go +++ b/models/issue_comment_list.go @@ -36,7 +36,7 @@ func (comments CommentList) loadPosters(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit posterIDs = posterIDs[limit:] } @@ -94,13 +94,13 @@ func (comments CommentList) loadLabels(e Engine) error { var label Label err = rows.Scan(&label) if err != nil { - rows.Close() + _ = rows.Close() return err } commentLabels[label.ID] = &label } - rows.Close() - left = left - limit + _ = rows.Close() + left -= limit labelIDs = labelIDs[limit:] } @@ -143,7 +143,7 @@ func (comments CommentList) loadMilestones(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit milestoneIDs = milestoneIDs[limit:] } @@ -186,7 +186,7 @@ func (comments CommentList) loadOldMilestones(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit milestoneIDs = milestoneIDs[limit:] } @@ -236,9 +236,9 @@ func (comments CommentList) loadAssignees(e Engine) error { assignees[user.ID] = &user } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit assigneeIDs = assigneeIDs[limit:] } @@ -310,9 +310,9 @@ func (comments CommentList) loadIssues(e Engine) error { issues[issue.ID] = &issue } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit issueIDs = issueIDs[limit:] } @@ -361,15 +361,15 @@ func (comments CommentList) loadDependentIssues(e Engine) error { var issue Issue err = rows.Scan(&issue) if err != nil { - rows.Close() + _ = rows.Close() return err } issues[issue.ID] = &issue } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit issueIDs = issueIDs[limit:] } @@ -406,14 +406,14 @@ func (comments CommentList) loadAttachments(e Engine) (err error) { var attachment Attachment err = rows.Scan(&attachment) if err != nil { - rows.Close() + _ = rows.Close() return err } attachments[attachment.CommentID] = append(attachments[attachment.CommentID], &attachment) } - rows.Close() - left = left - limit + _ = rows.Close() + left -= limit commentsIDs = commentsIDs[limit:] } @@ -457,15 +457,15 @@ func (comments CommentList) loadReviews(e Engine) error { var review Review err = rows.Scan(&review) if err != nil { - rows.Close() + _ = rows.Close() return err } reviews[review.ID] = &review } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit reviewIDs = reviewIDs[limit:] } diff --git a/models/issue_label.go b/models/issue_label.go index 38266f3e7c..363d4bb814 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -401,14 +401,6 @@ func NewIssueLabels(issue *Issue, labels []*Label, doer *User) (err error) { return sess.Commit() } -func getIssueLabels(e Engine, issueID int64) ([]*IssueLabel, error) { - issueLabels := make([]*IssueLabel, 0, 10) - return issueLabels, e. - Where("issue_id=?", issueID). - Asc("label_id"). - Find(&issueLabels) -} - func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (err error) { if count, err := e.Delete(&IssueLabel{ IssueID: issue.ID, diff --git a/models/issue_list.go b/models/issue_list.go index a1aab488fc..4ddb32da13 100644 --- a/models/issue_list.go +++ b/models/issue_list.go @@ -7,6 +7,8 @@ package models import ( "fmt" + "code.gitea.io/gitea/modules/log" + "github.com/go-xorm/builder" ) @@ -47,7 +49,7 @@ func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) { if err != nil { return nil, fmt.Errorf("find repository: %v", err) } - left = left - limit + left -= limit repoIDs = repoIDs[limit:] } @@ -91,7 +93,7 @@ func (issues IssueList) loadPosters(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit posterIDs = posterIDs[limit:] } @@ -146,13 +148,21 @@ func (issues IssueList) loadLabels(e Engine) error { var labelIssue LabelIssue err = rows.Scan(&labelIssue) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadLabels: Close: %v", err) + } return err } issueLabels[labelIssue.IssueLabel.IssueID] = append(issueLabels[labelIssue.IssueLabel.IssueID], labelIssue.Label) } - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadLabels: Close: %v", err) + } + left -= limit issueIDs = issueIDs[limit:] } @@ -191,7 +201,7 @@ func (issues IssueList) loadMilestones(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit milestoneIDs = milestoneIDs[limit:] } @@ -231,15 +241,22 @@ func (issues IssueList) loadAssignees(e Engine) error { var assigneeIssue AssigneeIssue err = rows.Scan(&assigneeIssue) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAssignees: Close: %v", err) + } return err } assignees[assigneeIssue.IssueAssignee.IssueID] = append(assignees[assigneeIssue.IssueAssignee.IssueID], assigneeIssue.Assignee) } - rows.Close() - - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAssignees: Close: %v", err) + } + left -= limit issueIDs = issueIDs[limit:] } @@ -283,14 +300,21 @@ func (issues IssueList) loadPullRequests(e Engine) error { var pr PullRequest err = rows.Scan(&pr) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadPullRequests: Close: %v", err) + } return err } pullRequestMaps[pr.IssueID] = &pr } - - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadPullRequests: Close: %v", err) + } + left -= limit issuesIDs = issuesIDs[limit:] } @@ -325,14 +349,21 @@ func (issues IssueList) loadAttachments(e Engine) (err error) { var attachment Attachment err = rows.Scan(&attachment) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAttachments: Close: %v", err) + } return err } attachments[attachment.IssueID] = append(attachments[attachment.IssueID], &attachment) } - - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAttachments: Close: %v", err) + } + left -= limit issuesIDs = issuesIDs[limit:] } @@ -368,13 +399,21 @@ func (issues IssueList) loadComments(e Engine, cond builder.Cond) (err error) { var comment Comment err = rows.Scan(&comment) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadComments: Close: %v", err) + } return err } comments[comment.IssueID] = append(comments[comment.IssueID], &comment) } - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadComments: Close: %v", err) + } + left -= limit issuesIDs = issuesIDs[limit:] } @@ -422,13 +461,21 @@ func (issues IssueList) loadTotalTrackedTimes(e Engine) (err error) { var totalTime totalTimesByIssue err = rows.Scan(&totalTime) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadTotalTrackedTimes: Close: %v", err) + } return err } trackedTimes[totalTime.IssueID] = totalTime.Time } - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadTotalTrackedTimes: Close: %v", err) + } + left -= limit ids = ids[limit:] } @@ -439,33 +486,33 @@ func (issues IssueList) loadTotalTrackedTimes(e Engine) (err error) { } // loadAttributes loads all attributes, expect for attachments and comments -func (issues IssueList) loadAttributes(e Engine) (err error) { - if _, err = issues.loadRepositories(e); err != nil { - return +func (issues IssueList) loadAttributes(e Engine) error { + if _, err := issues.loadRepositories(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadRepositories: %v", err) } - if err = issues.loadPosters(e); err != nil { - return + if err := issues.loadPosters(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadPosters: %v", err) } - if err = issues.loadLabels(e); err != nil { - return + if err := issues.loadLabels(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadLabels: %v", err) } - if err = issues.loadMilestones(e); err != nil { - return + if err := issues.loadMilestones(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadMilestones: %v", err) } - if err = issues.loadAssignees(e); err != nil { - return + if err := issues.loadAssignees(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadAssignees: %v", err) } - if err = issues.loadPullRequests(e); err != nil { - return + if err := issues.loadPullRequests(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadPullRequests: %v", err) } - if err = issues.loadTotalTrackedTimes(e); err != nil { - return + if err := issues.loadTotalTrackedTimes(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadTotalTrackedTimes: %v", err) } return nil diff --git a/models/log.go b/models/log.go index 4994545c5f..38d6caf07c 100644 --- a/models/log.go +++ b/models/log.go @@ -15,7 +15,6 @@ import ( // XORMLogBridge a logger bridge from Logger to xorm type XORMLogBridge struct { showSQL bool - level core.LogLevel logger *log.Logger } @@ -34,42 +33,42 @@ func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...inter // Debug show debug log func (l *XORMLogBridge) Debug(v ...interface{}) { - l.Log(2, log.DEBUG, fmt.Sprint(v...)) + _ = l.Log(2, log.DEBUG, fmt.Sprint(v...)) } // Debugf show debug log func (l *XORMLogBridge) Debugf(format string, v ...interface{}) { - l.Log(2, log.DEBUG, format, v...) + _ = l.Log(2, log.DEBUG, format, v...) } // Error show error log func (l *XORMLogBridge) Error(v ...interface{}) { - l.Log(2, log.ERROR, fmt.Sprint(v...)) + _ = l.Log(2, log.ERROR, fmt.Sprint(v...)) } // Errorf show error log func (l *XORMLogBridge) Errorf(format string, v ...interface{}) { - l.Log(2, log.ERROR, format, v...) + _ = l.Log(2, log.ERROR, format, v...) } // Info show information level log func (l *XORMLogBridge) Info(v ...interface{}) { - l.Log(2, log.INFO, fmt.Sprint(v...)) + _ = l.Log(2, log.INFO, fmt.Sprint(v...)) } // Infof show information level log func (l *XORMLogBridge) Infof(format string, v ...interface{}) { - l.Log(2, log.INFO, format, v...) + _ = l.Log(2, log.INFO, format, v...) } // Warn show warning log func (l *XORMLogBridge) Warn(v ...interface{}) { - l.Log(2, log.WARN, fmt.Sprint(v...)) + _ = l.Log(2, log.WARN, fmt.Sprint(v...)) } // Warnf show warnning log func (l *XORMLogBridge) Warnf(format string, v ...interface{}) { - l.Log(2, log.WARN, format, v...) + _ = l.Log(2, log.WARN, format, v...) } // Level get logger level diff --git a/models/login_source.go b/models/login_source.go index 9b8173b84d..8eefec4ae5 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -164,8 +164,7 @@ func Cell2Int64(val xorm.Cell) int64 { // BeforeSet is invoked from XORM before setting the value of a field of this object. func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) { - switch colName { - case "type": + if colName == "type" { switch LoginType(Cell2Int64(val)) { case LoginLDAP, LoginDLDAP: source.Cfg = new(LDAPConfig) @@ -282,10 +281,12 @@ func CreateLoginSource(source *LoginSource) error { oAuth2Config := source.OAuth2() err = oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) err = wrapOpenIDConnectInitializeError(err, source.Name, oAuth2Config) - if err != nil { // remove the LoginSource in case of errors while registering OAuth2 providers - x.Delete(source) + if _, err := x.Delete(source); err != nil { + log.Error("CreateLoginSource: Error while wrapOpenIDConnectInitializeError: %v", err) + } + return err } } return err @@ -325,10 +326,12 @@ func UpdateSource(source *LoginSource) error { oAuth2Config := source.OAuth2() err = oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) err = wrapOpenIDConnectInitializeError(err, source.Name, oAuth2Config) - if err != nil { // restore original values since we cannot update the provider it self - x.ID(source.ID).AllCols().Update(originalLoginSource) + if _, err := x.ID(source.ID).AllCols().Update(originalLoginSource); err != nil { + log.Error("UpdateSource: Error while wrapOpenIDConnectInitializeError: %v", err) + } + return err } } return err @@ -385,7 +388,7 @@ func composeFullName(firstname, surname, username string) string { } var ( - alphaDashDotPattern = regexp.MustCompile("[^\\w-\\.]") + alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) ) // LoginViaLDAP queries if login/password is valid against the LDAP directory pool, @@ -401,7 +404,7 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR if !autoRegister { if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { - RewriteAllPublicKeys() + return user, RewriteAllPublicKeys() } return user, nil @@ -435,7 +438,7 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR err := CreateUser(user) if err == nil && isAttributeSSHPublicKeySet && addLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { - RewriteAllPublicKeys() + err = RewriteAllPublicKeys() } return user, err diff --git a/models/mail.go b/models/mail.go index 6be0df95ba..2bb07607a4 100644 --- a/models/mail.go +++ b/models/mail.go @@ -157,10 +157,13 @@ func composeTplData(subject, body, link string) map[string]interface{} { func composeIssueCommentMessage(issue *Issue, doer *User, content string, comment *Comment, tplName base.TplName, tos []string, info string) *mailer.Message { subject := issue.mailSubject() - issue.LoadRepo() + err := issue.LoadRepo() + if err != nil { + log.Error("LoadRepo: %v", err) + } body := string(markup.RenderByType(markdown.MarkupName, []byte(content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas())) - data := make(map[string]interface{}, 10) + var data = make(map[string]interface{}, 10) if comment != nil { data = composeTplData(subject, body, issue.HTMLURL()+"#"+comment.HashTag()) } else { diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index b95a74c362..e8fb42c492 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -399,7 +399,7 @@ func trimCommitActionAppURLPrefix(x *xorm.Engine) error { return fmt.Errorf("marshal action content[%d]: %v", actID, err) } - if _, err = sess.Id(actID).Update(&Action{ + if _, err = sess.ID(actID).Update(&Action{ Content: string(p), }); err != nil { return fmt.Errorf("update action[%d]: %v", actID, err) @@ -503,7 +503,7 @@ func attachmentRefactor(x *xorm.Engine) error { // Update database first because this is where error happens the most often. for _, attach := range attachments { - if _, err = sess.Id(attach.ID).Update(attach); err != nil { + if _, err = sess.ID(attach.ID).Update(attach); err != nil { return err } @@ -581,7 +581,7 @@ func renamePullRequestFields(x *xorm.Engine) (err error) { if pull.Index == 0 { continue } - if _, err = sess.Id(pull.ID).Update(pull); err != nil { + if _, err = sess.ID(pull.ID).Update(pull); err != nil { return err } } @@ -661,7 +661,7 @@ func generateOrgRandsAndSalt(x *xorm.Engine) (err error) { if org.Salt, err = generate.GetRandomString(10); err != nil { return err } - if _, err = sess.Id(org.ID).Update(org); err != nil { + if _, err = sess.ID(org.ID).Update(org); err != nil { return err } } diff --git a/models/migrations/v27.go b/models/migrations/v27.go index bd115cf937..e87c7ab68f 100644 --- a/models/migrations/v27.go +++ b/models/migrations/v27.go @@ -58,13 +58,13 @@ func convertIntervalToDuration(x *xorm.Engine) (err error) { return fmt.Errorf("Query repositories: %v", err) } for _, mirror := range mirrors { - mirror.Interval = mirror.Interval * time.Hour + mirror.Interval *= time.Hour if mirror.Interval < setting.Mirror.MinInterval { log.Info("Mirror interval less than Mirror.MinInterval, setting default interval: repo id %v", mirror.RepoID) mirror.Interval = setting.Mirror.DefaultInterval } log.Debug("Mirror interval set to %v for repo id %v", mirror.Interval, mirror.RepoID) - _, err := sess.Id(mirror.ID).Cols("interval").Update(mirror) + _, err := sess.ID(mirror.ID).Cols("interval").Update(mirror) if err != nil { return fmt.Errorf("update mirror interval failed: %v", err) } diff --git a/models/migrations/v78.go b/models/migrations/v78.go index 7ca112dbd5..310c479d01 100644 --- a/models/migrations/v78.go +++ b/models/migrations/v78.go @@ -48,6 +48,9 @@ func renameRepoIsBareToIsEmpty(x *xorm.Engine) error { if len(indexes) >= 1 { _, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository") + if err != nil { + return fmt.Errorf("Drop index failed: %v", err) + } } } else { _, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository") diff --git a/models/migrations/v85.go b/models/migrations/v85.go index 1fe85ac408..d511628b8d 100644 --- a/models/migrations/v85.go +++ b/models/migrations/v85.go @@ -58,6 +58,9 @@ func hashAppToken(x *xorm.Engine) error { if len(indexes) >= 1 { _, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token") + if err != nil { + return err + } } } else { _, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token") diff --git a/models/models.go b/models/models.go index c1d4c100d0..5752a8edd6 100644 --- a/models/models.go +++ b/models/models.go @@ -48,6 +48,7 @@ type Engine interface { Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *xorm.Session SQL(interface{}, ...interface{}) *xorm.Session Where(interface{}, ...interface{}) *xorm.Session + Asc(colNames ...string) *xorm.Session } var ( @@ -181,14 +182,14 @@ func parsePostgreSQLHostPort(info string) (string, string) { return host, port } -func getPostgreSQLConnectionString(DBHost, DBUser, DBPasswd, DBName, DBParam, DBSSLMode string) (connStr string) { - host, port := parsePostgreSQLHostPort(DBHost) +func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) { + host, port := parsePostgreSQLHostPort(dbHost) if host[0] == '/' { // looks like a unix socket connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s", - url.PathEscape(DBUser), url.PathEscape(DBPasswd), port, DBName, DBParam, DBSSLMode, host) + url.PathEscape(dbUser), url.PathEscape(dbPasswd), port, dbName, dbParam, dbsslMode, host) } else { connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s", - url.PathEscape(DBUser), url.PathEscape(DBPasswd), host, port, DBName, DBParam, DBSSLMode) + url.PathEscape(dbUser), url.PathEscape(dbPasswd), host, port, dbName, dbParam, dbsslMode) } return } diff --git a/models/notification.go b/models/notification.go index cda2916fae..f83fe63e5a 100644 --- a/models/notification.go +++ b/models/notification.go @@ -119,7 +119,10 @@ func createOrUpdateIssueNotifications(e Engine, issue *Issue, notificationAuthor } } - issue.loadRepo(e) + err = issue.loadRepo(e) + if err != nil { + return err + } for _, watch := range watches { issue.Repo.Units = nil diff --git a/models/oauth2.go b/models/oauth2.go index 10bce31924..bf4446229a 100644 --- a/models/oauth2.go +++ b/models/oauth2.go @@ -106,7 +106,10 @@ func InitOAuth2() error { for _, source := range loginSources { oAuth2Config := source.OAuth2() - oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) + err := oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) + if err != nil { + return err + } } return nil } diff --git a/models/oauth2_application.go b/models/oauth2_application.go index 1e69dd6430..63d2e7ce5e 100644 --- a/models/oauth2_application.go +++ b/models/oauth2_application.go @@ -142,6 +142,9 @@ func GetOAuth2ApplicationByID(id int64) (app *OAuth2Application, err error) { func getOAuth2ApplicationByID(e Engine, id int64) (app *OAuth2Application, err error) { app = new(OAuth2Application) has, err := e.ID(id).Get(app) + if err != nil { + return nil, err + } if !has { return nil, ErrOAuthApplicationNotFound{ID: id} } @@ -295,10 +298,10 @@ func (code *OAuth2AuthorizationCode) invalidate(e Engine) error { // ValidateCodeChallenge validates the given verifier against the saved code challenge. This is part of the PKCE implementation. func (code *OAuth2AuthorizationCode) ValidateCodeChallenge(verifier string) bool { - return code.validateCodeChallenge(x, verifier) + return code.validateCodeChallenge(verifier) } -func (code *OAuth2AuthorizationCode) validateCodeChallenge(e Engine, verifier string) bool { +func (code *OAuth2AuthorizationCode) validateCodeChallenge(verifier string) bool { switch code.CodeChallengeMethod { case "S256": // base64url(SHA256(verifier)) see https://tools.ietf.org/html/rfc7636#section-4.6 diff --git a/models/org.go b/models/org.go index 6511072e2b..65002eadff 100644 --- a/models/org.go +++ b/models/org.go @@ -172,7 +172,9 @@ func CreateOrganization(org, owner *User) (err error) { } if _, err = sess.Insert(&units); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("CreateOrganization: sess.Rollback: %v", err) + } return err } @@ -376,10 +378,7 @@ func HasOrgVisible(org *User, user *User) bool { func hasOrgVisible(e Engine, org *User, user *User) bool { // Not SignedUser if user == nil { - if org.Visibility == structs.VisibleTypePublic { - return true - } - return false + return org.Visibility == structs.VisibleTypePublic } if user.IsAdmin { @@ -485,10 +484,14 @@ func AddOrgUser(orgID, uid int64) error { } if _, err := sess.Insert(ou); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("AddOrgUser: sess.Rollback: %v", err) + } return err } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("AddOrgUser: sess.Rollback: %v", err) + } return err } diff --git a/models/org_team.go b/models/org_team.go index 49d06896e5..dcf0743740 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -287,7 +287,8 @@ func NewTeam(t *Team) (err error) { has, err := x.ID(t.OrgID).Get(new(User)) if err != nil { return err - } else if !has { + } + if !has { return ErrOrgNotExist{t.OrgID, ""} } @@ -298,7 +299,8 @@ func NewTeam(t *Team) (err error) { Get(new(Team)) if err != nil { return err - } else if has { + } + if has { return ErrTeamAlreadyExist{t.OrgID, t.LowerName} } @@ -309,7 +311,10 @@ func NewTeam(t *Team) (err error) { } if _, err = sess.Insert(t); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewTeam sess.Rollback: %v", errRollback) + } return err } @@ -319,14 +324,20 @@ func NewTeam(t *Team) (err error) { unit.TeamID = t.ID } if _, err = sess.Insert(&t.Units); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewTeam sess.Rollback: %v", errRollback) + } return err } } // Update organization number of teams. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewTeam sess.Rollback: %v", errRollback) + } return err } return sess.Commit() @@ -412,7 +423,10 @@ func UpdateTeam(t *Team, authChanged bool) (err error) { } if _, err = sess.Insert(&t.Units); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("UpdateTeam sess.Rollback: %v", errRollback) + } return err } } @@ -841,7 +855,10 @@ func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) { } if _, err = sess.Insert(units); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("UpdateTeamUnits sess.Rollback: %v", errRollback) + } return err } diff --git a/models/org_test.go b/models/org_test.go index b484208be1..a2ebf1f60b 100644 --- a/models/org_test.go +++ b/models/org_test.go @@ -242,10 +242,10 @@ func TestGetOrgByName(t *testing.T) { assert.EqualValues(t, 3, org.ID) assert.Equal(t, "user3", org.Name) - org, err = GetOrgByName("user2") // user2 is an individual + _, err = GetOrgByName("user2") // user2 is an individual assert.True(t, IsErrOrgNotExist(err)) - org, err = GetOrgByName("") // corner case + _, err = GetOrgByName("") // corner case assert.True(t, IsErrOrgNotExist(err)) } @@ -499,7 +499,7 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) { func TestAccessibleReposEnv_RepoIDs(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) - testSuccess := func(userID, page, pageSize int64, expectedRepoIDs []int64) { + testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) { env, err := org.AccessibleReposEnv(userID) assert.NoError(t, err) repoIDs, err := env.RepoIDs(1, 100) diff --git a/models/pull.go b/models/pull.go index 1f03dd9b0f..7a168181e2 100644 --- a/models/pull.go +++ b/models/pull.go @@ -192,15 +192,19 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest { } } if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil { + log.Error("pr.BaseRepo.GetBranch[%d]: %v", pr.BaseBranch, err) return nil } if baseCommit, err = baseBranch.GetCommit(); err != nil { + log.Error("baseBranch.GetCommit[%d]: %v", pr.ID, err) return nil } if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil { + log.Error("pr.HeadRepo.GetBranch[%d]: %v", pr.HeadBranch, err) return nil } if headCommit, err = headBranch.GetCommit(); err != nil { + log.Error("headBranch.GetCommit[%d]: %v", pr.ID, err) return nil } apiBaseBranchInfo := &api.PRBranchInfo{ @@ -218,7 +222,10 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest { Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false), } - pr.Issue.loadRepo(e) + if err = pr.Issue.loadRepo(e); err != nil { + log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err) + return nil + } apiPullRequest := &api.PullRequest{ ID: pr.ID, @@ -420,7 +427,11 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle if err != nil { return err } - defer RemoveTemporaryPath(tmpBasePath) + defer func() { + if err := RemoveTemporaryPath(tmpBasePath); err != nil { + log.Error("Merge: RemoveTemporaryPath: %s", err) + } + }() headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name) @@ -1142,7 +1153,9 @@ func (pr *PullRequest) UpdatePatch() (err error) { return fmt.Errorf("AddRemote: %v", err) } defer func() { - headGitRepo.RemoveRemote(tmpRemote) + if err := headGitRepo.RemoveRemote(tmpRemote); err != nil { + log.Error("UpdatePatch: RemoveRemote: %s", err) + } }() pr.MergeBase, _, err = headGitRepo.GetMergeBase(tmpRemote, pr.BaseBranch, pr.HeadBranch) if err != nil { @@ -1180,7 +1193,11 @@ func (pr *PullRequest) PushToBaseRepo() (err error) { return fmt.Errorf("headGitRepo.AddRemote: %v", err) } // Make sure to remove the remote even if the push fails - defer headGitRepo.RemoveRemote(tmpRemoteName) + defer func() { + if err := headGitRepo.RemoveRemote(tmpRemoteName); err != nil { + log.Error("PushToBaseRepo: RemoveRemote: %s", err) + } + }() headFile := pr.GetGitRefName() diff --git a/models/pull_test.go b/models/pull_test.go index 1dad664077..5a53474ac4 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -94,7 +94,7 @@ func TestGetUnmergedPullRequest(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(2), pr.ID) - pr, err = GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master") + _, err = GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master") assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } @@ -128,7 +128,7 @@ func TestGetPullRequestByIndex(t *testing.T) { assert.Equal(t, int64(1), pr.BaseRepoID) assert.Equal(t, int64(2), pr.Index) - pr, err = GetPullRequestByIndex(9223372036854775807, 9223372036854775807) + _, err = GetPullRequestByIndex(9223372036854775807, 9223372036854775807) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } @@ -151,7 +151,7 @@ func TestGetPullRequestByIssueID(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(2), pr.IssueID) - pr, err = GetPullRequestByIssueID(9223372036854775807) + _, err = GetPullRequestByIssueID(9223372036854775807) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } diff --git a/models/release.go b/models/release.go index b7ec4461f2..28a2891013 100644 --- a/models/release.go +++ b/models/release.go @@ -50,12 +50,12 @@ func (r *Release) loadAttributes(e Engine) error { } } if r.Publisher == nil { - r.Publisher, err = GetUserByID(r.PublisherID) + r.Publisher, err = getUserByID(e, r.PublisherID) if err != nil { return err } } - return GetReleaseAttachments(r) + return getReleaseAttachments(e, r) } // LoadAttributes load repo and publisher attributes for a release @@ -316,6 +316,10 @@ func (s releaseMetaSearch) Less(i, j int) bool { // GetReleaseAttachments retrieves the attachments for releases func GetReleaseAttachments(rels ...*Release) (err error) { + return getReleaseAttachments(x, rels...) +} + +func getReleaseAttachments(e Engine, rels ...*Release) (err error) { if len(rels) == 0 { return } @@ -335,11 +339,10 @@ func GetReleaseAttachments(rels ...*Release) (err error) { sort.Sort(sortedRels) // Select attachments - err = x. + err = e. Asc("release_id"). In("release_id", sortedRels.ID). Find(&attachments, Attachment{}) - if err != nil { return err } @@ -354,7 +357,6 @@ func GetReleaseAttachments(rels ...*Release) (err error) { } return - } type releaseSorter struct { @@ -493,7 +495,7 @@ func SyncReleasesWithTags(repo *Repository, gitRepo *git.Repository) error { return fmt.Errorf("GetTagCommitID: %v", err) } if git.IsErrNotExist(err) || commitID != rel.Sha1 { - if err := pushUpdateDeleteTag(repo, gitRepo, rel.TagName); err != nil { + if err := pushUpdateDeleteTag(repo, rel.TagName); err != nil { return fmt.Errorf("pushUpdateDeleteTag: %v", err) } } else { diff --git a/models/repo.go b/models/repo.go index a855c84939..a4a7521aa4 100644 --- a/models/repo.go +++ b/models/repo.go @@ -20,7 +20,6 @@ import ( "os" "path" "path/filepath" - "regexp" "sort" "strconv" "strings" @@ -744,10 +743,6 @@ func (repo *Repository) getUsersWithAccessMode(e Engine, mode AccessMode) (_ []* return users, nil } -var ( - descPattern = regexp.MustCompile(`https?://\S+`) -) - // DescriptionHTML does special handles to description and return HTML string. func (repo *Repository) DescriptionHTML() template.HTML { desc, err := markup.RenderDescriptionHTML([]byte(repo.Description), repo.HTMLURL(), repo.ComposeMetas()) @@ -1333,11 +1328,9 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err return fmt.Errorf("prepareWebhooks: %v", err) } go HookQueue.Add(repo.ID) - } else { + } else if err = repo.recalculateAccesses(e); err != nil { // Organization automatically called this in addRepository method. - if err = repo.recalculateAccesses(e); err != nil { - return fmt.Errorf("recalculateAccesses: %v", err) - } + return fmt.Errorf("recalculateAccesses: %v", err) } if setting.Service.AutoWatchNewRepos { @@ -1512,11 +1505,9 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error } else if err = t.addRepository(sess, repo); err != nil { return fmt.Errorf("add to owner team: %v", err) } - } else { + } else if err = repo.recalculateAccesses(sess); err != nil { // Organization called this in addRepository method. - if err = repo.recalculateAccesses(sess); err != nil { - return fmt.Errorf("recalculateAccesses: %v", err) - } + return fmt.Errorf("recalculateAccesses: %v", err) } // Update repository count. @@ -1864,7 +1855,10 @@ func DeleteRepository(doer *User, uid, repoID int64) error { repoPath := repo.repoPath(sess) removeAllWithNotice(sess, "Delete repository files", repoPath) - repo.deleteWiki(sess) + err = repo.deleteWiki(sess) + if err != nil { + return err + } // Remove attachment files. for i := range attachmentPaths { @@ -2522,7 +2516,7 @@ func (repo *Repository) GetUserFork(userID int64) (*Repository, error) { // CustomAvatarPath returns repository custom avatar file path. func (repo *Repository) CustomAvatarPath() string { // Avatar empty by default - if len(repo.Avatar) <= 0 { + if len(repo.Avatar) == 0 { return "" } return filepath.Join(setting.RepositoryAvatarUploadPath, repo.Avatar) @@ -2562,10 +2556,7 @@ func (repo *Repository) generateRandomAvatar(e Engine) error { // RemoveRandomAvatars removes the randomly generated avatars that were created for repositories func RemoveRandomAvatars() error { - var ( - err error - ) - err = x. + return x. Where("id > 0").BufferSize(setting.IterateBufferSize). Iterate(new(Repository), func(idx int, bean interface{}) error { @@ -2576,7 +2567,6 @@ func RemoveRandomAvatars() error { } return nil }) - return err } // RelAvatarLink returns a relative link to the repository's avatar. @@ -2587,7 +2577,7 @@ func (repo *Repository) RelAvatarLink() string { func (repo *Repository) relAvatarLink(e Engine) string { // If no avatar - path is empty avatarPath := repo.CustomAvatarPath() - if len(avatarPath) <= 0 || !com.IsFile(avatarPath) { + if len(avatarPath) == 0 || !com.IsFile(avatarPath) { switch mode := setting.RepositoryAvatarFallback; mode { case "image": return setting.RepositoryAvatarFallbackImage diff --git a/models/repo_activity.go b/models/repo_activity.go index fb1385a54b..04612ae1ef 100644 --- a/models/repo_activity.go +++ b/models/repo_activity.go @@ -114,7 +114,7 @@ func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int) v = append(v, u) } - sort.Slice(v[:], func(i, j int) bool { + sort.Slice(v, func(i, j int) bool { return v[i].Commits < v[j].Commits }) diff --git a/models/repo_branch.go b/models/repo_branch.go index 08c881fc24..dee6ef3d7e 100644 --- a/models/repo_branch.go +++ b/models/repo_branch.go @@ -75,7 +75,11 @@ func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName st if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("CreateNewBranch: RemoveTemporaryPath: %s", err) + } + }() if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{ Bare: true, @@ -117,7 +121,11 @@ func (repo *Repository) CreateNewBranchFromCommit(doer *User, commit, branchName if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("CreateNewBranchFromCommit: RemoveTemporaryPath: %s", err) + } + }() if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{ Bare: true, diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index 9d2935d581..0797f50430 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -142,7 +142,7 @@ func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode AccessMode } if _, err = sess. - Id(collaboration.ID). + ID(collaboration.ID). Cols("mode"). Update(collaboration); err != nil { return fmt.Errorf("update collaboration: %v", err) diff --git a/models/repo_list.go b/models/repo_list.go index 9686676eae..5655404f7c 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -148,19 +148,19 @@ func (s SearchOrderBy) String() string { // Strings for sorting result const ( SearchOrderByAlphabetically SearchOrderBy = "name ASC" - SearchOrderByAlphabeticallyReverse = "name DESC" - SearchOrderByLeastUpdated = "updated_unix ASC" - SearchOrderByRecentUpdated = "updated_unix DESC" - SearchOrderByOldest = "created_unix ASC" - SearchOrderByNewest = "created_unix DESC" - SearchOrderBySize = "size ASC" - SearchOrderBySizeReverse = "size DESC" - SearchOrderByID = "id ASC" - SearchOrderByIDReverse = "id DESC" - SearchOrderByStars = "num_stars ASC" - SearchOrderByStarsReverse = "num_stars DESC" - SearchOrderByForks = "num_forks ASC" - SearchOrderByForksReverse = "num_forks DESC" + SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" + SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" + SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" + SearchOrderByOldest SearchOrderBy = "created_unix ASC" + SearchOrderByNewest SearchOrderBy = "created_unix DESC" + SearchOrderBySize SearchOrderBy = "size ASC" + SearchOrderBySizeReverse SearchOrderBy = "size DESC" + SearchOrderByID SearchOrderBy = "id ASC" + SearchOrderByIDReverse SearchOrderBy = "id DESC" + SearchOrderByStars SearchOrderBy = "num_stars ASC" + SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" + SearchOrderByForks SearchOrderBy = "num_forks ASC" + SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" ) // SearchRepositoryByName takes keyword and part of repository name to search, diff --git a/models/repo_redirect.go b/models/repo_redirect.go index 813b3e6c9e..8847a0889c 100644 --- a/models/repo_redirect.go +++ b/models/repo_redirect.go @@ -4,7 +4,10 @@ package models -import "strings" +import ( + "code.gitea.io/gitea/modules/log" + "strings" +) // RepoRedirect represents that a repo name should be redirected to another type RepoRedirect struct { @@ -38,7 +41,10 @@ func NewRepoRedirect(ownerID, repoID int64, oldRepoName, newRepoName string) err } if err := deleteRepoRedirect(sess, ownerID, newRepoName); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewRepoRedirect sess.Rollback: %v", errRollback) + } return err } @@ -47,7 +53,10 @@ func NewRepoRedirect(ownerID, repoID int64, oldRepoName, newRepoName string) err LowerName: oldRepoName, RedirectRepoID: repoID, }); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewRepoRedirect sess.Rollback: %v", errRollback) + } return err } return sess.Commit() diff --git a/models/ssh_key.go b/models/ssh_key.go index fb5f9f399b..1f2288b13e 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -142,7 +142,7 @@ func parseKeyString(content string) (string, error) { if continuationLine || strings.ContainsAny(line, ":-") { continuationLine = strings.HasSuffix(line, "\\") } else { - keyContent = keyContent + line + keyContent += line } } @@ -392,7 +392,7 @@ func addKey(e Engine, key *PublicKey) (err error) { } // AddPublicKey adds new public key to database and authorized_keys file. -func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*PublicKey, error) { +func AddPublicKey(ownerID int64, name, content string, loginSourceID int64) (*PublicKey, error) { log.Trace(content) fingerprint, err := calcFingerprint(content) @@ -427,7 +427,7 @@ func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*Pu Content: content, Mode: AccessModeWrite, Type: KeyTypeUser, - LoginSourceID: LoginSourceID, + LoginSourceID: loginSourceID, } if err = addKey(sess, key); err != nil { return nil, fmt.Errorf("addKey: %v", err) @@ -491,10 +491,10 @@ func ListPublicKeys(uid int64) ([]*PublicKey, error) { } // ListPublicLdapSSHKeys returns a list of synchronized public ldap ssh keys belongs to given user and login source. -func ListPublicLdapSSHKeys(uid int64, LoginSourceID int64) ([]*PublicKey, error) { +func ListPublicLdapSSHKeys(uid int64, loginSourceID int64) ([]*PublicKey, error) { keys := make([]*PublicKey, 0, 5) return keys, x. - Where("owner_id = ? AND login_source_id = ?", uid, LoginSourceID). + Where("owner_id = ? AND login_source_id = ?", uid, loginSourceID). Find(&keys) } diff --git a/models/status.go b/models/status.go index a3db47f455..384f5693dc 100644 --- a/models/status.go +++ b/models/status.go @@ -87,7 +87,7 @@ func (status *CommitStatus) loadRepo(e Engine) (err error) { // APIURL returns the absolute APIURL to this commit-status. func (status *CommitStatus) APIURL() string { - status.loadRepo(x) + _ = status.loadRepo(x) return fmt.Sprintf("%sapi/v1/%s/statuses/%s", setting.AppURL, status.Repo.FullName(), status.SHA) } @@ -95,7 +95,7 @@ func (status *CommitStatus) APIURL() string { // APIFormat assumes some fields assigned with values: // Required - Repo, Creator func (status *CommitStatus) APIFormat() *api.Status { - status.loadRepo(x) + _ = status.loadRepo(x) apiStatus := &api.Status{ Created: status.CreatedUnix.AsTime(), Updated: status.CreatedUnix.AsTime(), @@ -219,7 +219,9 @@ func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error { } has, err := sess.Desc("index").Limit(1).Get(lastCommitStatus) if err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("newCommitStatus: sess.Rollback: %v", err) + } return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) } if has { @@ -231,7 +233,9 @@ func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error { // Insert new CommitStatus if _, err = sess.Insert(opts.CommitStatus); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("newCommitStatus: sess.Rollback: %v", err) + } return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) } diff --git a/models/token_test.go b/models/token_test.go index 9f2699a168..a74de8f818 100644 --- a/models/token_test.go +++ b/models/token_test.go @@ -36,11 +36,11 @@ func TestGetAccessTokenBySHA(t *testing.T) { assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash) assert.Equal(t, "e4efbf36", token.TokenLastEight) - token, err = GetAccessTokenBySHA("notahash") + _, err = GetAccessTokenBySHA("notahash") assert.Error(t, err) assert.True(t, IsErrAccessTokenNotExist(err)) - token, err = GetAccessTokenBySHA("") + _, err = GetAccessTokenBySHA("") assert.Error(t, err) assert.True(t, IsErrAccessTokenEmpty(err)) } diff --git a/models/update.go b/models/update.go index 0883cb0e01..3eb0990d3d 100644 --- a/models/update.go +++ b/models/update.go @@ -84,7 +84,7 @@ func PushUpdate(branch string, opt PushUpdateOptions) error { return nil } -func pushUpdateDeleteTag(repo *Repository, gitRepo *git.Repository, tagName string) error { +func pushUpdateDeleteTag(repo *Repository, tagName string) error { rel, err := GetRelease(repo.ID, tagName) if err != nil { if IsErrReleaseNotExist(err) { @@ -223,7 +223,7 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { // If is tag reference tagName := opts.RefFullName[len(git.TagPrefix):] if isDelRef { - err = pushUpdateDeleteTag(repo, gitRepo, tagName) + err = pushUpdateDeleteTag(repo, tagName) if err != nil { return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err) } diff --git a/models/user.go b/models/user.go index e29cf5b32a..2820d2edbc 100644 --- a/models/user.go +++ b/models/user.go @@ -1072,7 +1072,10 @@ func deleteUser(e *xorm.Session, u *User) error { if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deletePublicKeys: %v", err) } - rewriteAllPublicKeys(e) + err = rewriteAllPublicKeys(e) + if err != nil { + return err + } // ***** END: PublicKey ***** // ***** START: GPGPublicKey ***** @@ -1401,8 +1404,7 @@ func (opts *SearchUserOptions) toConds() builder.Cond { } else { exprCond = builder.Expr("org_user.org_id = \"user\".id") } - var accessCond = builder.NewCond() - accessCond = builder.Or( + accessCond := builder.Or( builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.OwnerID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited)) cond = cond.And(accessCond) @@ -1512,9 +1514,9 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) { } // addLdapSSHPublicKeys add a users public keys. Returns true if there are changes. -func addLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) bool { +func addLdapSSHPublicKeys(usr *User, s *LoginSource, sshPublicKeys []string) bool { var sshKeysNeedUpdate bool - for _, sshKey := range SSHPublicKeys { + for _, sshKey := range sshPublicKeys { _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshKey)) if err == nil { sshKeyName := fmt.Sprintf("%s-%s", s.Name, sshKey[0:40]) @@ -1536,7 +1538,7 @@ func addLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) boo } // synchronizeLdapSSHPublicKeys updates a users public keys. Returns true if there are changes. -func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) bool { +func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, sshPublicKeys []string) bool { var sshKeysNeedUpdate bool log.Trace("synchronizeLdapSSHPublicKeys[%s]: Handling LDAP Public SSH Key synchronization for user %s", s.Name, usr.Name) @@ -1554,7 +1556,7 @@ func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []str // Get Public Keys from LDAP and skip duplicate keys var ldapKeys []string - for _, v := range SSHPublicKeys { + for _, v := range sshPublicKeys { sshKeySplit := strings.Split(v, " ") if len(sshKeySplit) > 1 { ldapKey := strings.Join(sshKeySplit[:2], " ") @@ -1634,9 +1636,13 @@ func SyncExternalUsers() { // Find all users with this login type var users []*User - x.Where("login_type = ?", LoginLDAP). + err = x.Where("login_type = ?", LoginLDAP). And("login_source = ?", s.ID). Find(&users) + if err != nil { + log.Error("SyncExternalUsers: %v", err) + return + } sr := s.LDAP().SearchEntries() for _, su := range sr { @@ -1694,7 +1700,7 @@ func SyncExternalUsers() { // Check if user data has changed if (len(s.LDAP().AdminFilter) > 0 && usr.IsAdmin != su.IsAdmin) || - strings.ToLower(usr.Email) != strings.ToLower(su.Mail) || + !strings.EqualFold(usr.Email, su.Mail) || usr.FullName != fullName || !usr.IsActive { @@ -1718,7 +1724,10 @@ func SyncExternalUsers() { // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed if sshKeysNeedUpdate { - RewriteAllPublicKeys() + err = RewriteAllPublicKeys() + if err != nil { + log.Error("RewriteAllPublicKeys: %v", err) + } } // Deactivate users not present in LDAP diff --git a/models/user_mail.go b/models/user_mail.go index 39d1070c35..d929ba5a5d 100644 --- a/models/user_mail.go +++ b/models/user_mail.go @@ -134,7 +134,7 @@ func (email *EmailAddress) Activate() error { email.IsActivated = true if _, err := sess. - Id(email.ID). + ID(email.ID). Cols("is_activated"). Update(email); err != nil { return err diff --git a/models/user_openid_test.go b/models/user_openid_test.go index 711f92b9ff..18f84bef76 100644 --- a/models/user_openid_test.go +++ b/models/user_openid_test.go @@ -31,12 +31,12 @@ func TestGetUserOpenIDs(t *testing.T) { func TestGetUserByOpenID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - user, err := GetUserByOpenID("https://unknown") + _, err := GetUserByOpenID("https://unknown") if assert.Error(t, err) { assert.True(t, IsErrUserNotExist(err)) } - user, err = GetUserByOpenID("https://user1.domain1.tld") + user, err := GetUserByOpenID("https://user1.domain1.tld") if assert.NoError(t, err) { assert.Equal(t, user.ID, int64(1)) } diff --git a/models/webhook.go b/models/webhook.go index 7a28e37958..e3e11e5963 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -700,7 +700,10 @@ func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, log.Error("prepareWebhooks.JSONPayload: %v", err) } sig := hmac.New(sha256.New, []byte(w.Secret)) - sig.Write(data) + _, err = sig.Write(data) + if err != nil { + log.Error("prepareWebhooks.sigWrite: %v", err) + } signature = hex.EncodeToString(sig.Sum(nil)) } @@ -930,8 +933,7 @@ func InitDeliverHooks() { return nil, err } - conn.SetDeadline(time.Now().Add(timeout)) - return conn, nil + return conn, conn.SetDeadline(time.Now().Add(timeout)) }, }, diff --git a/models/webhook_discord.go b/models/webhook_discord.go index 0029e94fca..d7a2de0d11 100644 --- a/models/webhook_discord.go +++ b/models/webhook_discord.go @@ -490,7 +490,7 @@ func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*Discor Embeds: []DiscordEmbed{ { Title: title, - Description: fmt.Sprintf("%s", p.Release.Note), + Description: p.Release.Note, URL: url, Color: color, Author: DiscordEmbedAuthor{ diff --git a/models/wiki.go b/models/wiki.go index bcf97c0765..9ae3386333 100644 --- a/models/wiki.go +++ b/models/wiki.go @@ -115,7 +115,11 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("Merge: RemoveTemporaryPath: %s", err) + } + }() cloneOpts := git.CloneRepoOptions{ Bare: true, @@ -246,7 +250,11 @@ func (repo *Repository) DeleteWikiPage(doer *User, wikiName string) (err error) if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("Merge: RemoveTemporaryPath: %s", err) + } + }() if err := git.Clone(repo.WikiPath(), basePath, git.CloneRepoOptions{ Bare: true, diff --git a/modules/auth/auth.go b/modules/auth/auth.go index edb596c240..2a2ee40492 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -214,10 +214,8 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) if err = models.UpdateAccessToken(token); err != nil { log.Error("UpdateAccessToken: %v", err) } - } else { - if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) { - log.Error("GetAccessTokenBySha: %v", err) - } + } else if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) { + log.Error("GetAccessTokenBySha: %v", err) } if u == nil { @@ -301,12 +299,6 @@ func GetInclude(field reflect.StructField) string { return getRuleBody(field, "Include(") } -// FIXME: struct contains a struct -func validateStruct(obj interface{}) binding.Errors { - - return nil -} - func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaron.Locale) binding.Errors { if errs.Len() == 0 { return errs diff --git a/modules/auth/oauth2/oauth2.go b/modules/auth/oauth2/oauth2.go index 5684f44a89..a2d7116211 100644 --- a/modules/auth/oauth2/oauth2.go +++ b/modules/auth/oauth2/oauth2.go @@ -220,8 +220,7 @@ func GetDefaultProfileURL(provider string) string { // GetDefaultEmailURL return the default email url for the given provider func GetDefaultEmailURL(provider string) string { - switch provider { - case "github": + if provider == "github" { return github.EmailURL } return "" diff --git a/modules/auth/openid/discovery_cache_test.go b/modules/auth/openid/discovery_cache_test.go index 2e37058cc3..931e5c7945 100644 --- a/modules/auth/openid/discovery_cache_test.go +++ b/modules/auth/openid/discovery_cache_test.go @@ -39,7 +39,7 @@ func TestTimedDiscoveryCache(t *testing.T) { t.Errorf("Expected nil, got %v", di) } - // Sleep one second and try retrive again + // Sleep one second and try retrieve again time.Sleep(1 * time.Second) if di := dc.Get("foo"); di != nil { diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 8b9e5877d9..0c8bd30abc 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -253,7 +253,7 @@ func (f UpdateThemeForm) IsThemeExists() bool { var exists bool for _, v := range setting.UI.Themes { - if strings.ToLower(v) == strings.ToLower(f.Theme) { + if strings.EqualFold(v, f.Theme) { exists = true break } diff --git a/modules/base/tool.go b/modules/base/tool.go index dcf9155a07..4893abff71 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -44,21 +44,21 @@ var UTF8BOM = []byte{'\xef', '\xbb', '\xbf'} // EncodeMD5 encodes string to md5 hex value. func EncodeMD5(str string) string { m := md5.New() - m.Write([]byte(str)) + _, _ = m.Write([]byte(str)) return hex.EncodeToString(m.Sum(nil)) } // EncodeSha1 string to sha1 hex value. func EncodeSha1(str string) string { h := sha1.New() - h.Write([]byte(str)) + _, _ = h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } // EncodeSha256 string to sha1 hex value. func EncodeSha256(str string) string { h := sha256.New() - h.Write([]byte(str)) + _, _ = h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } @@ -193,7 +193,7 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string // create sha1 encode string sh := sha1.New() - sh.Write([]byte(data + setting.SecretKey + startStr + endStr + com.ToStr(minutes))) + _, _ = sh.Write([]byte(data + setting.SecretKey + startStr + endStr + com.ToStr(minutes))) encoded := hex.EncodeToString(sh.Sum(nil)) code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded) @@ -425,16 +425,6 @@ const ( EByte = PByte * 1024 ) -var bytesSizeTable = map[string]uint64{ - "b": Byte, - "kb": KByte, - "mb": MByte, - "gb": GByte, - "tb": TByte, - "pb": PByte, - "eb": EByte, -} - func logn(n, b float64) float64 { return math.Log(n) / math.Log(b) } @@ -582,27 +572,27 @@ func IsTextFile(data []byte) bool { if len(data) == 0 { return true } - return strings.Index(http.DetectContentType(data), "text/") != -1 + return strings.Contains(http.DetectContentType(data), "text/") } // IsImageFile detects if data is an image format func IsImageFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "image/") != -1 + return strings.Contains(http.DetectContentType(data), "image/") } // IsPDFFile detects if data is a pdf format func IsPDFFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "application/pdf") != -1 + return strings.Contains(http.DetectContentType(data), "application/pdf") } // IsVideoFile detects if data is an video format func IsVideoFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "video/") != -1 + return strings.Contains(http.DetectContentType(data), "video/") } // IsAudioFile detects if data is an video format func IsAudioFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "audio/") != -1 + return strings.Contains(http.DetectContentType(data), "audio/") } // EntryIcon returns the octicon class for displaying files/directories diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go index ec9bc1eb52..fa61e5dfb1 100644 --- a/modules/base/tool_test.go +++ b/modules/base/tool_test.go @@ -287,20 +287,19 @@ func TestHtmlTimeSince(t *testing.T) { } func TestFileSize(t *testing.T) { - var size int64 - size = 512 + var size int64 = 512 assert.Equal(t, "512B", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512KB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512MB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512GB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512TB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512PB", FileSize(size)) - size = size * 4 + size *= 4 assert.Equal(t, "2.0EB", FileSize(size)) } diff --git a/modules/cache/cache.go b/modules/cache/cache.go index a2d6c724c8..a7412f109f 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -43,7 +43,10 @@ func GetInt(key string, getFunc func() (int, error)) (int, error) { if value, err = getFunc(); err != nil { return value, err } - conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + err = conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + if err != nil { + return 0, err + } } switch value := conn.Get(key).(type) { case int: @@ -72,7 +75,10 @@ func GetInt64(key string, getFunc func() (int64, error)) (int64, error) { if value, err = getFunc(); err != nil { return value, err } - conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + err = conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + if err != nil { + return 0, err + } } switch value := conn.Get(key).(type) { case int64: @@ -93,5 +99,5 @@ func Remove(key string) { if conn == nil { return } - conn.Delete(key) + _ = conn.Delete(key) } diff --git a/modules/context/context.go b/modules/context/context.go index 1699d7aecc..b7c77ac460 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -130,7 +130,6 @@ func (ctx *Context) RedirectToFirst(location ...string) { } ctx.Redirect(setting.AppSubURL + "/") - return } // HTML calls Context.HTML and converts template name to string. @@ -266,7 +265,7 @@ func Contexter() macaron.Handler { } c.Header().Set("Content-Type", "text/html") c.WriteHeader(http.StatusOK) - c.Write([]byte(com.Expand(` + _, _ = c.Write([]byte(com.Expand(` diff --git a/modules/context/pagination.go b/modules/context/pagination.go index 4795f650fb..390b4dbdd7 100644 --- a/modules/context/pagination.go +++ b/modules/context/pagination.go @@ -39,7 +39,7 @@ func (p *Pagination) AddParam(ctx *Context, paramKey string, ctxKey string) { // GetParams returns the configured URL params func (p *Pagination) GetParams() template.URL { - return template.URL(strings.Join(p.urlParams[:], "&")) + return template.URL(strings.Join(p.urlParams, "&")) } // SetDefaultParams sets common pagination params that are often used diff --git a/modules/context/repo.go b/modules/context/repo.go index 0908340879..096f3c0a5d 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -455,15 +455,13 @@ func RepoAssignment() macaron.Handler { ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo ctx.Repo.PullRequest.Allowed = true ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName - } else { + } else if repo.AllowsPulls() { // Or, this is repository accepts pull requests between branches. - if repo.AllowsPulls() { - ctx.Data["BaseRepo"] = repo - ctx.Repo.PullRequest.BaseRepo = repo - ctx.Repo.PullRequest.Allowed = true - ctx.Repo.PullRequest.SameRepo = true - ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName - } + ctx.Data["BaseRepo"] = repo + ctx.Repo.PullRequest.BaseRepo = repo + ctx.Repo.PullRequest.Allowed = true + ctx.Repo.PullRequest.SameRepo = true + ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName } } ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest diff --git a/modules/git/blob.go b/modules/git/blob.go index 171b4a1010..73ac89dfdf 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -50,12 +50,12 @@ func (b *Blob) GetBlobContentBase64() (string, error) { go func() { _, err := io.Copy(encoder, dataRc) - encoder.Close() + _ = encoder.Close() if err != nil { - pw.CloseWithError(err) + _ = pw.CloseWithError(err) } else { - pw.Close() + _ = pw.Close() } }() diff --git a/modules/git/commit.go b/modules/git/commit.go index 7b64a300ab..c86ece9848 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -133,7 +133,7 @@ func (c *Commit) ParentCount() int { func isImageFile(data []byte) (string, bool) { contentType := http.DetectContentType(data) - if strings.Index(contentType, "image/") != -1 { + if strings.Contains(contentType, "image/") { return contentType, true } return contentType, false @@ -206,8 +206,7 @@ func CommitChanges(repoPath string, opts CommitChangesOptions) error { } func commitsCount(repoPath, revision, relpath string) (int64, error) { - var cmd *Command - cmd = NewCommand("rev-list", "--count") + cmd := NewCommand("rev-list", "--count") cmd.AddArguments(revision) if len(relpath) > 0 { cmd.AddArguments("--", relpath) @@ -263,7 +262,7 @@ type SearchCommitsOptions struct { All bool } -// NewSearchCommitsOptions contruct a SearchCommitsOption from a space-delimited search string +// NewSearchCommitsOptions construct a SearchCommitsOption from a space-delimited search string func NewSearchCommitsOptions(searchString string, forAllRefs bool) SearchCommitsOptions { var keywords, authors, committers []string var after, before string diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go index da430a21cd..43723d169b 100644 --- a/modules/git/commit_info.go +++ b/modules/git/commit_info.go @@ -87,16 +87,6 @@ func getCommitTree(c *object.Commit, treePath string) (*object.Tree, error) { return tree, nil } -func getFullPath(treePath, path string) string { - if treePath != "" { - if path != "" { - return treePath + "/" + path - } - return treePath - } - return path -} - func getFileHashes(c *object.Commit, treePath string, paths []string) (map[string]plumbing.Hash, error) { tree, err := getCommitTree(c, treePath) if err == object.ErrDirectoryNotFound { diff --git a/modules/git/repo.go b/modules/git/repo.go index 4be3164130..f5d7ee63bb 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -58,21 +58,21 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, err // IsRepoURLAccessible checks if given repository URL is accessible. func IsRepoURLAccessible(url string) bool { _, err := NewCommand("ls-remote", "-q", "-h", url, "HEAD").Run() - if err != nil { - return false - } - return true + return err == nil } // InitRepository initializes a new Git repository. func InitRepository(repoPath string, bare bool) error { - os.MkdirAll(repoPath, os.ModePerm) + err := os.MkdirAll(repoPath, os.ModePerm) + if err != nil { + return err + } cmd := NewCommand("init") if bare { cmd.AddArguments("--bare") } - _, err := cmd.RunInDir(repoPath) + _, err = cmd.RunInDir(repoPath) return err } diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 116bdbee82..05eba1e30e 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -29,10 +29,7 @@ func IsBranchExist(repoPath, name string) bool { // IsBranchExist returns true if given branch exists in current repository. func (repo *Repository) IsBranchExist(name string) bool { _, err := repo.gogitRepo.Reference(plumbing.ReferenceName(BranchPrefix+name), true) - if err != nil { - return false - } - return true + return err == nil } // Branch represents a Git branch. @@ -77,7 +74,7 @@ func (repo *Repository) GetBranches() ([]string, error) { return nil, err } - branches.ForEach(func(branch *plumbing.Reference) error { + _ = branches.ForEach(func(branch *plumbing.Reference) error { branchNames = append(branchNames, strings.TrimPrefix(branch.Name().String(), BranchPrefix)) return nil }) diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 501ea88e40..8ea2a33145 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -31,10 +31,7 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) { func (repo *Repository) IsCommitExist(name string) bool { hash := plumbing.NewHash(name) _, err := repo.gogitRepo.CommitObject(hash) - if err != nil { - return false - } - return true + return err == nil } // GetBranchCommitID returns last commit ID string of given branch. diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go index 42f0b9ad0c..ddc8109720 100644 --- a/modules/git/repo_compare.go +++ b/modules/git/repo_compare.go @@ -13,6 +13,8 @@ import ( "strconv" "strings" "time" + + logger "code.gitea.io/gitea/modules/log" ) // CompareInfo represents needed information for comparing references. @@ -55,7 +57,11 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string) if err = repo.AddRemote(tmpRemote, basePath, true); err != nil { return nil, fmt.Errorf("AddRemote: %v", err) } - defer repo.RemoveRemote(tmpRemote) + defer func() { + if err := repo.RemoveRemote(tmpRemote); err != nil { + logger.Error("GetPullRequestInfo: RemoveRemote: %v", err) + } + }() } compareInfo := new(CompareInfo) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 08d66262c1..df49e9acd6 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -24,10 +24,7 @@ func IsTagExist(repoPath, name string) bool { // IsTagExist returns true if given tag exists in the repository. func (repo *Repository) IsTagExist(name string) bool { _, err := repo.gogitRepo.Reference(plumbing.ReferenceName(TagPrefix+name), true) - if err != nil { - return false - } - return true + return err == nil } // CreateTag create one tag in the repository @@ -221,7 +218,7 @@ func (repo *Repository) GetTags() ([]string, error) { return nil, err } - tags.ForEach(func(tag *plumbing.Reference) error { + _ = tags.ForEach(func(tag *plumbing.Reference) error { tagNames = append(tagNames, strings.TrimPrefix(tag.Name().String(), TagPrefix)) return nil }) diff --git a/modules/git/utils.go b/modules/git/utils.go index 8f010321cf..83cd21f34e 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -7,7 +7,6 @@ package git import ( "fmt" "os" - "path/filepath" "strings" "sync" ) @@ -75,13 +74,6 @@ func concatenateError(err error, stderr string) error { return fmt.Errorf("%v - %s", err, stderr) } -// If the object is stored in its own file (i.e not in a pack file), -// this function returns the full path to the object file. -// It does not test if the file exists. -func filepathFromSHA1(rootdir, sha1 string) string { - return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:]) -} - // RefEndName return the end name of a ref name func RefEndName(refStr string) string { if strings.HasPrefix(refStr, BranchPrefix) { diff --git a/modules/gzip/gzip.go b/modules/gzip/gzip.go index 4a4a797c7a..0d10071830 100644 --- a/modules/gzip/gzip.go +++ b/modules/gzip/gzip.go @@ -74,7 +74,6 @@ func (wp *WriterPool) Put(w *gzip.Writer) { } var writerPool WriterPool -var regex regexp.Regexp // Options represents the configuration for the gzip middleware type Options struct { @@ -116,7 +115,7 @@ func Middleware(options ...Options) macaron.Handler { if rangeHdr := ctx.Req.Header.Get(rangeHeader); rangeHdr != "" { match := regex.FindStringSubmatch(rangeHdr) - if match != nil && len(match) > 1 { + if len(match) > 1 { return } } @@ -270,9 +269,8 @@ func (proxy *ProxyResponseWriter) Close() error { if proxy.writer == nil { err := proxy.startPlain() - if err != nil { - err = fmt.Errorf("GzipMiddleware: write to regular responseWriter at close gets error: %q", err.Error()) + return fmt.Errorf("GzipMiddleware: write to regular responseWriter at close gets error: %q", err.Error()) } } diff --git a/modules/httplib/httplib.go b/modules/httplib/httplib.go index c96e04c35f..90bbe8f12a 100644 --- a/modules/httplib/httplib.go +++ b/modules/httplib/httplib.go @@ -263,7 +263,7 @@ func (r *Request) getResponse() (*http.Response, error) { } if r.req.Method == "GET" && len(paramBody) > 0 { - if strings.Index(r.url, "?") != -1 { + if strings.Contains(r.url, "?") { r.url += "&" + paramBody } else { r.url = r.url + "?" + paramBody @@ -290,10 +290,13 @@ func (r *Request) getResponse() (*http.Response, error) { } } for k, v := range r.params { - bodyWriter.WriteField(k, v) + err := bodyWriter.WriteField(k, v) + if err != nil { + log.Fatal(err) + } } - bodyWriter.Close() - pw.Close() + _ = bodyWriter.Close() + _ = pw.Close() }() r.Header("Content-Type", bodyWriter.FormDataContentType()) r.req.Body = ioutil.NopCloser(pr) @@ -323,18 +326,15 @@ func (r *Request) getResponse() (*http.Response, error) { Proxy: proxy, Dial: TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout), } - } else { - // if r.transport is *http.Transport then set the settings. - if t, ok := trans.(*http.Transport); ok { - if t.TLSClientConfig == nil { - t.TLSClientConfig = r.setting.TLSClientConfig - } - if t.Proxy == nil { - t.Proxy = r.setting.Proxy - } - if t.Dial == nil { - t.Dial = TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout) - } + } else if t, ok := trans.(*http.Transport); ok { + if t.TLSClientConfig == nil { + t.TLSClientConfig = r.setting.TLSClientConfig + } + if t.Proxy == nil { + t.Proxy = r.setting.Proxy + } + if t.Dial == nil { + t.Dial = TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout) } } @@ -461,7 +461,6 @@ func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, ad if err != nil { return nil, err } - conn.SetDeadline(time.Now().Add(rwTimeout)) - return conn, nil + return conn, conn.SetDeadline(time.Now().Add(rwTimeout)) } } diff --git a/modules/indexer/indexer.go b/modules/indexer/indexer.go index 9e12a7f501..29261c693b 100644 --- a/modules/indexer/indexer.go +++ b/modules/indexer/indexer.go @@ -5,7 +5,6 @@ package indexer import ( - "fmt" "os" "strconv" @@ -24,15 +23,6 @@ func indexerID(id int64) string { return strconv.FormatInt(id, 36) } -// idOfIndexerID the integer id associated with an indexer id -func idOfIndexerID(indexerID string) (int64, error) { - id, err := strconv.ParseInt(indexerID, 36, 64) - if err != nil { - return 0, fmt.Errorf("Unexpected indexer ID %s: %v", indexerID, err) - } - return id, nil -} - // numericEqualityQuery a numeric equality query for the given value and field func numericEqualityQuery(value int64, field string) *query.NumericRangeQuery { f := float64(value) @@ -42,13 +32,6 @@ func numericEqualityQuery(value int64, field string) *query.NumericRangeQuery { return q } -func newMatchPhraseQuery(matchPhrase, field, analyzer string) *query.MatchPhraseQuery { - q := bleve.NewMatchPhraseQuery(matchPhrase) - q.FieldVal = field - q.Analyzer = analyzer - return q -} - const unicodeNormalizeName = "unicodeNormalize" func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index 75e6893b87..df8bfd6305 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -101,7 +101,12 @@ func InitIssueIndexer(syncReindex bool) error { return fmt.Errorf("Unsupported indexer queue type: %v", setting.Indexer.IssueQueueType) } - go issueIndexerQueue.Run() + go func() { + err = issueIndexerQueue.Run() + if err != nil { + log.Error("issueIndexerQueue.Run: %v", err) + } + }() if populate { if syncReindex { @@ -161,7 +166,7 @@ func UpdateIssueIndexer(issue *models.Issue) { comments = append(comments, comment.Content) } } - issueIndexerQueue.Push(&IndexerData{ + _ = issueIndexerQueue.Push(&IndexerData{ ID: issue.ID, RepoID: issue.RepoID, Title: issue.Title, @@ -179,11 +184,11 @@ func DeleteRepoIssueIndexer(repo *models.Repository) { return } - if len(ids) <= 0 { + if len(ids) == 0 { return } - issueIndexerQueue.Push(&IndexerData{ + _ = issueIndexerQueue.Push(&IndexerData{ IDs: ids, IsDelete: true, }) diff --git a/modules/indexer/issues/queue_channel.go b/modules/indexer/issues/queue_channel.go index bd92f6b7b1..b6458d3eb5 100644 --- a/modules/indexer/issues/queue_channel.go +++ b/modules/indexer/issues/queue_channel.go @@ -34,20 +34,20 @@ func (c *ChannelQueue) Run() error { select { case data := <-c.queue: if data.IsDelete { - c.indexer.Delete(data.IDs...) + _ = c.indexer.Delete(data.IDs...) continue } datas = append(datas, data) if len(datas) >= c.batchNumber { - c.indexer.Index(datas) + _ = c.indexer.Index(datas) // TODO: save the point datas = make([]*IndexerData, 0, c.batchNumber) } case <-time.After(time.Millisecond * 100): i++ if i >= 3 && len(datas) > 0 { - c.indexer.Index(datas) + _ = c.indexer.Index(datas) // TODO: save the point datas = make([]*IndexerData, 0, c.batchNumber) } diff --git a/modules/indexer/issues/queue_disk.go b/modules/indexer/issues/queue_disk.go index cf9e6aee22..e5ac2a7981 100644 --- a/modules/indexer/issues/queue_disk.go +++ b/modules/indexer/issues/queue_disk.go @@ -44,7 +44,7 @@ func (l *LevelQueue) Run() error { for { i++ if len(datas) > l.batchNumber || (len(datas) > 0 && i > 3) { - l.indexer.Index(datas) + _ = l.indexer.Index(datas) datas = make([]*IndexerData, 0, l.batchNumber) i = 0 continue @@ -59,7 +59,7 @@ func (l *LevelQueue) Run() error { continue } - if len(bs) <= 0 { + if len(bs) == 0 { time.Sleep(time.Millisecond * 100) continue } diff --git a/modules/indexer/issues/queue_redis.go b/modules/indexer/issues/queue_redis.go index a9434c4f92..aeccd7920c 100644 --- a/modules/indexer/issues/queue_redis.go +++ b/modules/indexer/issues/queue_redis.go @@ -96,12 +96,12 @@ func (r *RedisQueue) Run() error { i++ if len(datas) > r.batchNumber || (len(datas) > 0 && i > 3) { - r.indexer.Index(datas) + _ = r.indexer.Index(datas) datas = make([]*IndexerData, 0, r.batchNumber) i = 0 } - if len(bs) <= 0 { + if len(bs) == 0 { time.Sleep(time.Millisecond * 100) continue } diff --git a/modules/lfs/locks.go b/modules/lfs/locks.go index b1ca2f094a..4516ba01ae 100644 --- a/modules/lfs/locks.go +++ b/modules/lfs/locks.go @@ -17,7 +17,7 @@ import ( ) //checkIsValidRequest check if it a valid request in case of bad request it write the response to ctx. -func checkIsValidRequest(ctx *context.Context, post bool) bool { +func checkIsValidRequest(ctx *context.Context) bool { if !setting.LFS.StartServer { writeStatus(ctx, 404) return false @@ -35,13 +35,6 @@ func checkIsValidRequest(ctx *context.Context, post bool) bool { } ctx.User = user } - if post { - mediaParts := strings.Split(ctx.Req.Header.Get("Content-Type"), ";") - if mediaParts[0] != metaMediaType { - writeStatus(ctx, 400) - return false - } - } return true } @@ -71,7 +64,7 @@ func handleLockListOut(ctx *context.Context, repo *models.Repository, lock *mode // GetListLockHandler list locks func GetListLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) @@ -135,7 +128,7 @@ func GetListLockHandler(ctx *context.Context) { // PostLockHandler create lock func PostLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) @@ -198,7 +191,7 @@ func PostLockHandler(ctx *context.Context) { // VerifyLockHandler list locks for verification func VerifyLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) @@ -249,7 +242,7 @@ func VerifyLockHandler(ctx *context.Context) { // UnLockHandler delete locks func UnLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) diff --git a/modules/lfs/server.go b/modules/lfs/server.go index 7e20aa8515..bf5355acfc 100644 --- a/modules/lfs/server.go +++ b/modules/lfs/server.go @@ -152,7 +152,7 @@ func getContentHandler(ctx *context.Context) { if rangeHdr := ctx.Req.Header.Get("Range"); rangeHdr != "" { regex := regexp.MustCompile(`bytes=(\d+)\-.*`) match := regex.FindStringSubmatch(rangeHdr) - if match != nil && len(match) > 1 { + if len(match) > 1 { statusCode = 206 fromByte, _ = strconv.ParseInt(match[1], 10, 32) ctx.Resp.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", fromByte, meta.Size-1, meta.Size-fromByte)) @@ -178,8 +178,8 @@ func getContentHandler(ctx *context.Context) { } ctx.Resp.WriteHeader(statusCode) - io.Copy(ctx.Resp, content) - content.Close() + _, _ = io.Copy(ctx.Resp, content) + _ = content.Close() logRequest(ctx.Req, statusCode) } @@ -196,7 +196,7 @@ func getMetaHandler(ctx *context.Context) { if ctx.Req.Method == "GET" { enc := json.NewEncoder(ctx.Resp) - enc.Encode(Represent(rv, meta, true, false)) + _ = enc.Encode(Represent(rv, meta, true, false)) } logRequest(ctx.Req, 200) @@ -249,7 +249,7 @@ func PostHandler(ctx *context.Context) { ctx.Resp.WriteHeader(sentStatus) enc := json.NewEncoder(ctx.Resp) - enc.Encode(Represent(rv, meta, meta.Existing, true)) + _ = enc.Encode(Represent(rv, meta, meta.Existing, true)) logRequest(ctx.Req, sentStatus) } @@ -313,7 +313,7 @@ func BatchHandler(ctx *context.Context) { respobj := &BatchResponse{Objects: responseObjects} enc := json.NewEncoder(ctx.Resp) - enc.Encode(respobj) + _ = enc.Encode(respobj) logRequest(ctx.Req, 200) } diff --git a/modules/log/colors.go b/modules/log/colors.go index 0ec8ce4ba8..c29741634f 100644 --- a/modules/log/colors.go +++ b/modules/log/colors.go @@ -208,7 +208,7 @@ normalLoop: if i > lasti { written, err := c.w.Write(bytes[lasti:i]) - totalWritten = totalWritten + written + totalWritten += written if err != nil { return totalWritten, err } @@ -243,7 +243,7 @@ normalLoop: if bytes[j] == 'm' { if c.mode == allowColor { written, err := c.w.Write(bytes[i : j+1]) - totalWritten = totalWritten + written + totalWritten += written if err != nil { return totalWritten, err } @@ -278,7 +278,7 @@ func ColorSprintf(format string, args ...interface{}) string { } return fmt.Sprintf(format, v...) } - return fmt.Sprintf(format) + return format } // ColorFprintf will write to the provided writer similar to ColorSprintf @@ -290,7 +290,7 @@ func ColorFprintf(w io.Writer, format string, args ...interface{}) (int, error) } return fmt.Fprintf(w, format, v...) } - return fmt.Fprintf(w, format) + return fmt.Fprint(w, format) } // ColorFormatted structs provide their own colored string when formatted with ColorSprintf diff --git a/modules/log/conn.go b/modules/log/conn.go index bd76855168..8816664526 100644 --- a/modules/log/conn.go +++ b/modules/log/conn.go @@ -67,7 +67,10 @@ func (i *connWriter) connect() error { } if tcpConn, ok := conn.(*net.TCPConn); ok { - tcpConn.SetKeepAlive(true) + err = tcpConn.SetKeepAlive(true) + if err != nil { + return err + } } i.innerWriter = conn diff --git a/modules/log/conn_test.go b/modules/log/conn_test.go index 380a115d96..cc3d758fa9 100644 --- a/modules/log/conn_test.go +++ b/modules/log/conn_test.go @@ -24,7 +24,6 @@ func listenReadAndClose(t *testing.T, l net.Listener, expected string) { assert.NoError(t, err) assert.Equal(t, expected, string(written)) - return } func TestConnLogger(t *testing.T) { diff --git a/modules/log/event.go b/modules/log/event.go index 2ec1f9587d..37efa3c230 100644 --- a/modules/log/event.go +++ b/modules/log/event.go @@ -79,7 +79,7 @@ func (l *ChannelledLog) Start() { return } l.loggerProvider.Flush() - case _, _ = <-l.close: + case <-l.close: l.closeLogger() return } @@ -104,7 +104,6 @@ func (l *ChannelledLog) closeLogger() { l.loggerProvider.Flush() l.loggerProvider.Close() l.closed <- true - return } // Close this ChannelledLog @@ -228,7 +227,6 @@ func (m *MultiChannelledLog) closeLoggers() { } m.mutex.Unlock() m.closed <- true - return } // Start processing the MultiChannelledLog diff --git a/modules/log/file.go b/modules/log/file.go index cdda85d626..877820b8be 100644 --- a/modules/log/file.go +++ b/modules/log/file.go @@ -223,7 +223,7 @@ func compressOldLogFile(fname string, compressionLevel int) error { func (log *FileLogger) deleteOldLog() { dir := filepath.Dir(log.Filename) - filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) { + _ = filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) { defer func() { if r := recover(); r != nil { returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v", path, r) @@ -246,7 +246,7 @@ func (log *FileLogger) deleteOldLog() { // there are no buffering messages in file logger in memory. // flush file means sync file from disk. func (log *FileLogger) Flush() { - log.mw.fd.Sync() + _ = log.mw.fd.Sync() } // GetName returns the default name for this implementation diff --git a/modules/log/file_test.go b/modules/log/file_test.go index 648db6f393..38279315ab 100644 --- a/modules/log/file_test.go +++ b/modules/log/file_test.go @@ -103,7 +103,7 @@ func TestFileLogger(t *testing.T) { assert.Equal(t, expected, string(logData)) event.level = WARN - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) @@ -130,7 +130,7 @@ func TestFileLogger(t *testing.T) { err = realFileLogger.DoRotate() assert.Error(t, err) - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) @@ -138,7 +138,7 @@ func TestFileLogger(t *testing.T) { assert.Equal(t, expected, string(logData)) // Should fail to rotate - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) @@ -188,7 +188,7 @@ func TestCompressFileLogger(t *testing.T) { assert.Equal(t, expected, string(logData)) event.level = WARN - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) diff --git a/modules/log/flags.go b/modules/log/flags.go index 928d42b965..992fc62ddb 100644 --- a/modules/log/flags.go +++ b/modules/log/flags.go @@ -57,7 +57,7 @@ func FlagsFromString(from string) int { for _, flag := range strings.Split(strings.ToLower(from), ",") { f, ok := flagFromString[strings.TrimSpace(flag)] if ok { - flags = flags | f + flags |= f } } return flags diff --git a/modules/log/log.go b/modules/log/log.go index 8698e9eed3..0ca0f3adc5 100644 --- a/modules/log/log.go +++ b/modules/log/log.go @@ -218,7 +218,7 @@ func (l *LoggerAsWriter) Write(p []byte) (int, error) { func (l *LoggerAsWriter) Log(msg string) { for _, logger := range l.ourLoggers { // Set the skip to reference the call just above this - logger.Log(1, l.level, msg) + _ = logger.Log(1, l.level, msg) } } diff --git a/modules/log/smtp.go b/modules/log/smtp.go index f77d716d94..f912299a73 100644 --- a/modules/log/smtp.go +++ b/modules/log/smtp.go @@ -11,10 +11,6 @@ import ( "strings" ) -const ( - subjectPhrase = "Diagnostic message from server" -) - type smtpWriter struct { owner *SMTPLogger } diff --git a/modules/log/writer.go b/modules/log/writer.go index 22ef0b9047..2503f04d76 100644 --- a/modules/log/writer.go +++ b/modules/log/writer.go @@ -252,10 +252,7 @@ func (logger *WriterLogger) Match(event *Event) bool { mode: removeColor, }).Write([]byte(event.msg)) msg = baw - if logger.regexp.Match(msg) { - return true - } - return false + return logger.regexp.Match(msg) } // Close the base logger diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go index 411d6eafd8..d19ae7b2f4 100644 --- a/modules/mailer/mailer.go +++ b/modules/mailer/mailer.go @@ -258,15 +258,12 @@ func (s *dummySender) Send(from string, to []string, msg io.WriterTo) error { } func processMailQueue() { - for { - select { - case msg := <-mailQueue: - log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info) - if err := gomail.Send(Sender, msg.Message); err != nil { - log.Error("Failed to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err) - } else { - log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info) - } + for msg := range mailQueue { + log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info) + if err := gomail.Send(Sender, msg.Message); err != nil { + log.Error("Failed to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err) + } else { + log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info) } } } diff --git a/modules/markup/html.go b/modules/markup/html.go index 91913b0679..dbfc8dbe85 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -108,24 +108,6 @@ func FindAllMentions(content string) []string { return ret } -// cutoutVerbosePrefix cutouts URL prefix including sub-path to -// return a clean unified string of request URL path. -func cutoutVerbosePrefix(prefix string) string { - if len(prefix) == 0 || prefix[0] != '/' { - return prefix - } - count := 0 - for i := 0; i < len(prefix); i++ { - if prefix[i] == '/' { - count++ - } - if count >= 3+setting.AppSubURLDepth { - return prefix[:i] - } - } - return prefix -} - // IsSameDomain checks if given url string has the same hostname as current Gitea instance func IsSameDomain(s string) bool { if strings.HasPrefix(s, "/") { @@ -146,7 +128,7 @@ type postProcessError struct { } func (p *postProcessError) Error() string { - return "PostProcess: " + p.context + ", " + p.Error() + return "PostProcess: " + p.context + ", " + p.err.Error() } type processor func(ctx *postProcessCtx, node *html.Node) @@ -304,20 +286,6 @@ func (ctx *postProcessCtx) visitNode(node *html.Node) { // ignore everything else } -func (ctx *postProcessCtx) visitNodeForShortLinks(node *html.Node) { - switch node.Type { - case html.TextNode: - shortLinkProcessorFull(ctx, node, true) - case html.ElementNode: - if node.Data == "code" || node.Data == "pre" || node.Data == "a" { - return - } - for n := node.FirstChild; n != nil; n = n.NextSibling { - ctx.visitNodeForShortLinks(n) - } - } -} - // textNode runs the passed node through various processors, in order to handle // all kinds of special links handled by the post-processing. func (ctx *postProcessCtx) textNode(node *html.Node) { diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go index 135a8e103c..10bc4973cd 100644 --- a/modules/markup/html_internal_test.go +++ b/modules/markup/html_internal_test.go @@ -29,11 +29,6 @@ func numericIssueLink(baseURL string, index int) string { return link(util.URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index)) } -// urlContentsLink an HTML link whose contents is the target URL -func urlContentsLink(href string) string { - return link(href, href) -} - // link an HTML link func link(href, contents string) string { return fmt.Sprintf("%s", href, contents) diff --git a/modules/notification/ui/ui.go b/modules/notification/ui/ui.go index a31591c2a7..22089158f5 100644 --- a/modules/notification/ui/ui.go +++ b/modules/notification/ui/ui.go @@ -35,12 +35,9 @@ func NewNotifier() base.Notifier { } func (ns *notificationService) Run() { - for { - select { - case opts := <-ns.issueQueue: - if err := models.CreateOrUpdateIssueNotifications(opts.issue, opts.notificationAuthorID); err != nil { - log.Error("Was unable to create issue notification: %v", err) - } + for opts := range ns.issueQueue { + if err := models.CreateOrUpdateIssueNotifications(opts.issue, opts.notificationAuthorID); err != nil { + log.Error("Was unable to create issue notification: %v", err) } } } diff --git a/modules/pprof/pprof.go b/modules/pprof/pprof.go index b63904e713..80ad67be3a 100644 --- a/modules/pprof/pprof.go +++ b/modules/pprof/pprof.go @@ -9,6 +9,8 @@ import ( "io/ioutil" "runtime" "runtime/pprof" + + "code.gitea.io/gitea/modules/log" ) // DumpMemProfileForUsername dumps a memory profile at pprofDataPath as memprofile__ @@ -30,9 +32,15 @@ func DumpCPUProfileForUsername(pprofDataPath, username string) (func(), error) { return nil, err } - pprof.StartCPUProfile(f) + err = pprof.StartCPUProfile(f) + if err != nil { + log.Fatal("StartCPUProfile: %v", err) + } return func() { pprof.StopCPUProfile() - f.Close() + err = f.Close() + if err != nil { + log.Fatal("StopCPUProfile Close: %v", err) + } }, nil } diff --git a/modules/repofiles/delete.go b/modules/repofiles/delete.go index 09a4dbb44c..91910fa860 100644 --- a/modules/repofiles/delete.go +++ b/modules/repofiles/delete.go @@ -53,11 +53,9 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo BranchName: opts.NewBranch, } } - } else { - if protected, _ := repo.IsProtectedBranchForPush(opts.OldBranch, doer); protected { - return nil, models.ErrUserCannotCommit{ - UserName: doer.LowerName, - } + } else if protected, _ := repo.IsProtectedBranchForPush(opts.OldBranch, doer); protected { + return nil, models.ErrUserCannotCommit{ + UserName: doer.LowerName, } } @@ -74,10 +72,10 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo author, committer := GetAuthorAndCommitterUsers(opts.Committer, opts.Author, doer) t, err := NewTemporaryUploadRepository(repo) - defer t.Close() if err != nil { return nil, err } + defer t.Close() if err := t.Clone(opts.OldBranch); err != nil { return nil, err } diff --git a/modules/repofiles/file.go b/modules/repofiles/file.go index de3ee71dba..70fd57bba0 100644 --- a/modules/repofiles/file.go +++ b/modules/repofiles/file.go @@ -86,7 +86,7 @@ func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *models // If only one of the two are provided, we set both of them to it. // If neither are provided, both are the doer. if committer != nil && committer.Email != "" { - if doer != nil && strings.ToLower(doer.Email) == strings.ToLower(committer.Email) { + if doer != nil && strings.EqualFold(doer.Email, committer.Email) { committerUser = doer // the committer is the doer, so will use their user object if committer.Name != "" { committerUser.FullName = committer.Name @@ -99,7 +99,7 @@ func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *models } } if author != nil && author.Email != "" { - if doer != nil && strings.ToLower(doer.Email) == strings.ToLower(author.Email) { + if doer != nil && strings.EqualFold(doer.Email, author.Email) { authorUser = doer // the author is the doer, so will use their user object if authorUser.Name != "" { authorUser.FullName = author.Name diff --git a/modules/repofiles/tree.go b/modules/repofiles/tree.go index 4eb54a2598..318a5d152d 100644 --- a/modules/repofiles/tree.go +++ b/modules/repofiles/tree.go @@ -16,6 +16,9 @@ import ( // GetTreeBySHA get the GitTreeResponse of a repository using a sha hash. func GetTreeBySHA(repo *models.Repository, sha string, page, perPage int, recursive bool) (*api.GitTreeResponse, error) { gitRepo, err := git.OpenRepository(repo.RepoPath()) + if err != nil { + return nil, err + } gitTree, err := gitRepo.GetTree(sha) if err != nil || gitTree == nil { return nil, models.ErrSHANotFound{ @@ -39,12 +42,12 @@ func GetTreeBySHA(repo *models.Repository, sha string, page, perPage int, recurs // 51 is len(sha1) + len("/git/blobs/"). 40 + 11. blobURL := make([]byte, apiURLLen+51) - copy(blobURL[:], apiURL) + copy(blobURL, apiURL) copy(blobURL[apiURLLen:], "/git/blobs/") // 51 is len(sha1) + len("/git/trees/"). 40 + 11. treeURL := make([]byte, apiURLLen+51) - copy(treeURL[:], apiURL) + copy(treeURL, apiURL) copy(treeURL[apiURLLen:], "/git/trees/") // 40 is the size of the sha1 hash in hexadecimal format. @@ -83,10 +86,10 @@ func GetTreeBySHA(repo *models.Repository, sha string, page, perPage int, recurs if entries[e].IsDir() { copy(treeURL[copyPos:], entries[e].ID.String()) - tree.Entries[i].URL = string(treeURL[:]) + tree.Entries[i].URL = string(treeURL) } else { copy(blobURL[copyPos:], entries[e].ID.String()) - tree.Entries[i].URL = string(blobURL[:]) + tree.Entries[i].URL = string(blobURL) } } return tree, nil diff --git a/modules/repofiles/update.go b/modules/repofiles/update.go index 569c89ac51..f011017a5e 100644 --- a/modules/repofiles/update.go +++ b/modules/repofiles/update.go @@ -99,6 +99,10 @@ func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string } result, n, err := transform.String(charsetEncoding.NewDecoder(), string(buf)) + if err != nil { + // return default + return "UTF-8", false + } if n > 2 { return encoding, bytes.Equal([]byte(result)[0:3], base.UTF8BOM) @@ -135,10 +139,8 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up if err != nil && !git.IsErrBranchNotExist(err) { return nil, err } - } else { - if protected, _ := repo.IsProtectedBranchForPush(opts.OldBranch, doer); protected { - return nil, models.ErrUserCannotCommit{UserName: doer.LowerName} - } + } else if protected, _ := repo.IsProtectedBranchForPush(opts.OldBranch, doer); protected { + return nil, models.ErrUserCannotCommit{UserName: doer.LowerName} } // If FromTreePath is not set, set it to the opts.TreePath @@ -166,10 +168,10 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up author, committer := GetAuthorAndCommitterUsers(opts.Committer, opts.Author, doer) t, err := NewTemporaryUploadRepository(repo) - defer t.Close() if err != nil { - return nil, err + log.Error("%v", err) } + defer t.Close() if err := t.Clone(opts.OldBranch); err != nil { return nil, err } diff --git a/modules/repofiles/upload.go b/modules/repofiles/upload.go index 5f428c3139..2da101c64d 100644 --- a/modules/repofiles/upload.go +++ b/modules/repofiles/upload.go @@ -57,10 +57,10 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep } t, err := NewTemporaryUploadRepository(repo) - defer t.Close() if err != nil { return err } + defer t.Close() if err := t.Clone(opts.OldBranch); err != nil { return err } @@ -108,10 +108,8 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep } infos[i] = uploadInfo - } else { - if objectHash, err = t.HashObject(file); err != nil { - return err - } + } else if objectHash, err = t.HashObject(file); err != nil { + return err } // Add the object to the index diff --git a/modules/repofiles/verification.go b/modules/repofiles/verification.go index be56f9b8b8..9fc084daaf 100644 --- a/modules/repofiles/verification.go +++ b/modules/repofiles/verification.go @@ -20,10 +20,8 @@ func GetPayloadCommitVerification(commit *git.Commit) *structs.PayloadCommitVeri } if verification.Reason != "" { verification.Reason = commitVerification.Reason - } else { - if verification.Verified { - verification.Reason = "unsigned" - } + } else if verification.Verified { + verification.Reason = "unsigned" } return verification } diff --git a/modules/session/virtual.go b/modules/session/virtual.go index b90f03417a..b8ddd2f71b 100644 --- a/modules/session/virtual.go +++ b/modules/session/virtual.go @@ -21,10 +21,8 @@ import ( // VirtualSessionProvider represents a shadowed session provider implementation. type VirtualSessionProvider struct { - lock sync.RWMutex - maxlifetime int64 - rootPath string - provider session.Provider + lock sync.RWMutex + provider session.Provider } // Init initializes the cookie session provider with given root path. diff --git a/modules/setting/log.go b/modules/setting/log.go index 9f4bbf9d87..5e2d2d769d 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -150,8 +150,6 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription sections := strings.Split(Cfg.Section("log").Key(strings.ToUpper(key)).MustString(""), ",") - //description.Configs = make([]string, len(description.Sections)) - for i := 0; i < len(sections); i++ { sections[i] = strings.TrimSpace(sections[i]) } @@ -167,7 +165,10 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription provider, config, levelName := generateLogConfig(sec, name, options) - log.NewNamedLogger(key, options.bufferLength, name, provider, config) + if err := log.NewNamedLogger(key, options.bufferLength, name, provider, config); err != nil { + // Maybe panic here? + log.Error("Could not create new named logger: %v", err.Error()) + } description.SubLogDescriptions = append(description.SubLogDescriptions, SubLogDescription{ Name: name, @@ -242,7 +243,10 @@ func newLogService() { } if !useConsole { - log.DelLogger("console") + err := log.DelLogger("console") + if err != nil { + log.Fatal("DelLogger: %v", err) + } } for _, name := range sections { diff --git a/modules/setting/setting.go b/modules/setting/setting.go index ff53e9a375..b550836bc1 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -545,13 +545,14 @@ func NewContext() { AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") Protocol = HTTP - if sec.Key("PROTOCOL").String() == "https" { + switch sec.Key("PROTOCOL").String() { + case "https": Protocol = HTTPS CertFile = sec.Key("CERT_FILE").String() KeyFile = sec.Key("KEY_FILE").String() - } else if sec.Key("PROTOCOL").String() == "fcgi" { + case "fcgi": Protocol = FCGI - } else if sec.Key("PROTOCOL").String() == "unix" { + case "unix": Protocol = UnixSocket UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666") UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32) diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 98ff50bfec..c5251ef23a 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -37,7 +37,10 @@ func cleanCommand(cmd string) string { func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { for newChan := range chans { if newChan.ChannelType() != "session" { - newChan.Reject(ssh.UnknownChannelType, "unknown channel type") + err := newChan.Reject(ssh.UnknownChannelType, "unknown channel type") + if err != nil { + log.Error("Error rejecting channel: %v", err) + } continue } @@ -48,7 +51,11 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { } go func(in <-chan *ssh.Request) { - defer ch.Close() + defer func() { + if err = ch.Close(); err != nil { + log.Error("Close: %v", err) + } + }() for req := range in { payload := cleanCommand(string(req.Payload)) switch req.Type { @@ -87,17 +94,34 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { return } - req.Reply(true, nil) - go io.Copy(input, ch) - io.Copy(ch, stdout) - io.Copy(ch.Stderr(), stderr) + err = req.Reply(true, nil) + if err != nil { + log.Error("SSH: Reply: %v", err) + } + go func() { + _, err = io.Copy(input, ch) + if err != nil { + log.Error("SSH: Copy: %v", err) + } + }() + _, err = io.Copy(ch, stdout) + if err != nil { + log.Error("SSH: Copy: %v", err) + } + _, err = io.Copy(ch.Stderr(), stderr) + if err != nil { + log.Error("SSH: Copy: %v", err) + } if err = cmd.Wait(); err != nil { log.Error("SSH: Wait: %v", err) return } - ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) + _, err = ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) + if err != nil { + log.Error("SSH: SendRequest: %v", err) + } return default: } @@ -203,7 +227,11 @@ func GenKeyPair(keyPath string) error { if err != nil { return err } - defer f.Close() + defer func() { + if err = f.Close(); err != nil { + log.Error("Close: %v", err) + } + }() if err := pem.Encode(f, privateKeyPEM); err != nil { return err @@ -220,7 +248,11 @@ func GenKeyPair(keyPath string) error { if err != nil { return err } - defer p.Close() + defer func() { + if err = p.Close(); err != nil { + log.Error("Close: %v", err) + } + }() _, err = p.Write(public) return err } diff --git a/modules/structs/user_search.go b/modules/structs/user_search.go deleted file mode 100644 index 1650cf736a..0000000000 --- a/modules/structs/user_search.go +++ /dev/null @@ -1,5 +0,0 @@ -package structs - -type searchUsersResponse struct { - Users []*User `json:"data"` -} diff --git a/modules/structs/utils.go b/modules/structs/utils.go index 1b9d689562..aaeb653d03 100644 --- a/modules/structs/utils.go +++ b/modules/structs/utils.go @@ -4,12 +4,6 @@ package structs -import ( - "net/http" -) - -var jsonHeader = http.Header{"content-type": []string{"application/json"}} - // Bool return address of bool value func Bool(v bool) *bool { return &v diff --git a/modules/templates/dynamic.go b/modules/templates/dynamic.go index dbd75221d2..d7c04ccb09 100644 --- a/modules/templates/dynamic.go +++ b/modules/templates/dynamic.go @@ -83,12 +83,15 @@ func Mailer() *template.Template { continue } - templates.New( + _, err = templates.New( strings.TrimSuffix( filePath, ".tmpl", ), ).Parse(string(content)) + if err != nil { + log.Warn("Failed to parse template %v", err) + } } } } @@ -113,12 +116,15 @@ func Mailer() *template.Template { continue } - templates.New( + _, err = templates.New( strings.TrimSuffix( filePath, ".tmpl", ), ).Parse(string(content)) + if err != nil { + log.Warn("Failed to parse template %v", err) + } } } } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index ef4a68add0..c4551bb4be 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -343,7 +343,7 @@ func ReplaceLeft(s, oldS, newS string) string { // allocating space for the new string curLen := n*newLen + len(s[i:]) - replacement := make([]byte, curLen, curLen) + replacement := make([]byte, curLen) j := 0 for ; j < n*newLen; j += newLen { diff --git a/modules/user/user_test.go b/modules/user/user_test.go index ae7460281f..fadcbde7bf 100644 --- a/modules/user/user_test.go +++ b/modules/user/user_test.go @@ -13,7 +13,7 @@ func getWhoamiOutput() (string, error) { if err != nil { return "", err } - return strings.TrimSpace(string(output[:])), nil + return strings.TrimSpace(string(output)), nil } func TestCurrentUsername(t *testing.T) { diff --git a/modules/validation/binding_test.go b/modules/validation/binding_test.go index 7bc41ac395..f55b09266d 100644 --- a/modules/validation/binding_test.go +++ b/modules/validation/binding_test.go @@ -26,12 +26,6 @@ type ( expectedErrors binding.Errors } - handlerFunc func(interface{}, ...interface{}) macaron.Handler - - modeler interface { - Model() string - } - TestForm struct { BranchName string `form:"BranchName" binding:"GitRefName"` URL string `form:"ValidUrl" binding:"ValidUrl"` diff --git a/routers/admin/admin.go b/routers/admin/admin.go index 5107e18b7d..b4eac2c677 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -261,10 +261,6 @@ func Config(ctx *context.Context) { } ctx.Data["EnvVars"] = envVars - - type logger struct { - Mode, Config string - } ctx.Data["Loggers"] = setting.LogDescriptions ctx.Data["RedirectMacaronLog"] = setting.RedirectMacaronLog ctx.Data["EnableAccessLog"] = setting.EnableAccessLog diff --git a/routers/api/v1/misc/markdown.go b/routers/api/v1/misc/markdown.go index 06e344a15b..b00b00c499 100644 --- a/routers/api/v1/misc/markdown.go +++ b/routers/api/v1/misc/markdown.go @@ -5,6 +5,7 @@ package misc import ( + "net/http" "strings" api "code.gitea.io/gitea/modules/structs" @@ -42,7 +43,7 @@ func Markdown(ctx *context.APIContext, form api.MarkdownOption) { } if len(form.Text) == 0 { - ctx.Write([]byte("")) + _, _ = ctx.Write([]byte("")) return } @@ -63,12 +64,24 @@ func Markdown(ctx *context.APIContext, form api.MarkdownOption) { meta = ctx.Repo.Repository.ComposeMetas() } if form.Wiki { - ctx.Write([]byte(markdown.RenderWiki(md, urlPrefix, meta))) + _, err := ctx.Write([]byte(markdown.RenderWiki(md, urlPrefix, meta))) + if err != nil { + ctx.Error(http.StatusInternalServerError, "", err) + return + } } else { - ctx.Write(markdown.Render(md, urlPrefix, meta)) + _, err := ctx.Write(markdown.Render(md, urlPrefix, meta)) + if err != nil { + ctx.Error(http.StatusInternalServerError, "", err) + return + } } default: - ctx.Write(markdown.RenderRaw([]byte(form.Text), "", false)) + _, err := ctx.Write(markdown.RenderRaw([]byte(form.Text), "", false)) + if err != nil { + ctx.Error(http.StatusInternalServerError, "", err) + return + } } } @@ -98,5 +111,9 @@ func MarkdownRaw(ctx *context.APIContext) { ctx.Error(422, "", err) return } - ctx.Write(markdown.RenderRaw(body, "", false)) + _, err = ctx.Write(markdown.RenderRaw(body, "", false)) + if err != nil { + ctx.Error(http.StatusInternalServerError, "", err) + return + } } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 0e1db144b1..b14b0b02b8 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -353,7 +353,11 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) { return } - pr.LoadIssue() + err = pr.LoadIssue() + if err != nil { + ctx.Error(http.StatusInternalServerError, "LoadIssue", err) + return + } issue := pr.Issue issue.Repo = ctx.Repo.Repository @@ -547,7 +551,11 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) { return } - pr.LoadIssue() + err = pr.LoadIssue() + if err != nil { + ctx.Error(http.StatusInternalServerError, "LoadIssue", err) + return + } pr.Issue.Repo = ctx.Repo.Repository if ctx.IsSigned { diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index f8df3e9fa1..26cfff51ce 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -631,15 +631,6 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err return nil } -func unitTypeInTypes(unitType models.UnitType, unitTypes []models.UnitType) bool { - for _, tp := range unitTypes { - if unitType == tp { - return true - } - } - return false -} - // updateRepoUnits updates repo units: Issue settings, Wiki settings, PR settings func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { owner := ctx.Repo.Owner diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go index c2c55e9b92..7bf43c5822 100644 --- a/routers/api/v1/user/gpg_key.go +++ b/routers/api/v1/user/gpg_key.go @@ -9,14 +9,9 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/api/v1/convert" ) -func composePublicGPGKeysAPILink() string { - return setting.AppURL + "api/v1/user/gpg_keys/" -} - func listGPGKeys(ctx *context.APIContext, uid int64) { keys, err := models.ListGPGKeys(uid) if err != nil { diff --git a/routers/init.go b/routers/init.go index b3078b478a..e6b23cf8b8 100644 --- a/routers/init.go +++ b/routers/init.go @@ -41,7 +41,7 @@ func checkRunMode() { func NewServices() { setting.NewServices() mailer.NewContext() - cache.NewContext() + _ = cache.NewContext() } // In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology diff --git a/routers/org/teams.go b/routers/org/teams.go index 27db14e4b5..f662bd92e2 100644 --- a/routers/org/teams.go +++ b/routers/org/teams.go @@ -5,6 +5,7 @@ package org import ( + "net/http" "path" "strings" @@ -287,7 +288,11 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) { Type: tp, }) } - models.UpdateTeamUnits(t, units) + err := models.UpdateTeamUnits(t, units) + if err != nil { + ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error()) + return + } } if ctx.HasError() { diff --git a/routers/private/hook.go b/routers/private/hook.go index a5985f161e..3da5e38edb 100644 --- a/routers/private/hook.go +++ b/routers/private/hook.go @@ -214,5 +214,4 @@ func HookPostReceive(ctx *macaron.Context) { ctx.JSON(http.StatusOK, map[string]interface{}{ "message": false, }) - return } diff --git a/routers/private/serv.go b/routers/private/serv.go index 68e4361e56..90579a3dcc 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -62,7 +62,6 @@ func ServNoCommand(ctx *macaron.Context) { results.Owner = user } ctx.JSON(http.StatusOK, &results) - return } // ServCommand returns information about the provided keyid @@ -282,5 +281,4 @@ func ServCommand(ctx *macaron.Context) { ctx.JSON(http.StatusOK, results) // We will update the keys in a different call. - return } diff --git a/routers/repo/blame.go b/routers/repo/blame.go index 964fdc8746..2b2f45f0bb 100644 --- a/routers/repo/blame.go +++ b/routers/repo/blame.go @@ -192,7 +192,7 @@ func RefBlame(ctx *context.Context) { func renderBlame(ctx *context.Context, blameParts []models.BlamePart, commitNames map[string]models.UserCommit) { repoLink := ctx.Repo.RepoLink - var lines = make([]string, 0, 0) + var lines = make([]string, 0) var commitInfo bytes.Buffer var lineNumbers bytes.Buffer diff --git a/routers/repo/commit.go b/routers/repo/commit.go index dde6d8f321..4dbedea2a0 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -261,6 +261,9 @@ func Diff(ctx *context.Context) { } ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", commitID) ctx.Data["BranchName"], err = commit.GetBranchName() + if err != nil { + ctx.ServerError("commit.GetBranchName", err) + } ctx.HTML(200, tplCommitPage) } diff --git a/routers/repo/download.go b/routers/repo/download.go index 41c4a18102..2da8b109ca 100644 --- a/routers/repo/download.go +++ b/routers/repo/download.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/lfs" + "code.gitea.io/gitea/modules/log" ) // ServeData download file from io.Reader @@ -39,8 +40,11 @@ func ServeData(ctx *context.Context, name string, reader io.Reader) error { ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) } - ctx.Resp.Write(buf) - _, err := io.Copy(ctx.Resp, reader) + _, err := ctx.Resp.Write(buf) + if err != nil { + return err + } + _, err = io.Copy(ctx.Resp, reader) return err } @@ -50,7 +54,11 @@ func ServeBlob(ctx *context.Context, blob *git.Blob) error { if err != nil { return err } - defer dataRc.Close() + defer func() { + if err = dataRc.Close(); err != nil { + log.Error("ServeBlob: Close: %v", err) + } + }() return ServeData(ctx, ctx.Repo.TreePath, dataRc) } @@ -61,7 +69,11 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error { if err != nil { return err } - defer dataRc.Close() + defer func() { + if err = dataRc.Close(); err != nil { + log.Error("ServeBlobOrLFS: Close: %v", err) + } + }() if meta, _ := lfs.ReadPointerFile(dataRc); meta != nil { meta, _ = ctx.Repo.Repository.GetLFSMetaObjectByOid(meta.Oid) diff --git a/routers/repo/editor.go b/routers/repo/editor.go index 46f12d66d2..062ecfebf7 100644 --- a/routers/repo/editor.go +++ b/routers/repo/editor.go @@ -118,9 +118,7 @@ func editFile(ctx *context.Context, isNewFile bool) { d, _ := ioutil.ReadAll(dataRc) buf = append(buf, d...) if content, err := templates.ToUTF8WithErr(buf); err != nil { - if err != nil { - log.Error("ToUTF8WithErr: %v", err) - } + log.Error("ToUTF8WithErr: %v", err) ctx.Data["FileContent"] = string(buf) } else { ctx.Data["FileContent"] = content @@ -235,16 +233,12 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo switch fileErr.Type { case git.EntryModeSymlink: ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplEditFile, &form) - break case git.EntryModeTree: ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplEditFile, &form) - break case git.EntryModeBlob: ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form) - break default: ctx.Error(500, err.Error()) - break } } else { ctx.Error(500, err.Error()) @@ -403,16 +397,12 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) { switch fileErr.Type { case git.EntryModeSymlink: ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplEditFile, &form) - break case git.EntryModeTree: ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplEditFile, &form) - break case git.EntryModeBlob: ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form) - break default: ctx.ServerError("DeleteRepoFile", err) - break } } else { ctx.ServerError("DeleteRepoFile", err) diff --git a/routers/repo/http.go b/routers/repo/http.go index 214e2f3411..3072209448 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -206,10 +206,8 @@ func HTTP(ctx *context.Context) { if err = models.UpdateAccessToken(token); err != nil { ctx.ServerError("UpdateAccessToken", err) } - } else { - if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) { - log.Error("GetAccessTokenBySha: %v", err) - } + } else if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) { + log.Error("GetAccessTokenBySha: %v", err) } if authUser == nil { @@ -332,17 +330,17 @@ type route struct { } var routes = []route{ - {regexp.MustCompile("(.*?)/git-upload-pack$"), "POST", serviceUploadPack}, - {regexp.MustCompile("(.*?)/git-receive-pack$"), "POST", serviceReceivePack}, - {regexp.MustCompile("(.*?)/info/refs$"), "GET", getInfoRefs}, - {regexp.MustCompile("(.*?)/HEAD$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/info/alternates$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/info/http-alternates$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/info/packs$"), "GET", getInfoPacks}, - {regexp.MustCompile("(.*?)/objects/info/[^/]*$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"), "GET", getLooseObject}, - {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"), "GET", getPackFile}, - {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"), "GET", getIdxFile}, + {regexp.MustCompile(`(.*?)/git-upload-pack$`), "POST", serviceUploadPack}, + {regexp.MustCompile(`(.*?)/git-receive-pack$`), "POST", serviceReceivePack}, + {regexp.MustCompile(`(.*?)/info/refs$`), "GET", getInfoRefs}, + {regexp.MustCompile(`(.*?)/HEAD$`), "GET", getTextFile}, + {regexp.MustCompile(`(.*?)/objects/info/alternates$`), "GET", getTextFile}, + {regexp.MustCompile(`(.*?)/objects/info/http-alternates$`), "GET", getTextFile}, + {regexp.MustCompile(`(.*?)/objects/info/packs$`), "GET", getInfoPacks}, + {regexp.MustCompile(`(.*?)/objects/info/[^/]*$`), "GET", getTextFile}, + {regexp.MustCompile(`(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$`), "GET", getLooseObject}, + {regexp.MustCompile(`(.*?)/objects/pack/pack-[0-9a-f]{40}\.pack$`), "GET", getPackFile}, + {regexp.MustCompile(`(.*?)/objects/pack/pack-[0-9a-f]{40}\.idx$`), "GET", getIdxFile}, } // FIXME: use process module @@ -393,7 +391,12 @@ func hasAccess(service string, h serviceHandler, checkContentType bool) bool { } func serviceRPC(h serviceHandler, service string) { - defer h.r.Body.Close() + defer func() { + if err := h.r.Body.Close(); err != nil { + log.Error("serviceRPC: Close: %v", err) + } + + }() if !hasAccess(service, h, true) { h.w.WriteHeader(http.StatusUnauthorized) @@ -469,9 +472,9 @@ func getInfoRefs(h serviceHandler) { h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service)) h.w.WriteHeader(http.StatusOK) - h.w.Write(packetWrite("# service=git-" + service + "\n")) - h.w.Write([]byte("0000")) - h.w.Write(refs) + _, _ = h.w.Write(packetWrite("# service=git-" + service + "\n")) + _, _ = h.w.Write([]byte("0000")) + _, _ = h.w.Write(refs) } else { updateServerInfo(h.dir) h.sendFile("text/plain; charset=utf-8") @@ -524,16 +527,25 @@ func HTTPBackend(ctx *context.Context, cfg *serviceConfig) http.HandlerFunc { if m := route.reg.FindStringSubmatch(r.URL.Path); m != nil { if setting.Repository.DisableHTTPGit { w.WriteHeader(http.StatusForbidden) - w.Write([]byte("Interacting with repositories by HTTP protocol is not allowed")) + _, err := w.Write([]byte("Interacting with repositories by HTTP protocol is not allowed")) + if err != nil { + log.Error(err.Error()) + } return } if route.method != r.Method { if r.Proto == "HTTP/1.1" { w.WriteHeader(http.StatusMethodNotAllowed) - w.Write([]byte("Method Not Allowed")) + _, err := w.Write([]byte("Method Not Allowed")) + if err != nil { + log.Error(err.Error()) + } } else { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Bad Request")) + _, err := w.Write([]byte("Bad Request")) + if err != nil { + log.Error(err.Error()) + } } return } @@ -552,6 +564,5 @@ func HTTPBackend(ctx *context.Context, cfg *serviceConfig) http.HandlerFunc { } ctx.NotFound("HTTPBackend", nil) - return } } diff --git a/routers/repo/issue.go b/routers/repo/issue.go index cd384da0d6..3904d29532 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -945,7 +945,15 @@ func ViewIssue(ctx *context.Context) { // Get Dependencies ctx.Data["BlockedByDependencies"], err = issue.BlockedByDependencies() + if err != nil { + ctx.ServerError("BlockedByDependencies", err) + return + } ctx.Data["BlockingDependencies"], err = issue.BlockingDependencies() + if err != nil { + ctx.ServerError("BlockingDependencies", err) + return + } ctx.Data["Participants"] = participants ctx.Data["NumParticipants"] = len(participants) @@ -1226,7 +1234,8 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) { if form.Status == "reopen" && issue.IsPull { pull := issue.PullRequest - pr, err := models.GetUnmergedPullRequest(pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch) + var err error + pr, err = models.GetUnmergedPullRequest(pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch) if err != nil { if !models.IsErrPullRequestNotExist(err) { ctx.ServerError("GetUnmergedPullRequest", err) diff --git a/routers/repo/issue_label.go b/routers/repo/issue_label.go index 556a24c33e..cae6535c79 100644 --- a/routers/repo/issue_label.go +++ b/routers/repo/issue_label.go @@ -129,7 +129,6 @@ func DeleteLabel(ctx *context.Context) { ctx.JSON(200, map[string]interface{}{ "redirect": ctx.Repo.RepoLink + "/labels", }) - return } // UpdateIssueLabel change issue's labels diff --git a/routers/repo/milestone.go b/routers/repo/milestone.go index 644f7e043b..3ad638e60a 100644 --- a/routers/repo/milestone.go +++ b/routers/repo/milestone.go @@ -19,7 +19,6 @@ import ( const ( tplMilestone base.TplName = "repo/issue/milestones" tplMilestoneNew base.TplName = "repo/issue/milestone_new" - tplMilestoneEdit base.TplName = "repo/issue/milestone_edit" tplMilestoneIssues base.TplName = "repo/issue/milestone_issues" ) @@ -57,7 +56,7 @@ func Milestones(ctx *context.Context) { return } if ctx.Repo.Repository.IsTimetrackerEnabled() { - if miles.LoadTotalTrackedTimes(); err != nil { + if err := miles.LoadTotalTrackedTimes(); err != nil { ctx.ServerError("LoadTotalTrackedTimes", err) return } diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 71c684356d..5be8aa57c1 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -793,10 +793,10 @@ func CleanUpPullRequest(ctx *context.Context) { // Forked repository has already been deleted ctx.NotFound("CleanUpPullRequest", nil) return - } else if pr.GetBaseRepo(); err != nil { + } else if err = pr.GetBaseRepo(); err != nil { ctx.ServerError("GetBaseRepo", err) return - } else if pr.HeadRepo.GetOwner(); err != nil { + } else if err = pr.HeadRepo.GetOwner(); err != nil { ctx.ServerError("HeadRepo.GetOwner", err) return } diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 767cdacde0..757295069e 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -419,7 +419,10 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { return } - repo.DeleteWiki() + err := repo.DeleteWiki() + if err != nil { + log.Error("Delete Wiki: %v", err.Error()) + } log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name) ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success")) diff --git a/routers/repo/view.go b/routers/repo/view.go index 3483a53a0d..edaf24017c 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -294,9 +294,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st // Building code view blocks with line number on server side. var fileContent string if content, err := templates.ToUTF8WithErr(buf); err != nil { - if err != nil { - log.Error("ToUTF8WithErr: %v", err) - } + log.Error("ToUTF8WithErr: %v", err) fileContent = string(buf) } else { fileContent = content diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index 8daf721b50..20a3a45c18 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -197,12 +197,20 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { } // GogsHooksNewPost response for creating webhook -func GogsHooksNewPost(ctx *context.Context, form auth.NewGogshookForm) { +func GogsHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { + newGenericWebhookPost(ctx, form, models.GOGS) +} + +func newGenericWebhookPost(ctx *context.Context, form auth.NewWebhookForm, kind models.HookTaskType) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} - ctx.Data["HookType"] = "gogs" + + ctx.Data["HookType"] = "gitea" + if kind == models.GOGS { + ctx.Data["HookType"] = "gogs" + } orCtx, err := getOrgRepoCtx(ctx) if err != nil { @@ -228,7 +236,7 @@ func GogsHooksNewPost(ctx *context.Context, form auth.NewGogshookForm) { Secret: form.Secret, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.GOGS, + HookTaskType: kind, OrgID: orCtx.OrgID, } if err := w.UpdateEvent(); err != nil { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index f7ccfc43d2..744088a9d7 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -47,19 +47,6 @@ import ( macaron "gopkg.in/macaron.v1" ) -/*func giteaLogger(l *log.LoggerAsWriter) macaron.Handler { - return func(ctx *macaron.Context) { - start := time.Now() - - l.Log(fmt.Sprintf("[Macaron] Started %s %s for %s", ctx.Req.Method, ctx.Req.RequestURI, ctx.RemoteAddr())) - - ctx.Next() - - rw := ctx.Resp.(macaron.ResponseWriter) - l.Log(fmt.Sprintf("[Macaron] Completed %s %s %v %s in %v", ctx.Req.Method, ctx.Req.RequestURI, rw.Status(), http.StatusText(rw.Status()), time.Since(start))) - } -}*/ - type routerLoggerOptions struct { Ctx *macaron.Context Identity *string @@ -83,14 +70,20 @@ func setupAccessLogger(m *macaron.Macaron) { rw := ctx.Resp.(macaron.ResponseWriter) buf := bytes.NewBuffer([]byte{}) - logTemplate.Execute(buf, routerLoggerOptions{ + err := logTemplate.Execute(buf, routerLoggerOptions{ Ctx: ctx, Identity: &identity, Start: &start, ResponseWriter: &rw, }) + if err != nil { + log.Error("Could not set up macaron access logger: %v", err.Error()) + } - logger.SendLog(log.INFO, "", "", 0, buf.String(), "") + err = logger.SendLog(log.INFO, "", "", 0, buf.String(), "") + if err != nil { + log.Error("Could not set up macaron access logger: %v", err.Error()) + } }) } @@ -99,13 +92,13 @@ func RouterHandler(level log.Level) func(ctx *macaron.Context) { return func(ctx *macaron.Context) { start := time.Now() - log.GetLogger("router").Log(0, level, "Started %s %s for %s", log.ColoredMethod(ctx.Req.Method), ctx.Req.RequestURI, ctx.RemoteAddr()) + _ = log.GetLogger("router").Log(0, level, "Started %s %s for %s", log.ColoredMethod(ctx.Req.Method), ctx.Req.RequestURI, ctx.RemoteAddr()) rw := ctx.Resp.(macaron.ResponseWriter) ctx.Next() status := rw.Status() - log.GetLogger("router").Log(0, level, "Completed %s %s %v %s in %v", log.ColoredMethod(ctx.Req.Method), ctx.Req.RequestURI, log.ColoredStatus(status), log.ColoredStatus(status, http.StatusText(rw.Status())), log.ColoredTime(time.Since(start))) + _ = log.GetLogger("router").Log(0, level, "Completed %s %s %v %s in %v", log.ColoredMethod(ctx.Req.Method), ctx.Req.RequestURI, log.ColoredStatus(status), log.ColoredStatus(status, http.StatusText(rw.Status())), log.ColoredTime(time.Since(start))) } } @@ -443,14 +436,14 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", admin.DeleteDefaultWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) m.Get("/:id", repo.WebHooksEdit) m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) - m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost) + m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksEditPost) m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) @@ -582,7 +575,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", org.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) @@ -640,7 +633,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", repo.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) diff --git a/routers/user/auth.go b/routers/user/auth.go index b8f697b3ca..0731e34675 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -77,8 +77,14 @@ func AutoSignIn(ctx *context.Context) (bool, error) { } isSucceed = true - ctx.Session.Set("uid", u.ID) - ctx.Session.Set("uname", u.Name) + err = ctx.Session.Set("uid", u.ID) + if err != nil { + return false, err + } + err = ctx.Session.Set("uname", u.Name) + if err != nil { + return false, err + } ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) return true, nil } @@ -191,8 +197,16 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) { } // User needs to use 2FA, save data and redirect to 2FA page. - ctx.Session.Set("twofaUid", u.ID) - ctx.Session.Set("twofaRemember", form.Remember) + err = ctx.Session.Set("twofaUid", u.ID) + if err != nil { + ctx.ServerError("UserSignIn", err) + return + } + err = ctx.Session.Set("twofaRemember", form.Remember) + if err != nil { + ctx.ServerError("UserSignIn", err) + return + } regs, err := models.GetU2FRegistrationsByUID(u.ID) if err == nil && len(regs) > 0 { @@ -383,6 +397,10 @@ func U2FChallenge(ctx *context.Context) { return } challenge, err := u2f.NewChallenge(setting.U2F.AppID, setting.U2F.TrustedFacets) + if err != nil { + ctx.ServerError("u2f.NewChallenge", err) + return + } if err = ctx.Session.Set("u2fChallenge", challenge); err != nil { ctx.ServerError("UserSignIn", err) return @@ -462,16 +480,22 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR setting.CookieRememberName, u.Name, days, setting.AppSubURL, "", setting.SessionConfig.Secure, true) } - ctx.Session.Delete("openid_verified_uri") - ctx.Session.Delete("openid_signin_remember") - ctx.Session.Delete("openid_determined_email") - ctx.Session.Delete("openid_determined_username") - ctx.Session.Delete("twofaUid") - ctx.Session.Delete("twofaRemember") - ctx.Session.Delete("u2fChallenge") - ctx.Session.Delete("linkAccount") - ctx.Session.Set("uid", u.ID) - ctx.Session.Set("uname", u.Name) + _ = ctx.Session.Delete("openid_verified_uri") + _ = ctx.Session.Delete("openid_signin_remember") + _ = ctx.Session.Delete("openid_determined_email") + _ = ctx.Session.Delete("openid_determined_username") + _ = ctx.Session.Delete("twofaUid") + _ = ctx.Session.Delete("twofaRemember") + _ = ctx.Session.Delete("u2fChallenge") + _ = ctx.Session.Delete("linkAccount") + err := ctx.Session.Set("uid", u.ID) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } + err = ctx.Session.Set("uname", u.Name) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } // Language setting of the user overwrites the one previously set // If the user does not have a locale set, we save the current one. @@ -563,7 +587,10 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context if u == nil { // no existing user is found, request attach or new account - ctx.Session.Set("linkAccountGothUser", gothUser) + err = ctx.Session.Set("linkAccountGothUser", gothUser) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } ctx.Redirect(setting.AppSubURL + "/user/link_account") return } @@ -573,8 +600,14 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context _, err = models.GetTwoFactorByUID(u.ID) if err != nil { if models.IsErrTwoFactorNotEnrolled(err) { - ctx.Session.Set("uid", u.ID) - ctx.Session.Set("uname", u.Name) + err = ctx.Session.Set("uid", u.ID) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } + err = ctx.Session.Set("uname", u.Name) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } // Clear whatever CSRF has right now, force to generate a new one ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) @@ -600,8 +633,14 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context } // User needs to use 2FA, save data and redirect to 2FA page. - ctx.Session.Set("twofaUid", u.ID) - ctx.Session.Set("twofaRemember", false) + err = ctx.Session.Set("twofaUid", u.ID) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } + err = ctx.Session.Set("twofaRemember", false) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } // If U2F is enrolled -> Redirect to U2F instead regs, err := models.GetU2FRegistrationsByUID(u.ID) @@ -760,9 +799,18 @@ func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) { } // User needs to use 2FA, save data and redirect to 2FA page. - ctx.Session.Set("twofaUid", u.ID) - ctx.Session.Set("twofaRemember", signInForm.Remember) - ctx.Session.Set("linkAccount", true) + err = ctx.Session.Set("twofaUid", u.ID) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } + err = ctx.Session.Set("twofaRemember", signInForm.Remember) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } + err = ctx.Session.Set("linkAccount", true) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } // If U2F is enrolled -> Redirect to U2F instead regs, err := models.GetU2FRegistrationsByUID(u.ID) @@ -897,11 +945,11 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au } func handleSignOut(ctx *context.Context) { - ctx.Session.Delete("uid") - ctx.Session.Delete("uname") - ctx.Session.Delete("socialId") - ctx.Session.Delete("socialName") - ctx.Session.Delete("socialEmail") + _ = ctx.Session.Delete("uid") + _ = ctx.Session.Delete("uname") + _ = ctx.Session.Delete("socialId") + _ = ctx.Session.Delete("socialName") + _ = ctx.Session.Delete("socialEmail") ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) @@ -1086,8 +1134,14 @@ func Activate(ctx *context.Context) { log.Trace("User activated: %s", user.Name) - ctx.Session.Set("uid", user.ID) - ctx.Session.Set("uname", user.Name) + err = ctx.Session.Set("uid", user.ID) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } + err = ctx.Session.Set("uname", user.Name) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } ctx.Flash.Success(ctx.Tr("auth.account_activated")) ctx.Redirect(setting.AppSubURL + "/") return @@ -1113,7 +1167,6 @@ func ActivateEmail(ctx *context.Context) { } ctx.Redirect(setting.AppSubURL + "/user/settings/email") - return } // ForgotPasswd render the forget pasword page diff --git a/routers/user/auth_openid.go b/routers/user/auth_openid.go index 1351ca040b..f98c07acd7 100644 --- a/routers/user/auth_openid.go +++ b/routers/user/auth_openid.go @@ -126,7 +126,10 @@ func SignInOpenIDPost(ctx *context.Context, form auth.SignInOpenIDForm) { url += "&openid.sreg.optional=nickname%2Cemail" log.Trace("Form-passed openid-remember: %t", form.Remember) - ctx.Session.Set("openid_signin_remember", form.Remember) + err = ctx.Session.Set("openid_signin_remember", form.Remember) + if err != nil { + log.Error("SignInOpenIDPost: Could not set session: %v", err.Error()) + } ctx.Redirect(url) } @@ -152,7 +155,7 @@ func signInOpenIDVerify(ctx *context.Context) { /* Now we should seek for the user and log him in, or prompt * to register if not found */ - u, _ := models.GetUserByOpenID(id) + u, err := models.GetUserByOpenID(id) if err != nil { if !models.IsErrUserNotExist(err) { ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{ @@ -160,6 +163,7 @@ func signInOpenIDVerify(ctx *context.Context) { }) return } + log.Error("signInOpenIDVerify: %v", err) } if u != nil { log.Trace("User exists, logging in") @@ -191,7 +195,7 @@ func signInOpenIDVerify(ctx *context.Context) { log.Trace("User has email=" + email + " and nickname=" + nickname) if email != "" { - u, _ = models.GetUserByEmail(email) + u, err = models.GetUserByEmail(email) if err != nil { if !models.IsErrUserNotExist(err) { ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{ @@ -199,6 +203,7 @@ func signInOpenIDVerify(ctx *context.Context) { }) return } + log.Error("signInOpenIDVerify: %v", err) } if u != nil { log.Trace("Local user " + u.LowerName + " has OpenID provided email " + email) @@ -220,15 +225,24 @@ func signInOpenIDVerify(ctx *context.Context) { } } - ctx.Session.Set("openid_verified_uri", id) + err = ctx.Session.Set("openid_verified_uri", id) + if err != nil { + log.Error("signInOpenIDVerify: Could not set session: %v", err.Error()) + } - ctx.Session.Set("openid_determined_email", email) + err = ctx.Session.Set("openid_determined_email", email) + if err != nil { + log.Error("signInOpenIDVerify: Could not set session: %v", err.Error()) + } if u != nil { nickname = u.LowerName } - ctx.Session.Set("openid_determined_username", nickname) + err = ctx.Session.Set("openid_determined_username", nickname) + if err != nil { + log.Error("signInOpenIDVerify: Could not set session: %v", err.Error()) + } if u != nil || !setting.Service.EnableOpenIDSignUp { ctx.Redirect(setting.AppSubURL + "/user/openid/connect") @@ -350,7 +364,11 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si } if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ReCaptcha { - ctx.Req.ParseForm() + err := ctx.Req.ParseForm() + if err != nil { + ctx.ServerError("", err) + return + } valid, _ := recaptcha.Verify(form.GRecaptchaResponse) if !valid { ctx.Data["Err_Captcha"] = true diff --git a/routers/user/oauth.go b/routers/user/oauth.go index b85ea8125e..aaad26201b 100644 --- a/routers/user/oauth.go +++ b/routers/user/oauth.go @@ -7,12 +7,10 @@ package user import ( "encoding/base64" "fmt" + "github.com/go-macaron/binding" "net/url" "strings" - "github.com/dgrijalva/jwt-go" - "github.com/go-macaron/binding" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" @@ -20,6 +18,8 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + + "github.com/dgrijalva/jwt-go" ) const ( @@ -164,6 +164,14 @@ func newAccessTokenResponse(grant *models.OAuth2Grant) (*AccessTokenResponse, *A func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) { errs := binding.Errors{} errs = form.Validate(ctx.Context, errs) + if len(errs) > 0 { + errstring := "" + for _, e := range errs { + errstring += e.Error() + "\n" + } + ctx.ServerError("AuthorizeOAuth: Validate: ", fmt.Errorf("errors occured during validation: %s", errstring)) + return + } app, err := models.GetOAuth2ApplicationByClientID(form.ClientID) if err != nil { @@ -221,7 +229,6 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) { }, form.RedirectURI) return } - break case "": break default: @@ -262,9 +269,24 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) { ctx.Data["ApplicationUserLink"] = "@" + app.User.Name + "" ctx.Data["ApplicationRedirectDomainHTML"] = "" + form.RedirectURI + "" // TODO document SESSION <=> FORM - ctx.Session.Set("client_id", app.ClientID) - ctx.Session.Set("redirect_uri", form.RedirectURI) - ctx.Session.Set("state", form.State) + err = ctx.Session.Set("client_id", app.ClientID) + if err != nil { + handleServerError(ctx, form.State, form.RedirectURI) + log.Error(err.Error()) + return + } + err = ctx.Session.Set("redirect_uri", form.RedirectURI) + if err != nil { + handleServerError(ctx, form.State, form.RedirectURI) + log.Error(err.Error()) + return + } + err = ctx.Session.Set("state", form.State) + if err != nil { + handleServerError(ctx, form.State, form.RedirectURI) + log.Error(err.Error()) + return + } ctx.HTML(200, tplGrantAccess) } diff --git a/routers/user/profile.go b/routers/user/profile.go index bda29522d9..7df92d44f5 100644 --- a/routers/user/profile.go +++ b/routers/user/profile.go @@ -20,7 +20,6 @@ import ( const ( tplFollowers base.TplName = "user/meta/followers" - tplStars base.TplName = "user/meta/stars" ) // GetUserByName get user by name diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index ac5c4c97fb..163bc869b4 100644 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -141,13 +141,11 @@ func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm, ctxUser *mo if err = ctxUser.UploadAvatar(data); err != nil { return fmt.Errorf("UploadAvatar: %v", err) } - } else { + } else if ctxUser.UseCustomAvatar && !com.IsFile(ctxUser.CustomAvatarPath()) { // No avatar is uploaded but setting has been changed to enable, // generate a random one when needed. - if ctxUser.UseCustomAvatar && !com.IsFile(ctxUser.CustomAvatarPath()) { - if err := ctxUser.GenerateRandomAvatar(); err != nil { - log.Error("GenerateRandomAvatar[%d]: %v", ctxUser.ID, err) - } + if err := ctxUser.GenerateRandomAvatar(); err != nil { + log.Error("GenerateRandomAvatar[%d]: %v", ctxUser.ID, err) } } diff --git a/routers/user/setting/security_twofa.go b/routers/user/setting/security_twofa.go index fca1151a04..6e3516dbba 100644 --- a/routers/user/setting/security_twofa.go +++ b/routers/user/setting/security_twofa.go @@ -73,6 +73,10 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool { uri := ctx.Session.Get("twofaUri") if uri != nil { otpKey, err = otp.NewKeyFromURL(uri.(string)) + if err != nil { + ctx.ServerError("SettingsTwoFactor: NewKeyFromURL: ", err) + return false + } } // Filter unsafe character ':' in issuer issuer := strings.Replace(setting.AppName+" ("+setting.Domain+")", ":", "", -1) @@ -103,8 +107,16 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool { } ctx.Data["QrUri"] = template.URL("data:image/png;base64," + base64.StdEncoding.EncodeToString(imgBytes.Bytes())) - ctx.Session.Set("twofaSecret", otpKey.Secret()) - ctx.Session.Set("twofaUri", otpKey.String()) + err = ctx.Session.Set("twofaSecret", otpKey.Secret()) + if err != nil { + ctx.ServerError("SettingsTwoFactor", err) + return false + } + err = ctx.Session.Set("twofaUri", otpKey.String()) + if err != nil { + ctx.ServerError("SettingsTwoFactor", err) + return false + } return true } @@ -184,8 +196,16 @@ func EnrollTwoFactorPost(ctx *context.Context, form auth.TwoFactorAuthForm) { return } - ctx.Session.Delete("twofaSecret") - ctx.Session.Delete("twofaUri") + err = ctx.Session.Delete("twofaSecret") + if err != nil { + ctx.ServerError("SettingsTwoFactor", err) + return + } + err = ctx.Session.Delete("twofaUri") + if err != nil { + ctx.ServerError("SettingsTwoFactor", err) + return + } ctx.Flash.Success(ctx.Tr("settings.twofa_enrolled", token)) ctx.Redirect(setting.AppSubURL + "/user/settings/security") } diff --git a/routers/user/setting/security_u2f.go b/routers/user/setting/security_u2f.go index c1d6eab967..b733467b84 100644 --- a/routers/user/setting/security_u2f.go +++ b/routers/user/setting/security_u2f.go @@ -42,7 +42,11 @@ func U2FRegister(ctx *context.Context, form auth.U2FRegistrationForm) { return } } - ctx.Session.Set("u2fName", form.Name) + err = ctx.Session.Set("u2fName", form.Name) + if err != nil { + ctx.ServerError("", err) + return + } ctx.JSON(200, u2f.NewWebRegisterRequest(challenge, regs.ToRegistrations())) } @@ -95,5 +99,4 @@ func U2FDelete(ctx *context.Context, form auth.U2FDeleteForm) { ctx.JSON(200, map[string]interface{}{ "redirect": setting.AppSubURL + "/user/settings/security", }) - return } diff --git a/templates/user/meta/stars.tmpl b/templates/user/meta/stars.tmpl deleted file mode 100644 index e69de29bb2..0000000000 From 744fd6a1c87f2ad39dbe282133fae1190df6e538 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Wed, 12 Jun 2019 15:20:43 -0500 Subject: [PATCH 110/220] Add error for fork already existing (#7185) --- models/error.go | 17 +++++++++++++++++ models/repo.go | 7 ++++--- models/repo_test.go | 2 +- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/models/error.go b/models/error.go index fe0f05d36b..11ca6e6863 100644 --- a/models/error.go +++ b/models/error.go @@ -674,6 +674,23 @@ func (err ErrRepoAlreadyExist) Error() string { return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name) } +// ErrForkAlreadyExist represents a "ForkAlreadyExist" kind of error. +type ErrForkAlreadyExist struct { + Uname string + RepoName string + ForkName string +} + +// IsErrForkAlreadyExist checks if an error is an ErrForkAlreadyExist. +func IsErrForkAlreadyExist(err error) bool { + _, ok := err.(ErrForkAlreadyExist) + return ok +} + +func (err ErrForkAlreadyExist) Error() string { + return fmt.Sprintf("repository is already forked by user [uname: %s, repo path: %s, fork path: %s]", err.Uname, err.RepoName, err.ForkName) +} + // ErrRepoRedirectNotExist represents a "RepoRedirectNotExist" kind of error. type ErrRepoRedirectNotExist struct { OwnerID int64 diff --git a/models/repo.go b/models/repo.go index a4a7521aa4..8819debd4b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -2395,9 +2395,10 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R return nil, err } if forkedRepo != nil { - return nil, ErrRepoAlreadyExist{ - Uname: u.Name, - Name: forkedRepo.Name, + return nil, ErrForkAlreadyExist{ + Uname: u.Name, + RepoName: oldRepo.FullName(), + ForkName: forkedRepo.FullName(), } } diff --git a/models/repo_test.go b/models/repo_test.go index 8411536d70..02cb5ab993 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -131,7 +131,7 @@ func TestForkRepository(t *testing.T) { fork, err := ForkRepository(user, user, repo, "test", "test") assert.Nil(t, fork) assert.Error(t, err) - assert.True(t, IsErrRepoAlreadyExist(err)) + assert.True(t, IsErrForkAlreadyExist(err)) } func TestRepoAPIURL(t *testing.T) { From 8f0182c3229dfbb8d731557e5006e39bd616b4e9 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Wed, 12 Jun 2019 16:07:24 -0500 Subject: [PATCH 111/220] API error cleanup (#7186) --- integrations/api_repo_file_content_test.go | 3 +-- integrations/api_repo_file_create_test.go | 3 +-- integrations/api_repo_file_delete_test.go | 4 ++-- integrations/api_repo_file_update_test.go | 3 +-- modules/base/base.go | 3 --- modules/context/api.go | 13 ++----------- modules/setting/setting.go | 12 +++++++++--- 7 files changed, 16 insertions(+), 25 deletions(-) diff --git a/integrations/api_repo_file_content_test.go b/integrations/api_repo_file_content_test.go index 896d811083..7a6025d423 100644 --- a/integrations/api_repo_file_content_test.go +++ b/integrations/api_repo_file_content_test.go @@ -11,7 +11,6 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -98,7 +97,7 @@ func testAPIGetFileContents(t *testing.T, u *url.URL) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "object does not exist [id: " + branch + ", rel_path: ]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index 3bb2ecb812..973ed9dfa5 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -13,7 +13,6 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" @@ -160,7 +159,7 @@ func TestAPICreateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "repository file already exists [path: " + treePath + "]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/integrations/api_repo_file_delete_test.go b/integrations/api_repo_file_delete_test.go index e9029a669b..2f5f9028a8 100644 --- a/integrations/api_repo_file_delete_test.go +++ b/integrations/api_repo_file_delete_test.go @@ -11,8 +11,8 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -102,7 +102,7 @@ func TestAPIDeleteFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "sha does not match [given: " + deleteFileOptions.SHA + ", expected: " + correctSHA + "]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index eab7090df6..90fecf59d0 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -13,7 +13,6 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" @@ -173,7 +172,7 @@ func TestAPIUpdateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "sha does not match [given: " + updateFileOptions.SHA + ", expected: " + correctSHA + "]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/modules/base/base.go b/modules/base/base.go index 0ba72c328e..026f68f646 100644 --- a/modules/base/base.go +++ b/modules/base/base.go @@ -4,9 +4,6 @@ package base -// DocURL api doc url -const DocURL = "https://godoc.org/github.com/go-gitea/go-sdk/gitea" - type ( // TplName template relative path type TplName string diff --git a/modules/context/api.go b/modules/context/api.go index 61f6514759..9be3fb512c 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -7,14 +7,11 @@ package context import ( "fmt" - "net/url" - "path" "strings" "github.com/go-macaron/csrf" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -76,7 +73,7 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) { ctx.JSON(status, APIError{ Message: message, - URL: base.DocURL, + URL: setting.API.SwaggerURL, }) } @@ -180,15 +177,9 @@ func (ctx *APIContext) NotFound(objs ...interface{}) { } } - u, err := url.Parse(setting.AppURL) - if err != nil { - ctx.Error(500, "Invalid AppURL", err) - return - } - u.Path = path.Join(u.Path, "api", "swagger") ctx.JSON(404, map[string]interface{}{ "message": message, - "documentation_url": u.String(), + "documentation_url": setting.API.SwaggerURL, "errors": errors, }) } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index b550836bc1..5471a0b61d 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -297,12 +297,14 @@ var ( // API settings API = struct { EnableSwagger bool + SwaggerURL string MaxResponseItems int DefaultPagingNum int DefaultGitTreesPerPage int DefaultMaxBlobSize int64 }{ EnableSwagger: true, + SwaggerURL: "", MaxResponseItems: 50, DefaultPagingNum: 30, DefaultGitTreesPerPage: 1000, @@ -581,17 +583,17 @@ func NewContext() { AppURL = strings.TrimRight(AppURL, "/") + "/" // Check if has app suburl. - url, err := url.Parse(AppURL) + appURL, err := url.Parse(AppURL) if err != nil { log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err) } // Suburl should start with '/' and end without '/', such as '/{subpath}'. // This value is empty if site does not have sub-url. - AppSubURL = strings.TrimSuffix(url.Path, "/") + AppSubURL = strings.TrimSuffix(appURL.Path, "/") AppSubURLDepth = strings.Count(AppSubURL, "/") // Check if Domain differs from AppURL domain than update it to AppURL's domain // TODO: Can be replaced with url.Hostname() when minimal GoLang version is 1.8 - urlHostname := strings.SplitN(url.Host, ":", 2)[0] + urlHostname := strings.SplitN(appURL.Host, ":", 2)[0] if urlHostname != Domain && net.ParseIP(urlHostname) == nil { Domain = urlHostname } @@ -900,6 +902,10 @@ func NewContext() { log.Fatal("Failed to map Metrics settings: %v", err) } + u := *appURL + u.Path = path.Join(u.Path, "api", "swagger") + API.SwaggerURL = u.String() + newCron() newGit() From 2f39fc7bb6a17b4637b723026a2e18dafd1a0adb Mon Sep 17 00:00:00 2001 From: Cherrg Date: Thu, 13 Jun 2019 06:23:45 +0200 Subject: [PATCH 112/220] fix drone build bug (#7192) --- Makefile | 1 + public/less/_repository.less | 2 ++ routers/user/oauth.go | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d7f27a8a94..56fa863c8e 100644 --- a/Makefile +++ b/Makefile @@ -469,6 +469,7 @@ pr: .PHONY: golangci-lint golangci-lint: @hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + export BINARY="golangci-lint"; \ curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.16.0; \ fi golangci-lint run diff --git a/public/less/_repository.less b/public/less/_repository.less index fcc153e31e..71062bfa0e 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -1112,6 +1112,7 @@ .show-form-container { text-align: left; } + .choose.branch { .octicon { padding-right: 10px; @@ -2226,6 +2227,7 @@ tbody.commit-list { &.top { text-align: left; } + .commit-body { margin: 0; } diff --git a/routers/user/oauth.go b/routers/user/oauth.go index aaad26201b..924bac8ef6 100644 --- a/routers/user/oauth.go +++ b/routers/user/oauth.go @@ -169,7 +169,7 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) { for _, e := range errs { errstring += e.Error() + "\n" } - ctx.ServerError("AuthorizeOAuth: Validate: ", fmt.Errorf("errors occured during validation: %s", errstring)) + ctx.ServerError("AuthorizeOAuth: Validate: ", fmt.Errorf("errors occurred during validation: %s", errstring)) return } From 9ce4d89e9922cc87bdb13d122339ae165a080c3d Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 14 Jun 2019 03:32:14 +0200 Subject: [PATCH 113/220] UI: Fix overflow issues in repo (#7190) - Fix layout overflow in repo file list. - Fix invisible status icon in file view and commit list. In file view, the icon was moved to the left because I could not figure out a proper fix because of HTML tables. - Added title attribute to commit messages. - Fixed two CSS linter warnings in existing CSS. - Fixed CI variable check in 'make css'. Fixes: https://github.com/go-gitea/gitea/issues/7180 --- Makefile | 2 +- public/css/index.css | 2 ++ public/less/_repository.less | 13 +++++++++++++ templates/repo/commit_status.tmpl | 10 +++++----- templates/repo/commits_table.tmpl | 18 ++++++++++-------- templates/repo/view_list.tmpl | 9 +++++---- 6 files changed, 36 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 56fa863c8e..1fca897d05 100644 --- a/Makefile +++ b/Makefile @@ -395,7 +395,7 @@ css: npx postcss --use autoprefixer --no-map --replace public/css/* @diff=$$(git diff public/css/*); \ - if ([ ! -z "$CI" ] && [ -n "$$diff" ]); then \ + if ([ -n "$$CI" ] && [ -n "$$diff" ]); then \ echo "Generated files in public/css have changed, please commit the result:"; \ echo "$${diff}"; \ exit 1; \ diff --git a/public/css/index.css b/public/css/index.css index d192f43d15..8f575fcd95 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -803,6 +803,8 @@ footer .ui.left,footer .ui.right{line-height:40px} .stats-table .table-cell{display:table-cell} .stats-table .table-cell.tiny{height:.5em} tbody.commit-list{vertical-align:baseline} +.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 24px);display:inline-block;vertical-align:middle} +.commit-list .message-wrapper .commit-status-link{display:inline-block;vertical-align:middle} .commit-body{white-space:pre-wrap} .git-notes.top{text-align:left} .git-notes .commit-body{margin:0} diff --git a/public/less/_repository.less b/public/less/_repository.less index 71062bfa0e..acf8d7b870 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -2219,6 +2219,19 @@ tbody.commit-list { vertical-align: baseline; } +.commit-list .message-wrapper { + overflow: hidden; + text-overflow: ellipsis; + max-width: calc(100% - 24px); + display: inline-block; + vertical-align: middle; +} + +.commit-list .message-wrapper .commit-status-link { + display: inline-block; + vertical-align: middle; +} + .commit-body { white-space: pre-wrap; } diff --git a/templates/repo/commit_status.tmpl b/templates/repo/commit_status.tmpl index f5bbbb02d6..638f81ed8f 100644 --- a/templates/repo/commit_status.tmpl +++ b/templates/repo/commit_status.tmpl @@ -1,15 +1,15 @@ {{if eq .State "pending"}} - + {{end}} {{if eq .State "success"}} - + {{end}} {{if eq .State "error"}} - + {{end}} {{if eq .State "failure"}} - + {{end}} {{if eq .State "warning"}} - + {{end}} diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index 10f4b60483..ebeb87b93c 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -47,9 +47,9 @@ {{if .User}} {{if .User.FullName}} -   {{.User.FullName}} +   {{.User.FullName}} {{else}} -   {{.Author.Name}} +   {{.Author.Name}} {{end}} {{else}}   {{.Author.Name}} @@ -69,12 +69,14 @@ {{end}} - - {{.Summary}} - {{if IsMultilineCommitMessage .Message}} - - - {{end}} + + + {{.Summary}} + {{if IsMultilineCommitMessage .Message}} + + + {{end}} + {{template "repo/commit_status" .Status}} {{TimeSince .Author.When $.Lang}} diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index d88c42ccae..75269837cb 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -1,4 +1,4 @@ - +
    @@ -82,7 +83,7 @@ {{end}} From 94ceaf1c0c2ae0b5abcb3b62c5c903258659615c Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 15 Jun 2019 05:00:32 +0100 Subject: [PATCH 114/220] Allow colon between fixing word and issue (#7207) * Allow colon between fixing word and issue * update test --- models/action.go | 2 +- models/action_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/models/action.go b/models/action.go index b4f4b1cb6d..ee5d052509 100644 --- a/models/action.go +++ b/models/action.go @@ -67,7 +67,7 @@ var ( const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+` func assembleKeywordsPattern(words []string) string { - return fmt.Sprintf(`(?i)(?:%s) %s`, strings.Join(words, "|"), issueRefRegexpStr) + return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr) } func init() { diff --git a/models/action_test.go b/models/action_test.go index 9ba2057318..53a3202894 100644 --- a/models/action_test.go +++ b/models/action_test.go @@ -166,6 +166,7 @@ func Test_getIssueFromRef(t *testing.T) { {"reopen #2", 2}, {"user2/repo2#1", 4}, {"fixes user2/repo2#1", 4}, + {"fixes: user2/repo2#1", 4}, } { issue, err := getIssueFromRef(repo, test.Ref) assert.NoError(t, err) @@ -260,6 +261,31 @@ func TestUpdateIssuesCommit(t *testing.T) { CheckConsistencyFor(t, &Action{}) } +func TestUpdateIssuesCommit_Colon(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + pushCommits := []*PushCommit{ + { + Sha1: "abcdef2", + CommitterEmail: "user2@example.com", + CommitterName: "User Two", + AuthorEmail: "user2@example.com", + AuthorName: "User Two", + Message: "close: #2", + }, + } + + user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) + repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo.Owner = user + + issueBean := &Issue{RepoID: repo.ID, Index: 2} + + AssertNotExistsBean(t, &Issue{RepoID: repo.ID, Index: 2}, "is_closed=1") + assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, repo.DefaultBranch)) + AssertExistsAndLoadBean(t, issueBean, "is_closed=1") + CheckConsistencyFor(t, &Action{}) +} + func TestUpdateIssuesCommit_Issue5957(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) From 0323122fd79f42296470bdc02dee57a5ef8e72c9 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 15 Jun 2019 22:22:26 +0800 Subject: [PATCH 115/220] fix duplicated file on pull request conflicted files (#7211) --- models/pull.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/models/pull.go b/models/pull.go index 7a168181e2..e5d421e6ba 100644 --- a/models/pull.go +++ b/models/pull.go @@ -863,7 +863,17 @@ func (pr *PullRequest) testPatch(e Engine) (err error) { line := scanner.Text() if strings.HasPrefix(line, prefix) { - pr.ConflictedFiles = append(pr.ConflictedFiles, strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0])) + var found bool + var filepath = strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0]) + for _, f := range pr.ConflictedFiles { + if f == filepath { + found = true + break + } + } + if !found { + pr.ConflictedFiles = append(pr.ConflictedFiles, filepath) + } } // only list 10 conflicted files if len(pr.ConflictedFiles) >= 10 { From cde410521ce235d1fccbb576a877b129c2da68d4 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 15 Jun 2019 23:20:29 +0100 Subject: [PATCH 116/220] Only warn on errors in deleting LFS orphaned files during repo deletion (#7213) --- models/admin.go | 2 +- models/repo.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/models/admin.go b/models/admin.go index f75428ad4e..4480d11480 100644 --- a/models/admin.go +++ b/models/admin.go @@ -63,7 +63,7 @@ func RemoveAllWithNotice(title, path string) { func removeAllWithNotice(e Engine, title, path string) { if err := os.RemoveAll(path); err != nil { desc := fmt.Sprintf("%s [%s]: %v", title, path, err) - log.Warn(desc) + log.Warn(title+" [%s]: %v", path, err) if err = createNotice(e, NoticeRepository, desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } diff --git a/models/repo.go b/models/repo.go index 8819debd4b..215222e279 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1882,10 +1882,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { } oidPath := filepath.Join(v.Oid[0:2], v.Oid[2:4], v.Oid[4:len(v.Oid)]) - err = os.Remove(filepath.Join(setting.LFS.ContentPath, oidPath)) - if err != nil { - return err - } + removeAllWithNotice(sess, "Delete orphaned LFS file", oidPath) } if _, err := sess.Delete(&LFSMetaObject{RepositoryID: repoID}); err != nil { From 273f1997ff21493bba38e9108ef668ce2d00f6aa Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 16 Jun 2019 04:49:07 +0200 Subject: [PATCH 117/220] setting: don't require same running user for internal SSH (like win platform) (#7215) --- modules/setting/setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 5471a0b61d..43a61aa7fa 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -438,7 +438,7 @@ func forcePathSeparator(path string) { // This check is ignored under Windows since SSH remote login is not the main // method to login on Windows. func IsRunUserMatchCurrentUser(runUser string) (string, bool) { - if IsWindows { + if IsWindows || SSH.StartBuiltinServer { return "", true } From cf2221e3acce4d2c88c09976557ce3e73068baaf Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 16 Jun 2019 04:28:32 +0100 Subject: [PATCH 118/220] Add LastLogin to the User API (#7196) --- models/user.go | 2 ++ modules/structs/user.go | 5 +++++ routers/api/v1/convert/convert.go | 2 ++ templates/swagger/v1_json.tmpl | 10 ++++++++++ 4 files changed, 19 insertions(+) diff --git a/models/user.go b/models/user.go index 2820d2edbc..4dc9aec650 100644 --- a/models/user.go +++ b/models/user.go @@ -214,6 +214,8 @@ func (u *User) APIFormat() *api.User { AvatarURL: u.AvatarLink(), Language: u.Language, IsAdmin: u.IsAdmin, + LastLogin: u.LastLoginUnix.AsTime(), + Created: u.CreatedUnix.AsTime(), } } diff --git a/modules/structs/user.go b/modules/structs/user.go index 251c803129..bf52cc9ed6 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -6,6 +6,7 @@ package structs import ( "encoding/json" + "time" ) // User represents a user @@ -25,6 +26,10 @@ type User struct { Language string `json:"language"` // Is the user an administrator IsAdmin bool `json:"is_admin"` + // swagger:strfmt date-time + LastLogin time.Time `json:"last_login,omitempty"` + // swagger:strfmt date-time + Created time.Time `json:"created,omitempty"` } // MarshalJSON implements the json.Marshaler interface for User, adding field(s) for backward compatibility diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index a982cb8d37..80c0811aed 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -236,6 +236,8 @@ func ToUser(user *models.User, signed, admin bool) *api.User { AvatarURL: user.AvatarLink(), FullName: markup.Sanitize(user.FullName), IsAdmin: user.IsAdmin, + LastLogin: user.LastLoginUnix.AsTime(), + Created: user.CreatedUnix.AsTime(), } if signed && (!user.KeepEmailPrivate || admin) { result.Email = user.Email diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 2b40c89791..6f9585fae2 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -9715,6 +9715,11 @@ "type": "string", "x-go-name": "AvatarURL" }, + "created": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, "email": { "type": "string", "format": "email", @@ -9741,6 +9746,11 @@ "type": "string", "x-go-name": "Language" }, + "last_login": { + "type": "string", + "format": "date-time", + "x-go-name": "LastLogin" + }, "login": { "description": "the user's username", "type": "string", From 367aeb169ac9f213a047bad24bbb3a4f58e3362a Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 16 Jun 2019 09:50:46 +0200 Subject: [PATCH 119/220] Use go method to calculate ssh key fingerprint (#7128) * Use go method to calculate key fingerprint * add gitea copyright * use native go method only for built-in server * refactor and add tests * add gitea copyright --- models/ssh_key.go | 31 +++++++++++++++- models/ssh_key_test.go | 82 +++++++++++++++++++++++++++++++----------- 2 files changed, 92 insertions(+), 21 deletions(-) diff --git a/models/ssh_key.go b/models/ssh_key.go index 1f2288b13e..15a10826d8 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -1,4 +1,5 @@ // Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -359,7 +360,7 @@ func checkKeyFingerprint(e Engine, fingerprint string) error { return nil } -func calcFingerprint(publicKeyContent string) (string, error) { +func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) { // Calculate fingerprint. tmpPath, err := writeTmpKeyFile(publicKeyContent) if err != nil { @@ -375,6 +376,34 @@ func calcFingerprint(publicKeyContent string) (string, error) { return strings.Split(stdout, " ")[1], nil } +func calcFingerprintNative(publicKeyContent string) (string, error) { + // Calculate fingerprint. + pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent)) + if err != nil { + return "", err + } + return ssh.FingerprintSHA256(pk), nil +} + +func calcFingerprint(publicKeyContent string) (string, error) { + //Call the method based on configuration + var ( + fnName, fp string + err error + ) + if setting.SSH.StartBuiltinServer { + fnName = "calcFingerprintNative" + fp, err = calcFingerprintNative(publicKeyContent) + } else { + fnName = "calcFingerprintSSHKeygen" + fp, err = calcFingerprintSSHKeygen(publicKeyContent) + } + if err != nil { + return "", fmt.Errorf("%s: %v", fnName, err) + } + return fp, nil +} + func addKey(e Engine, key *PublicKey) (err error) { if len(key.Fingerprint) == 0 { key.Fingerprint, err = calcFingerprint(key.Content) diff --git a/models/ssh_key_test.go b/models/ssh_key_test.go index 82f5f9724b..5d095f6378 100644 --- a/models/ssh_key_test.go +++ b/models/ssh_key_test.go @@ -1,4 +1,5 @@ // Copyright 2016 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -19,26 +20,67 @@ func init() { } func Test_SSHParsePublicKey(t *testing.T) { - test := func(name, keyType string, length int, content string) { - keyTypeN, lengthN, err := SSHNativeParsePublicKey(content) - assert.NoError(t, err) - assert.Equal(t, keyType, keyTypeN) - assert.EqualValues(t, length, lengthN) - - keyTypeK, lengthK, err := SSHKeyGenParsePublicKey(content) - if err != nil { - // Some servers do not support ecdsa format. - if !strings.Contains(err.Error(), "line 1 too long:") { - assert.Fail(t, "%v", err) - } - } - assert.Equal(t, keyType, keyTypeK) - assert.EqualValues(t, length, lengthK) + testCases := []struct { + name string + keyType string + length int + content string + }{ + {"dsa-1024", "dsa", 1024, "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment"}, + {"rsa-1024", "rsa", 1024, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n"}, + {"rsa-2048", "rsa", 2048, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMZXh+1OBUwSH9D45wTaxErQIN9IoC9xl7MKJkqvTvv6O5RR9YW/IK9FbfjXgXsppYGhsCZo1hFOOsXHMnfOORqu/xMDx4yPuyvKpw4LePEcg4TDipaDFuxbWOqc/BUZRZcXu41QAWfDLrInwsltWZHSeG7hjhpacl4FrVv9V1pS6Oc5Q1NxxEzTzuNLS/8diZrTm/YAQQ/+B+mzWI3zEtF4miZjjAljWd1LTBPvU23d29DcBmmFahcZ441XZsTeAwGxG/Q6j8NgNXj9WxMeWwxXV2jeAX/EBSpZrCVlCQ1yJswT6xCp8TuBnTiGWYMBNTbOZvPC4e0WI2/yZW/s5F nocomment"}, + {"ecdsa-256", "ecdsa", 256, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFQacN3PrOll7PXmN5B/ZNVahiUIqI05nbBlZk1KXsO3d06ktAWqbNflv2vEmA38bTFTfJ2sbn2B5ksT52cDDbA= nocomment"}, + {"ecdsa-384", "ecdsa", 384, "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBINmioV+XRX1Fm9Qk2ehHXJ2tfVxW30ypUWZw670Zyq5GQfBAH6xjygRsJ5wWsHXBsGYgFUXIHvMKVAG1tpw7s6ax9oA+dJOJ7tj+vhn8joFqT+sg3LYHgZkHrfqryRasQ== nocomment"}, } - test("dsa-1024", "dsa", 1024, "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment") - test("rsa-1024", "rsa", 1024, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n") - test("rsa-2048", "rsa", 2048, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMZXh+1OBUwSH9D45wTaxErQIN9IoC9xl7MKJkqvTvv6O5RR9YW/IK9FbfjXgXsppYGhsCZo1hFOOsXHMnfOORqu/xMDx4yPuyvKpw4LePEcg4TDipaDFuxbWOqc/BUZRZcXu41QAWfDLrInwsltWZHSeG7hjhpacl4FrVv9V1pS6Oc5Q1NxxEzTzuNLS/8diZrTm/YAQQ/+B+mzWI3zEtF4miZjjAljWd1LTBPvU23d29DcBmmFahcZ441XZsTeAwGxG/Q6j8NgNXj9WxMeWwxXV2jeAX/EBSpZrCVlCQ1yJswT6xCp8TuBnTiGWYMBNTbOZvPC4e0WI2/yZW/s5F nocomment") - test("ecdsa-256", "ecdsa", 256, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFQacN3PrOll7PXmN5B/ZNVahiUIqI05nbBlZk1KXsO3d06ktAWqbNflv2vEmA38bTFTfJ2sbn2B5ksT52cDDbA= nocomment") - test("ecdsa-384", "ecdsa", 384, "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBINmioV+XRX1Fm9Qk2ehHXJ2tfVxW30ypUWZw670Zyq5GQfBAH6xjygRsJ5wWsHXBsGYgFUXIHvMKVAG1tpw7s6ax9oA+dJOJ7tj+vhn8joFqT+sg3LYHgZkHrfqryRasQ== nocomment") + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Run("Native", func(t *testing.T) { + keyTypeN, lengthN, err := SSHNativeParsePublicKey(tc.content) + assert.NoError(t, err) + assert.Equal(t, tc.keyType, keyTypeN) + assert.EqualValues(t, tc.length, lengthN) + }) + t.Run("SSHKeygen", func(t *testing.T) { + keyTypeK, lengthK, err := SSHKeyGenParsePublicKey(tc.content) + if err != nil { + // Some servers do not support ecdsa format. + if !strings.Contains(err.Error(), "line 1 too long:") { + assert.Fail(t, "%v", err) + } + } + assert.Equal(t, tc.keyType, keyTypeK) + assert.EqualValues(t, tc.length, lengthK) + }) + }) + } +} + +func Test_calcFingerprint(t *testing.T) { + testCases := []struct { + name string + fp string + content string + }{ + {"dsa-1024", "SHA256:fSIHQlpKMDsGPVAXI8BPYfRp+e2sfvSt1sMrPsFiXrc", "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment"}, + {"rsa-1024", "SHA256:vSnDkvRh/xM6kMxPidLgrUhq3mCN7CDaronCEm2joyQ", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n"}, + {"rsa-2048", "SHA256:ZHD//a1b9VuTq9XSunAeYjKeU1xDa2tBFZYrFr2Okkg", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMZXh+1OBUwSH9D45wTaxErQIN9IoC9xl7MKJkqvTvv6O5RR9YW/IK9FbfjXgXsppYGhsCZo1hFOOsXHMnfOORqu/xMDx4yPuyvKpw4LePEcg4TDipaDFuxbWOqc/BUZRZcXu41QAWfDLrInwsltWZHSeG7hjhpacl4FrVv9V1pS6Oc5Q1NxxEzTzuNLS/8diZrTm/YAQQ/+B+mzWI3zEtF4miZjjAljWd1LTBPvU23d29DcBmmFahcZ441XZsTeAwGxG/Q6j8NgNXj9WxMeWwxXV2jeAX/EBSpZrCVlCQ1yJswT6xCp8TuBnTiGWYMBNTbOZvPC4e0WI2/yZW/s5F nocomment"}, + {"ecdsa-256", "SHA256:Bqx/xgWqRKLtkZ0Lr4iZpgb+5lYsFpSwXwVZbPwuTRw", "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFQacN3PrOll7PXmN5B/ZNVahiUIqI05nbBlZk1KXsO3d06ktAWqbNflv2vEmA38bTFTfJ2sbn2B5ksT52cDDbA= nocomment"}, + {"ecdsa-384", "SHA256:4qfJOgJDtUd8BrEjyVNdI8IgjiZKouztVde43aDhe1E", "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBINmioV+XRX1Fm9Qk2ehHXJ2tfVxW30ypUWZw670Zyq5GQfBAH6xjygRsJ5wWsHXBsGYgFUXIHvMKVAG1tpw7s6ax9oA+dJOJ7tj+vhn8joFqT+sg3LYHgZkHrfqryRasQ== nocomment"}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Run("Native", func(t *testing.T) { + fpN, err := calcFingerprintNative(tc.content) + assert.NoError(t, err) + assert.Equal(t, tc.fp, fpN) + }) + t.Run("SSHKeygen", func(t *testing.T) { + fpK, err := calcFingerprintSSHKeygen(tc.content) + assert.NoError(t, err) + assert.Equal(t, tc.fp, fpK) + }) + }) + } } From d8168b356d3ddaf3c38815a46ab075bf5bbe93c6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 16 Jun 2019 20:39:52 +0800 Subject: [PATCH 120/220] Add missing description of label on API (#7159) * add missing description of label on API * fix comment head * fix swagger --- models/issue_label.go | 7 ++++--- modules/structs/issue_label.go | 14 +++++++++----- routers/api/v1/repo/label.go | 10 +++++++--- templates/swagger/v1_json.tmpl | 12 ++++++++++++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/models/issue_label.go b/models/issue_label.go index 363d4bb814..7af6060f87 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -76,9 +76,10 @@ type Label struct { // APIFormat converts a Label to the api.Label format func (label *Label) APIFormat() *api.Label { return &api.Label{ - ID: label.ID, - Name: label.Name, - Color: strings.TrimLeft(label.Color, "#"), + ID: label.ID, + Name: label.Name, + Color: strings.TrimLeft(label.Color, "#"), + Description: label.Description, } } diff --git a/modules/structs/issue_label.go b/modules/structs/issue_label.go index f0821fbaf5..0789624ab1 100644 --- a/modules/structs/issue_label.go +++ b/modules/structs/issue_label.go @@ -1,4 +1,5 @@ // Copyright 2016 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -10,8 +11,9 @@ type Label struct { ID int64 `json:"id"` Name string `json:"name"` // example: 00aabb - Color string `json:"color"` - URL string `json:"url"` + Color string `json:"color"` + Description string `json:"description"` + URL string `json:"url"` } // CreateLabelOption options for creating a label @@ -20,13 +22,15 @@ type CreateLabelOption struct { Name string `json:"name" binding:"Required"` // required:true // example: #00aabb - Color string `json:"color" binding:"Required;Size(7)"` + Color string `json:"color" binding:"Required;Size(7)"` + Description string `json:"description"` } // EditLabelOption options for editing a label type EditLabelOption struct { - Name *string `json:"name"` - Color *string `json:"color"` + Name *string `json:"name"` + Color *string `json:"color"` + Description *string `json:"description"` } // IssueLabelsOption a collection of labels diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go index 1cd8890ca9..98ccee37bd 100644 --- a/routers/api/v1/repo/label.go +++ b/routers/api/v1/repo/label.go @@ -125,9 +125,10 @@ func CreateLabel(ctx *context.APIContext, form api.CreateLabelOption) { // "201": // "$ref": "#/responses/Label" label := &models.Label{ - Name: form.Name, - Color: form.Color, - RepoID: ctx.Repo.Repository.ID, + Name: form.Name, + Color: form.Color, + RepoID: ctx.Repo.Repository.ID, + Description: form.Description, } if err := models.NewLabel(label); err != nil { ctx.Error(500, "NewLabel", err) @@ -185,6 +186,9 @@ func EditLabel(ctx *context.APIContext, form api.EditLabelOption) { if form.Color != nil { label.Color = *form.Color } + if form.Description != nil { + label.Description = *form.Description + } if err := models.UpdateLabel(label); err != nil { ctx.ServerError("UpdateLabel", err) return diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 6f9585fae2..6c2708dd96 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -7245,6 +7245,10 @@ "x-go-name": "Color", "example": "#00aabb" }, + "description": { + "type": "string", + "x-go-name": "Description" + }, "name": { "type": "string", "x-go-name": "Name" @@ -7775,6 +7779,10 @@ "type": "string", "x-go-name": "Color" }, + "description": { + "type": "string", + "x-go-name": "Description" + }, "name": { "type": "string", "x-go-name": "Name" @@ -8663,6 +8671,10 @@ "x-go-name": "Color", "example": "00aabb" }, + "description": { + "type": "string", + "x-go-name": "Description" + }, "id": { "type": "integer", "format": "int64", From 1e8a6164262bafd6878269b153c43686977c4603 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 17 Jun 2019 02:24:49 +0800 Subject: [PATCH 121/220] show lfs config on admin panel (#7220) --- options/locale/locale_en-US.ini | 5 +++++ routers/admin/admin.go | 1 + templates/admin/config.tmpl | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 71c76fd9b6..97e4e3f91c 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1722,6 +1722,11 @@ config.ssh_keygen_path = Keygen ('ssh-keygen') Path config.ssh_minimum_key_size_check = Minimum Key Size Check config.ssh_minimum_key_sizes = Minimum Key Sizes +config.lfs_config = LFS Configuration +config.lfs_enabled = Enabled +config.lfs_content_path = LFS Content Path +config.lfs_http_auth_expiry = LFS HTTP Auth Expiry + config.db_config = Database Configuration config.db_type = Type config.db_host = Host diff --git a/routers/admin/admin.go b/routers/admin/admin.go index b4eac2c677..2836b7ddc7 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -225,6 +225,7 @@ func Config(ctx *context.Context) { ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail ctx.Data["SSH"] = setting.SSH + ctx.Data["LFS"] = setting.LFS ctx.Data["Service"] = setting.Service ctx.Data["DbCfg"] = models.DbCfg diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 7a81eb2668..b8bf1ec028 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -96,6 +96,22 @@ +

    + {{.i18n.Tr "admin.config.lfs_config"}} +

    +
    +
    +
    {{.i18n.Tr "admin.config.lfs_enabled"}}
    +
    + {{if .LFS.StartServer}} +
    {{.i18n.Tr "admin.config.lfs_content_path"}}
    +
    {{.LFS.ContentPath}}
    +
    {{.i18n.Tr "admin.config.lfs_http_auth_expiry"}}
    +
    {{.LFS.HTTPAuthExpiry}}
    + {{end}} +
    +
    +

    {{.i18n.Tr "admin.config.db_config"}}

    From eaa3a1db4ee0400a30c9eaabe5080b234f9f4053 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 17 Jun 2019 18:33:55 +0100 Subject: [PATCH 122/220] Use certmanager provided TLSConfig for LetsEncrypt (#7229) --- cmd/web.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cmd/web.go b/cmd/web.go index e211674b4d..d8bcba76d1 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -5,7 +5,6 @@ package cmd import ( - "crypto/tls" "fmt" "net" "net/http" @@ -82,11 +81,9 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) } }() server := &http.Server{ - Addr: listenAddr, - Handler: m, - TLSConfig: &tls.Config{ - GetCertificate: certManager.GetCertificate, - }, + Addr: listenAddr, + Handler: m, + TLSConfig: certManager.TLSConfig(), } return server.ListenAndServeTLS("", "") } From a200ca15519d6f23a0b64c062f23000c347ce7b6 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 17 Jun 2019 17:36:28 +0000 Subject: [PATCH 123/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_bg-BG.ini | 1 + options/locale/locale_cs-CZ.ini | 1 + options/locale/locale_de-DE.ini | 5 +++++ options/locale/locale_es-ES.ini | 1 + options/locale/locale_fa-IR.ini | 1 + options/locale/locale_fi-FI.ini | 1 + options/locale/locale_fr-FR.ini | 1 + options/locale/locale_hu-HU.ini | 1 + options/locale/locale_id-ID.ini | 1 + options/locale/locale_it-IT.ini | 1 + options/locale/locale_ja-JP.ini | 5 +++++ options/locale/locale_ko-KR.ini | 1 + options/locale/locale_lt-LT.ini | 1 + options/locale/locale_lv-LV.ini | 1 + options/locale/locale_nb-NO.ini | 1 + options/locale/locale_nl-NL.ini | 1 + options/locale/locale_nn-NO.ini | 1 + options/locale/locale_no-NO.ini | 1 + options/locale/locale_pl-PL.ini | 1 + options/locale/locale_pt-BR.ini | 5 +++++ options/locale/locale_ru-RU.ini | 1 + options/locale/locale_sr-SP.ini | 1 + options/locale/locale_sv-SE.ini | 1 + options/locale/locale_tr-TR.ini | 1 + options/locale/locale_uk-UA.ini | 1 + options/locale/locale_vi-VN.ini | 1 + options/locale/locale_zh-CN.ini | 1 + options/locale/locale_zh-HK.ini | 1 + options/locale/locale_zh-TW.ini | 1 + 29 files changed, 41 insertions(+) diff --git a/options/locale/locale_bg-BG.ini b/options/locale/locale_bg-BG.ini index 2cfae41880..a49eadbdde 100644 --- a/options/locale/locale_bg-BG.ini +++ b/options/locale/locale_bg-BG.ini @@ -664,6 +664,7 @@ config.ssh_keygen_path=Път до генератор ('ssh-keygen') config.ssh_minimum_key_size_check=Проверка за минимален размер на ключове config.ssh_minimum_key_sizes=Минимален размер на ключове + config.db_config=Настройки на базата данни config.db_type=Тип config.db_host=Сървър diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 13bb4f9c05..6df290baec 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -1665,6 +1665,7 @@ config.ssh_keygen_path=Cesta ke generátoru klíčů ('ssh-keygen') config.ssh_minimum_key_size_check=Kontrola minimální velikosti klíčů config.ssh_minimum_key_sizes=Minimální velikost klíčů + config.db_config=Nastavení databáze config.db_type=Typ config.db_host=Server diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 7176b23f56..adafc609ca 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -487,6 +487,7 @@ manage_oauth2_applications=OAuth2 Anwendungen verwalten edit_oauth2_application=OAuth2 Anwendung bearbeiten oauth2_applications_desc=OAuth2-Anwendungen ermöglichen die sichere Authentifizierung von Benutzern dieser Gitea-Instanz für deine Drittanwendung. remove_oauth2_application=OAuth2-Anwendung entfernen +remove_oauth2_application_desc=Das Entfernen einer OAuth2-Anwendung wird den Zugriff auf alle signierten Zugriffstokens widerrufen. Möchtest du fortfahren? remove_oauth2_application_success=Die Anwendung wurde gelöscht. create_oauth2_application=Neue OAuth2 Anwendung erstellen create_oauth2_application_button=Anwendung erstellen @@ -1720,6 +1721,10 @@ config.ssh_keygen_path=Keygen-Pfad („ssh-keygen“) config.ssh_minimum_key_size_check=Prüfung der Mindestschlüssellänge config.ssh_minimum_key_sizes=Mindestschlüssellängen +config.lfs_config=LFS-Konfiguration +config.lfs_enabled=Aktiviert +config.lfs_content_path=LFS Content-Pfad + config.db_config=Datenbankkonfiguration config.db_type=Typ config.db_host=Host diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index d620ebaddd..56c2791ef0 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -812,6 +812,7 @@ config.ssh_keygen_path=Ruta del generador de claves ('ssh-keygen') config.ssh_minimum_key_size_check=Tamaño mínimo de la clave de verificación config.ssh_minimum_key_sizes=Tamaños de clave mínimos + config.db_config=Configuración de la Base de Datos config.db_type=Tipo config.db_name=Nombre diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 239dc2a9a6..f0602dbf67 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -198,6 +198,7 @@ smtp_from=ارسال ایمیل به عنوان + [action] diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 1537d49608..25098c4a67 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -724,6 +724,7 @@ config.ssh_keygen_path=Keygen ('ssh-keygen') polku config.ssh_minimum_key_size_check=Avaimen vähimmäiskoko tarkistus config.ssh_minimum_key_sizes=Avaimen vähimmäiskoot + config.db_config=Tietokannan asetukset config.db_type=Tyyppi config.db_host=Isäntä diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 0b077d931d..67fdaa1424 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -1716,6 +1716,7 @@ config.ssh_keygen_path=Chemin vers le générateur de clefs ("ssh-keygen") config.ssh_minimum_key_size_check=Vérification de la longueur de clé minimale config.ssh_minimum_key_sizes=Tailles de clé minimales + config.db_config=Configuration de la base de données config.db_type=Type config.db_host=Hôte diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 3528bbfde7..cfb1fcfef6 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -840,6 +840,7 @@ config.ssh_keygen_path=Kulcsgeneráló ('ssh-keygen') elérési útja config.ssh_minimum_key_size_check=Kulcsok minimum méretének ellenőrzése config.ssh_minimum_key_sizes=Minimális kulcsok méretek + config.db_config=Adatbázis Konfiguráció config.db_type=Típus config.db_host=Kiszolgáló diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 381d838834..786f0a079e 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -887,6 +887,7 @@ config.ssh_keygen_path=Path Keygen ('ssh-keygen') config.ssh_minimum_key_size_check=Periksa ukuran kunci minimum config.ssh_minimum_key_sizes=Ukuran kunci minimum + config.db_config=Konfigurasi basis data config.db_type=Tipe config.db_host=Host diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index a5e74f9b58..bb4fcc0e38 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -1420,6 +1420,7 @@ config.ssh_keygen_path=Percorso Keygen ('ssh-keygen') config.ssh_minimum_key_size_check=Verifica delle dimensioni minime della chiave config.ssh_minimum_key_sizes=Dimensioni minime della chiave + config.db_config=Configurazione Database config.db_type=Tipo config.db_host=Host diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index c5028af841..131a59da5e 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1721,6 +1721,11 @@ config.ssh_keygen_path=キージェネレータ('ssh-keygen')パス config.ssh_minimum_key_size_check=最小キー長のチェック config.ssh_minimum_key_sizes=最小キー長 +config.lfs_config=LFS設定 +config.lfs_enabled=有効 +config.lfs_content_path=LFS保存先パス +config.lfs_http_auth_expiry=LFSのHTTP認証有効時間 + config.db_config=データベース設定 config.db_type=タイプ config.db_host=ホスト diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index 93bf790c74..ecbee9efe0 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -678,6 +678,7 @@ config.ssh_keygen_path=키 생성 ('ssh-keygen') 경로 config.ssh_minimum_key_size_check=최소 키 사이즈 검사 config.ssh_minimum_key_sizes=최소 키 사이즈 + config.db_config=데이터베이스 설정 config.db_type=유형 config.db_host=호스트 diff --git a/options/locale/locale_lt-LT.ini b/options/locale/locale_lt-LT.ini index cbb4a18bdf..5fd9e31c5d 100644 --- a/options/locale/locale_lt-LT.ini +++ b/options/locale/locale_lt-LT.ini @@ -266,6 +266,7 @@ issues.save=Saugoti + [action] diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 0aa31361e5..01a8bd070c 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -1636,6 +1636,7 @@ config.ssh_keygen_path=Keygen ('ssh-keygen') ceļš config.ssh_minimum_key_size_check=Minimālā atslēgas lieluma pārbaude config.ssh_minimum_key_sizes=Minimālais atslēgas lielums + config.db_config=Datu bāzes konfigurācija config.db_type=Veids config.db_host=Resursdators diff --git a/options/locale/locale_nb-NO.ini b/options/locale/locale_nb-NO.ini index 5e316bf786..bfb274bf60 100644 --- a/options/locale/locale_nb-NO.ini +++ b/options/locale/locale_nb-NO.ini @@ -203,6 +203,7 @@ forgot_password=Glemt passord? + [action] diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 7f5fd504ae..c97c72cbef 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -1179,6 +1179,7 @@ config.ssh_keygen_path=Pad van keygen ('ssh-keygen') config.ssh_minimum_key_size_check=Controleer minimale key-lengte config.ssh_minimum_key_sizes=Minimale key-lengtes + config.db_config=Databaseconfiguratie config.db_type=Type config.db_host=Host diff --git a/options/locale/locale_nn-NO.ini b/options/locale/locale_nn-NO.ini index dbb0ec77bd..8efc2a4d50 100644 --- a/options/locale/locale_nn-NO.ini +++ b/options/locale/locale_nn-NO.ini @@ -99,6 +99,7 @@ + [action] diff --git a/options/locale/locale_no-NO.ini b/options/locale/locale_no-NO.ini index d5701b2caf..45624fa3be 100644 --- a/options/locale/locale_no-NO.ini +++ b/options/locale/locale_no-NO.ini @@ -137,6 +137,7 @@ smtp_host=SMTP-vert + [action] diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 75fba79d02..94bf3eaa7c 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -1165,6 +1165,7 @@ config.ssh_keygen_path=Ścieżka do generatora ('ssh-keygen') config.ssh_minimum_key_size_check=Sprawdzanie minimalnej długości klucza config.ssh_minimum_key_sizes=Minimalne rozmiary kluczy + config.db_config=Konfiguracja bazy danych config.db_type=Typ config.db_host=Serwer diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 435b51552e..dd46bcffcb 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1721,6 +1721,11 @@ config.ssh_keygen_path=Caminho do keygen ('ssh-keygen') config.ssh_minimum_key_size_check=Verificar tamanho mínimo da chave config.ssh_minimum_key_sizes=Tamanhos mínimos da chave +config.lfs_config=Configuração de LFS +config.lfs_enabled=Habilitado +config.lfs_content_path=Caminho do conteúdo LFS +config.lfs_http_auth_expiry=Expiração da autenticação HTTP LFS + config.db_config=Configuração do banco de dados config.db_type=Tipo config.db_host=Servidor diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index b544b78d30..4c84dd1201 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -1655,6 +1655,7 @@ config.ssh_keygen_path=Путь к генератору ключей ('ssh-keyge config.ssh_minimum_key_size_check=Минимальный размер ключа проверки config.ssh_minimum_key_sizes=Минимальные размеры ключа + config.db_config=Конфигурация базы данных config.db_type=Тип config.db_host=Сервер diff --git a/options/locale/locale_sr-SP.ini b/options/locale/locale_sr-SP.ini index a0af2d5872..18ea2f0a45 100644 --- a/options/locale/locale_sr-SP.ini +++ b/options/locale/locale_sr-SP.ini @@ -595,6 +595,7 @@ config.ssh_keygen_path=Пут до генератор кључева ('ssh-keyge config.ssh_minimum_key_size_check=Минимална величина провера кључа config.ssh_minimum_key_sizes=Минимална величина кључева + config.db_config=Конфигурација базе података config.db_type=Тип config.db_host=Хост diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index d50e8b1c3a..001bcfbaac 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -1456,6 +1456,7 @@ config.ssh_keygen_path=Sökväg för nyckelgenerator ('ssh-keygen') config.ssh_minimum_key_size_check=Kontroll av minsta tillåtna nyckelstorlek config.ssh_minimum_key_sizes=Minsta tillåtna nyckelstorlek + config.db_config=Databaskonfiguration config.db_type=Typ config.db_host=Värd diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index f500f71c3d..b8e8427287 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -789,6 +789,7 @@ config.ssh_keygen_path=Keygen ('ssh-keygen') Yolu config.ssh_minimum_key_size_check=Minimum Anahtar Uzunluğu Kontrolü config.ssh_minimum_key_sizes=Minimum Anahtar Uzunlukları + config.db_config=Veritabanı Yapılandırması config.db_type=Türü config.db_host=Sunucu diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 6c5f45c5c4..5368d13a96 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -1522,6 +1522,7 @@ config.ssh_keygen_path=Шлях до генератора ключів ('ssh-key config.ssh_minimum_key_size_check=Мінімальний розмір ключа перевірки config.ssh_minimum_key_sizes=Мінімальні розміри ключів + config.db_config=Конфігурація бази даних config.db_type=Тип config.db_host=Хост diff --git a/options/locale/locale_vi-VN.ini b/options/locale/locale_vi-VN.ini index dbb0ec77bd..8efc2a4d50 100644 --- a/options/locale/locale_vi-VN.ini +++ b/options/locale/locale_vi-VN.ini @@ -99,6 +99,7 @@ + [action] diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 6b495bee87..0b6b1f4e44 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1721,6 +1721,7 @@ config.ssh_keygen_path=密钥生成器('ssh-keygen')路径 config.ssh_minimum_key_size_check=密钥最小长度检查 config.ssh_minimum_key_sizes=密钥最小长度限制 + config.db_config=数据库配置 config.db_type=类型 config.db_host=主机 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 6d8010ebae..8f3f392dc3 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -726,6 +726,7 @@ config.ssh_keygen_path=金鑰產生 (' ssh-keygen ') 路徑 config.ssh_minimum_key_size_check=金鑰最小大小檢查 config.ssh_minimum_key_sizes=金鑰最小大小 + config.db_config=資料庫設定 config.db_type=資料庫類型 config.db_host=主機地址 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 91e42a3857..42719c88c8 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -1240,6 +1240,7 @@ config.ssh_keygen_path=金鑰產生 (' ssh-keygen ') 路徑 config.ssh_minimum_key_size_check=金鑰最小大小檢查 config.ssh_minimum_key_sizes=金鑰最小大小 + config.db_config=資料庫設定 config.db_type=資料庫類型 config.db_host=主機地址 From a618df8d8474efb9148d29c4ce6cf8ec14cfca7a Mon Sep 17 00:00:00 2001 From: ngourdon Date: Mon, 17 Jun 2019 20:32:20 +0200 Subject: [PATCH 124/220] Add CLI commands to manage LDAP authentication source (#6681) * add CLI commands to manage LDAP authentication source * delete Gogs copyright * remove unused return value of func parseLoginSource * fix comment Co-Authored-By: ngourdon <31291059+ngourdon@users.noreply.github.com> * remove config flag already present in global flags * remove config flag from ldap commands in docs * remove config flag handling --- cmd/admin.go | 6 +- cmd/admin_auth_ldap.go | 359 +++++ cmd/admin_auth_ldap_test.go | 1350 ++++++++++++++++++ docs/content/doc/usage/command-line.en-us.md | 88 ++ 4 files changed, 1802 insertions(+), 1 deletion(-) create mode 100644 cmd/admin_auth_ldap.go create mode 100644 cmd/admin_auth_ldap_test.go diff --git a/cmd/admin.go b/cmd/admin.go index 6234ab828d..4c4d6f9b66 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -131,6 +131,10 @@ var ( Subcommands: []cli.Command{ microcmdAuthAddOauth, microcmdAuthUpdateOauth, + cmdAuthAddLdapBindDn, + cmdAuthUpdateLdapBindDn, + cmdAuthAddLdapSimpleAuth, + cmdAuthUpdateLdapSimpleAuth, microcmdAuthList, microcmdAuthDelete, }, @@ -144,7 +148,7 @@ var ( idFlag = cli.Int64Flag{ Name: "id", - Usage: "ID of OAuth authentication source", + Usage: "ID of authentication source", } microcmdAuthDelete = cli.Command{ diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go new file mode 100644 index 0000000000..cce3aa894f --- /dev/null +++ b/cmd/admin_auth_ldap.go @@ -0,0 +1,359 @@ +// Copyright 2019 The Gitea 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 cmd + +import ( + "fmt" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth/ldap" + + "github.com/urfave/cli" +) + +type ( + authService struct { + initDB func() error + createLoginSource func(loginSource *models.LoginSource) error + updateLoginSource func(loginSource *models.LoginSource) error + getLoginSourceByID func(id int64) (*models.LoginSource, error) + } +) + +var ( + commonLdapCLIFlags = []cli.Flag{ + cli.StringFlag{ + Name: "name", + Usage: "Authentication name.", + }, + cli.BoolFlag{ + Name: "not-active", + Usage: "Deactivate the authentication source.", + }, + cli.StringFlag{ + Name: "security-protocol", + Usage: "Security protocol name.", + }, + cli.BoolFlag{ + Name: "skip-tls-verify", + Usage: "Disable TLS verification.", + }, + cli.StringFlag{ + Name: "host", + Usage: "The address where the LDAP server can be reached.", + }, + cli.IntFlag{ + Name: "port", + Usage: "The port to use when connecting to the LDAP server.", + }, + cli.StringFlag{ + Name: "user-search-base", + Usage: "The LDAP base at which user accounts will be searched for.", + }, + cli.StringFlag{ + Name: "user-filter", + Usage: "An LDAP filter declaring how to find the user record that is attempting to authenticate.", + }, + cli.StringFlag{ + Name: "admin-filter", + Usage: "An LDAP filter specifying if a user should be given administrator privileges.", + }, + cli.StringFlag{ + Name: "username-attribute", + Usage: "The attribute of the user’s LDAP record containing the user name.", + }, + cli.StringFlag{ + Name: "firstname-attribute", + Usage: "The attribute of the user’s LDAP record containing the user’s first name.", + }, + cli.StringFlag{ + Name: "surname-attribute", + Usage: "The attribute of the user’s LDAP record containing the user’s surname.", + }, + cli.StringFlag{ + Name: "email-attribute", + Usage: "The attribute of the user’s LDAP record containing the user’s email address.", + }, + cli.StringFlag{ + Name: "public-ssh-key-attribute", + Usage: "The attribute of the user’s LDAP record containing the user’s public ssh key.", + }, + } + + ldapBindDnCLIFlags = append(commonLdapCLIFlags, + cli.StringFlag{ + Name: "bind-dn", + Usage: "The DN to bind to the LDAP server with when searching for the user.", + }, + cli.StringFlag{ + Name: "bind-password", + Usage: "The password for the Bind DN, if any.", + }, + cli.BoolFlag{ + Name: "attributes-in-bind", + Usage: "Fetch attributes in bind DN context.", + }, + cli.BoolFlag{ + Name: "synchronize-users", + Usage: "Enable user synchronization.", + }, + cli.UintFlag{ + Name: "page-size", + Usage: "Search page size.", + }) + + ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags, + cli.StringFlag{ + Name: "user-dn", + Usage: "The user’s DN.", + }) + + cmdAuthAddLdapBindDn = cli.Command{ + Name: "add-ldap", + Usage: "Add new LDAP (via Bind DN) authentication source", + Action: func(c *cli.Context) error { + return newAuthService().addLdapBindDn(c) + }, + Flags: ldapBindDnCLIFlags, + } + + cmdAuthUpdateLdapBindDn = cli.Command{ + Name: "update-ldap", + Usage: "Update existing LDAP (via Bind DN) authentication source", + Action: func(c *cli.Context) error { + return newAuthService().updateLdapBindDn(c) + }, + Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...), + } + + cmdAuthAddLdapSimpleAuth = cli.Command{ + Name: "add-ldap-simple", + Usage: "Add new LDAP (simple auth) authentication source", + Action: func(c *cli.Context) error { + return newAuthService().addLdapSimpleAuth(c) + }, + Flags: ldapSimpleAuthCLIFlags, + } + + cmdAuthUpdateLdapSimpleAuth = cli.Command{ + Name: "update-ldap-simple", + Usage: "Update existing LDAP (simple auth) authentication source", + Action: func(c *cli.Context) error { + return newAuthService().updateLdapSimpleAuth(c) + }, + Flags: append([]cli.Flag{idFlag}, ldapSimpleAuthCLIFlags...), + } +) + +// newAuthService creates a service with default functions. +func newAuthService() *authService { + return &authService{ + initDB: initDB, + createLoginSource: models.CreateLoginSource, + updateLoginSource: models.UpdateSource, + getLoginSourceByID: models.GetLoginSourceByID, + } +} + +// parseLoginSource assigns values on loginSource according to command line flags. +func parseLoginSource(c *cli.Context, loginSource *models.LoginSource) { + if c.IsSet("name") { + loginSource.Name = c.String("name") + } + if c.IsSet("not-active") { + loginSource.IsActived = !c.Bool("not-active") + } + if c.IsSet("synchronize-users") { + loginSource.IsSyncEnabled = c.Bool("synchronize-users") + } +} + +// parseLdapConfig assigns values on config according to command line flags. +func parseLdapConfig(c *cli.Context, config *models.LDAPConfig) error { + if c.IsSet("name") { + config.Source.Name = c.String("name") + } + if c.IsSet("host") { + config.Source.Host = c.String("host") + } + if c.IsSet("port") { + config.Source.Port = c.Int("port") + } + if c.IsSet("security-protocol") { + p, ok := findLdapSecurityProtocolByName(c.String("security-protocol")) + if !ok { + return fmt.Errorf("Unknown security protocol name: %s", c.String("security-protocol")) + } + config.Source.SecurityProtocol = p + } + if c.IsSet("skip-tls-verify") { + config.Source.SkipVerify = c.Bool("skip-tls-verify") + } + if c.IsSet("bind-dn") { + config.Source.BindDN = c.String("bind-dn") + } + if c.IsSet("user-dn") { + config.Source.UserDN = c.String("user-dn") + } + if c.IsSet("bind-password") { + config.Source.BindPassword = c.String("bind-password") + } + if c.IsSet("user-search-base") { + config.Source.UserBase = c.String("user-search-base") + } + if c.IsSet("username-attribute") { + config.Source.AttributeUsername = c.String("username-attribute") + } + if c.IsSet("firstname-attribute") { + config.Source.AttributeName = c.String("firstname-attribute") + } + if c.IsSet("surname-attribute") { + config.Source.AttributeSurname = c.String("surname-attribute") + } + if c.IsSet("email-attribute") { + config.Source.AttributeMail = c.String("email-attribute") + } + if c.IsSet("attributes-in-bind") { + config.Source.AttributesInBind = c.Bool("attributes-in-bind") + } + if c.IsSet("public-ssh-key-attribute") { + config.Source.AttributeSSHPublicKey = c.String("public-ssh-key-attribute") + } + if c.IsSet("page-size") { + config.Source.SearchPageSize = uint32(c.Uint("page-size")) + } + if c.IsSet("user-filter") { + config.Source.Filter = c.String("user-filter") + } + if c.IsSet("admin-filter") { + config.Source.AdminFilter = c.String("admin-filter") + } + return nil +} + +// findLdapSecurityProtocolByName finds security protocol by its name ignoring case. +// It returns the value of the security protocol and if it was found. +func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) { + for i, n := range models.SecurityProtocolNames { + if strings.EqualFold(name, n) { + return i, true + } + } + return 0, false +} + +// getLoginSource gets the login source by its id defined in the command line flags. +// It returns an error if the id is not set, does not match any source or if the source is not of expected type. +func (a *authService) getLoginSource(c *cli.Context, loginType models.LoginType) (*models.LoginSource, error) { + if err := argsSet(c, "id"); err != nil { + return nil, err + } + + loginSource, err := a.getLoginSourceByID(c.Int64("id")) + if err != nil { + return nil, err + } + + if loginSource.Type != loginType { + return nil, fmt.Errorf("Invalid authentication type. expected: %s, actual: %s", models.LoginNames[loginType], models.LoginNames[loginSource.Type]) + } + + return loginSource, nil +} + +// addLdapBindDn adds a new LDAP via Bind DN authentication source. +func (a *authService) addLdapBindDn(c *cli.Context) error { + if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil { + return err + } + + if err := a.initDB(); err != nil { + return err + } + + loginSource := &models.LoginSource{ + Type: models.LoginLDAP, + IsActived: true, // active by default + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Enabled: true, // always true + }, + }, + } + + parseLoginSource(c, loginSource) + if err := parseLdapConfig(c, loginSource.LDAP()); err != nil { + return err + } + + return a.createLoginSource(loginSource) +} + +// updateLdapBindDn updates a new LDAP via Bind DN authentication source. +func (a *authService) updateLdapBindDn(c *cli.Context) error { + if err := a.initDB(); err != nil { + return err + } + + loginSource, err := a.getLoginSource(c, models.LoginLDAP) + if err != nil { + return err + } + + parseLoginSource(c, loginSource) + if err := parseLdapConfig(c, loginSource.LDAP()); err != nil { + return err + } + + return a.updateLoginSource(loginSource) +} + +// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source. +func (a *authService) addLdapSimpleAuth(c *cli.Context) error { + if err := argsSet(c, "name", "security-protocol", "host", "port", "user-dn", "user-filter", "email-attribute"); err != nil { + return err + } + + if err := a.initDB(); err != nil { + return err + } + + loginSource := &models.LoginSource{ + Type: models.LoginDLDAP, + IsActived: true, // active by default + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Enabled: true, // always true + }, + }, + } + + parseLoginSource(c, loginSource) + if err := parseLdapConfig(c, loginSource.LDAP()); err != nil { + return err + } + + return a.createLoginSource(loginSource) +} + +// updateLdapBindDn updates a new LDAP (simple auth) authentication source. +func (a *authService) updateLdapSimpleAuth(c *cli.Context) error { + if err := a.initDB(); err != nil { + return err + } + + loginSource, err := a.getLoginSource(c, models.LoginDLDAP) + if err != nil { + return err + } + + parseLoginSource(c, loginSource) + if err := parseLdapConfig(c, loginSource.LDAP()); err != nil { + return err + } + + return a.updateLoginSource(loginSource) +} diff --git a/cmd/admin_auth_ldap_test.go b/cmd/admin_auth_ldap_test.go new file mode 100644 index 0000000000..4af9f167c3 --- /dev/null +++ b/cmd/admin_auth_ldap_test.go @@ -0,0 +1,1350 @@ +// Copyright 2019 The Gitea 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 cmd + +import ( + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth/ldap" + + "github.com/stretchr/testify/assert" + "github.com/urfave/cli" +) + +func TestAddLdapBindDn(t *testing.T) { + // Mock cli functions to do not exit on error + var osExiter = cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} + + // Test cases + var cases = []struct { + args []string + loginSource *models.LoginSource + errMsg string + }{ + // case 0 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source full", + "--not-active", + "--security-protocol", "ldaps", + "--skip-tls-verify", + "--host", "ldap-bind-server full", + "--port", "9876", + "--user-search-base", "ou=Users,dc=full-domain-bind,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)", + "--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)", + "--username-attribute", "uid-bind full", + "--firstname-attribute", "givenName-bind full", + "--surname-attribute", "sn-bind full", + "--email-attribute", "mail-bind full", + "--public-ssh-key-attribute", "publickey-bind full", + "--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org", + "--bind-password", "secret-bind-full", + "--attributes-in-bind", + "--synchronize-users", + "--page-size", "99", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Name: "ldap (via Bind DN) source full", + IsActived: false, + IsSyncEnabled: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (via Bind DN) source full", + Host: "ldap-bind-server full", + Port: 9876, + SecurityProtocol: ldap.SecurityProtocol(1), + SkipVerify: true, + BindDN: "cn=readonly,dc=full-domain-bind,dc=org", + BindPassword: "secret-bind-full", + UserBase: "ou=Users,dc=full-domain-bind,dc=org", + AttributeUsername: "uid-bind full", + AttributeName: "givenName-bind full", + AttributeSurname: "sn-bind full", + AttributeMail: "mail-bind full", + AttributesInBind: true, + AttributeSSHPublicKey: "publickey-bind full", + SearchPageSize: 99, + Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)", + AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)", + Enabled: true, + }, + }, + }, + }, + // case 1 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source min", + "--security-protocol", "unencrypted", + "--host", "ldap-bind-server min", + "--port", "1234", + "--user-search-base", "ou=Users,dc=min-domain-bind,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=min-domain-bind,dc=org)", + "--email-attribute", "mail-bind min", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Name: "ldap (via Bind DN) source min", + IsActived: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (via Bind DN) source min", + Host: "ldap-bind-server min", + Port: 1234, + SecurityProtocol: ldap.SecurityProtocol(0), + UserBase: "ou=Users,dc=min-domain-bind,dc=org", + AttributeMail: "mail-bind min", + Filter: "(memberOf=cn=user-group,ou=example,dc=min-domain-bind,dc=org)", + Enabled: true, + }, + }, + }, + }, + // case 2 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source", + "--security-protocol", "zzzzz", + "--host", "ldap-server", + "--port", "1234", + "--user-search-base", "ou=Users,dc=domain,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + "--email-attribute", "mail", + }, + errMsg: "Unknown security protocol name: zzzzz", + }, + // case 3 + { + args: []string{ + "ldap-test", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--port", "1234", + "--user-search-base", "ou=Users,dc=domain,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + "--email-attribute", "mail", + }, + errMsg: "name is not set", + }, + // case 4 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source", + "--host", "ldap-server", + "--port", "1234", + "--user-search-base", "ou=Users,dc=domain,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + "--email-attribute", "mail", + }, + errMsg: "security-protocol is not set", + }, + // case 5 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source", + "--security-protocol", "unencrypted", + "--port", "1234", + "--user-search-base", "ou=Users,dc=domain,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + "--email-attribute", "mail", + }, + errMsg: "host is not set", + }, + // case 6 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--user-search-base", "ou=Users,dc=domain,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + "--email-attribute", "mail", + }, + errMsg: "port is not set", + }, + // case 7 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--port", "1234", + "--user-search-base", "ou=Users,dc=domain,dc=org", + "--email-attribute", "mail", + }, + errMsg: "user-filter is not set", + }, + // case 8 + { + args: []string{ + "ldap-test", + "--name", "ldap (via Bind DN) source", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--port", "1234", + "--user-search-base", "ou=Users,dc=domain,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + }, + errMsg: "email-attribute is not set", + }, + } + + for n, c := range cases { + // Mock functions. + var createdLoginSource *models.LoginSource + service := &authService{ + initDB: func() error { + return nil + }, + createLoginSource: func(loginSource *models.LoginSource) error { + createdLoginSource = loginSource + return nil + }, + updateLoginSource: func(loginSource *models.LoginSource) error { + assert.FailNow(t, "case %d: should not call updateLoginSource", n) + return nil + }, + getLoginSourceByID: func(id int64) (*models.LoginSource, error) { + assert.FailNow(t, "case %d: should not call getLoginSourceByID", n) + return nil, nil + }, + } + + // Create a copy of command to test + app := cli.NewApp() + app.Flags = cmdAuthAddLdapBindDn.Flags + app.Action = service.addLdapBindDn + + // Run it + err := app.Run(c.args) + if c.errMsg != "" { + assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) + } else { + assert.NoError(t, err, "case %d: should have no errors", n) + assert.Equal(t, c.loginSource, createdLoginSource, "case %d: wrong loginSource", n) + } + } +} + +func TestAddLdapSimpleAuth(t *testing.T) { + // Mock cli functions to do not exit on error + var osExiter = cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} + + // Test cases + var cases = []struct { + args []string + loginSource *models.LoginSource + errMsg string + }{ + // case 0 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source full", + "--not-active", + "--security-protocol", "starttls", + "--skip-tls-verify", + "--host", "ldap-simple-server full", + "--port", "987", + "--user-search-base", "ou=Users,dc=full-domain-simple,dc=org", + "--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))", + "--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)", + "--username-attribute", "uid-simple full", + "--firstname-attribute", "givenName-simple full", + "--surname-attribute", "sn-simple full", + "--email-attribute", "mail-simple full", + "--public-ssh-key-attribute", "publickey-simple full", + "--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Name: "ldap (simple auth) source full", + IsActived: false, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (simple auth) source full", + Host: "ldap-simple-server full", + Port: 987, + SecurityProtocol: ldap.SecurityProtocol(2), + SkipVerify: true, + UserDN: "cn=%s,ou=Users,dc=full-domain-simple,dc=org", + UserBase: "ou=Users,dc=full-domain-simple,dc=org", + AttributeUsername: "uid-simple full", + AttributeName: "givenName-simple full", + AttributeSurname: "sn-simple full", + AttributeMail: "mail-simple full", + AttributeSSHPublicKey: "publickey-simple full", + Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))", + AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)", + Enabled: true, + }, + }, + }, + }, + // case 1 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source min", + "--security-protocol", "unencrypted", + "--host", "ldap-simple-server min", + "--port", "123", + "--user-filter", "(&(objectClass=posixAccount)(min-simple-cn=%s))", + "--email-attribute", "mail-simple min", + "--user-dn", "cn=%s,ou=Users,dc=min-domain-simple,dc=org", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Name: "ldap (simple auth) source min", + IsActived: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (simple auth) source min", + Host: "ldap-simple-server min", + Port: 123, + SecurityProtocol: ldap.SecurityProtocol(0), + UserDN: "cn=%s,ou=Users,dc=min-domain-simple,dc=org", + AttributeMail: "mail-simple min", + Filter: "(&(objectClass=posixAccount)(min-simple-cn=%s))", + Enabled: true, + }, + }, + }, + }, + // case 2 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source", + "--security-protocol", "zzzzz", + "--host", "ldap-server", + "--port", "123", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + "--email-attribute", "mail", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + errMsg: "Unknown security protocol name: zzzzz", + }, + // case 3 + { + args: []string{ + "ldap-test", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--port", "123", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + "--email-attribute", "mail", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + errMsg: "name is not set", + }, + // case 4 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source", + "--host", "ldap-server", + "--port", "123", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + "--email-attribute", "mail", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + errMsg: "security-protocol is not set", + }, + // case 5 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source", + "--security-protocol", "unencrypted", + "--port", "123", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + "--email-attribute", "mail", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + errMsg: "host is not set", + }, + // case 6 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + "--email-attribute", "mail", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + errMsg: "port is not set", + }, + // case 7 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--port", "123", + "--email-attribute", "mail", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + errMsg: "user-filter is not set", + }, + // case 8 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--port", "123", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + errMsg: "email-attribute is not set", + }, + // case 9 + { + args: []string{ + "ldap-test", + "--name", "ldap (simple auth) source", + "--security-protocol", "unencrypted", + "--host", "ldap-server", + "--port", "123", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + "--email-attribute", "mail", + }, + errMsg: "user-dn is not set", + }, + } + + for n, c := range cases { + // Mock functions. + var createdLoginSource *models.LoginSource + service := &authService{ + initDB: func() error { + return nil + }, + createLoginSource: func(loginSource *models.LoginSource) error { + createdLoginSource = loginSource + return nil + }, + updateLoginSource: func(loginSource *models.LoginSource) error { + assert.FailNow(t, "case %d: should not call updateLoginSource", n) + return nil + }, + getLoginSourceByID: func(id int64) (*models.LoginSource, error) { + assert.FailNow(t, "case %d: should not call getLoginSourceByID", n) + return nil, nil + }, + } + + // Create a copy of command to test + app := cli.NewApp() + app.Flags = cmdAuthAddLdapSimpleAuth.Flags + app.Action = service.addLdapSimpleAuth + + // Run it + err := app.Run(c.args) + if c.errMsg != "" { + assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) + } else { + assert.NoError(t, err, "case %d: should have no errors", n) + assert.Equal(t, c.loginSource, createdLoginSource, "case %d: wrong loginSource", n) + } + } +} + +func TestUpdateLdapBindDn(t *testing.T) { + // Mock cli functions to do not exit on error + var osExiter = cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} + + // Test cases + var cases = []struct { + args []string + id int64 + existingLoginSource *models.LoginSource + loginSource *models.LoginSource + errMsg string + }{ + // case 0 + { + args: []string{ + "ldap-test", + "--id", "23", + "--name", "ldap (via Bind DN) source full", + "--not-active", + "--security-protocol", "LDAPS", + "--skip-tls-verify", + "--host", "ldap-bind-server full", + "--port", "9876", + "--user-search-base", "ou=Users,dc=full-domain-bind,dc=org", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)", + "--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)", + "--username-attribute", "uid-bind full", + "--firstname-attribute", "givenName-bind full", + "--surname-attribute", "sn-bind full", + "--email-attribute", "mail-bind full", + "--public-ssh-key-attribute", "publickey-bind full", + "--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org", + "--bind-password", "secret-bind-full", + "--synchronize-users", + "--page-size", "99", + }, + id: 23, + existingLoginSource: &models.LoginSource{ + Type: models.LoginLDAP, + IsActived: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Enabled: true, + }, + }, + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Name: "ldap (via Bind DN) source full", + IsActived: false, + IsSyncEnabled: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (via Bind DN) source full", + Host: "ldap-bind-server full", + Port: 9876, + SecurityProtocol: ldap.SecurityProtocol(1), + SkipVerify: true, + BindDN: "cn=readonly,dc=full-domain-bind,dc=org", + BindPassword: "secret-bind-full", + UserBase: "ou=Users,dc=full-domain-bind,dc=org", + AttributeUsername: "uid-bind full", + AttributeName: "givenName-bind full", + AttributeSurname: "sn-bind full", + AttributeMail: "mail-bind full", + AttributesInBind: false, + AttributeSSHPublicKey: "publickey-bind full", + SearchPageSize: 99, + Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)", + AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)", + Enabled: true, + }, + }, + }, + }, + // case 1 + { + args: []string{ + "ldap-test", + "--id", "1", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + }, + // case 2 + { + args: []string{ + "ldap-test", + "--id", "1", + "--name", "ldap (via Bind DN) source", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Name: "ldap (via Bind DN) source", + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (via Bind DN) source", + }, + }, + }, + }, + // case 3 + { + args: []string{ + "ldap-test", + "--id", "1", + "--not-active", + }, + existingLoginSource: &models.LoginSource{ + Type: models.LoginLDAP, + IsActived: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + IsActived: false, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + }, + // case 4 + { + args: []string{ + "ldap-test", + "--id", "1", + "--security-protocol", "LDAPS", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + SecurityProtocol: ldap.SecurityProtocol(1), + }, + }, + }, + }, + // case 5 + { + args: []string{ + "ldap-test", + "--id", "1", + "--skip-tls-verify", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + SkipVerify: true, + }, + }, + }, + }, + // case 6 + { + args: []string{ + "ldap-test", + "--id", "1", + "--host", "ldap-server", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Host: "ldap-server", + }, + }, + }, + }, + // case 7 + { + args: []string{ + "ldap-test", + "--id", "1", + "--port", "389", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Port: 389, + }, + }, + }, + }, + // case 8 + { + args: []string{ + "ldap-test", + "--id", "1", + "--user-search-base", "ou=Users,dc=domain,dc=org", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + UserBase: "ou=Users,dc=domain,dc=org", + }, + }, + }, + }, + // case 9 + { + args: []string{ + "ldap-test", + "--id", "1", + "--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Filter: "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)", + }, + }, + }, + }, + // case 10 + { + args: []string{ + "ldap-test", + "--id", "1", + "--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)", + }, + }, + }, + }, + // case 11 + { + args: []string{ + "ldap-test", + "--id", "1", + "--username-attribute", "uid", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeUsername: "uid", + }, + }, + }, + }, + // case 12 + { + args: []string{ + "ldap-test", + "--id", "1", + "--firstname-attribute", "givenName", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeName: "givenName", + }, + }, + }, + }, + // case 13 + { + args: []string{ + "ldap-test", + "--id", "1", + "--surname-attribute", "sn", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeSurname: "sn", + }, + }, + }, + }, + // case 14 + { + args: []string{ + "ldap-test", + "--id", "1", + "--email-attribute", "mail", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeMail: "mail", + }, + }, + }, + }, + // case 15 + { + args: []string{ + "ldap-test", + "--id", "1", + "--attributes-in-bind", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributesInBind: true, + }, + }, + }, + }, + // case 16 + { + args: []string{ + "ldap-test", + "--id", "1", + "--public-ssh-key-attribute", "publickey", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeSSHPublicKey: "publickey", + }, + }, + }, + }, + // case 17 + { + args: []string{ + "ldap-test", + "--id", "1", + "--bind-dn", "cn=readonly,dc=domain,dc=org", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + BindDN: "cn=readonly,dc=domain,dc=org", + }, + }, + }, + }, + // case 18 + { + args: []string{ + "ldap-test", + "--id", "1", + "--bind-password", "secret", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + BindPassword: "secret", + }, + }, + }, + }, + // case 19 + { + args: []string{ + "ldap-test", + "--id", "1", + "--synchronize-users", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + IsSyncEnabled: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + }, + // case 20 + { + args: []string{ + "ldap-test", + "--id", "1", + "--page-size", "12", + }, + loginSource: &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + SearchPageSize: 12, + }, + }, + }, + }, + // case 21 + { + args: []string{ + "ldap-test", + "--id", "1", + "--security-protocol", "xxxxx", + }, + errMsg: "Unknown security protocol name: xxxxx", + }, + // case 22 + { + args: []string{ + "ldap-test", + }, + errMsg: "id is not set", + }, + // case 23 + { + args: []string{ + "ldap-test", + "--id", "1", + }, + existingLoginSource: &models.LoginSource{ + Type: models.LoginOAuth2, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + errMsg: "Invalid authentication type. expected: LDAP (via BindDN), actual: OAuth2", + }, + } + + for n, c := range cases { + // Mock functions. + var updatedLoginSource *models.LoginSource + service := &authService{ + initDB: func() error { + return nil + }, + createLoginSource: func(loginSource *models.LoginSource) error { + assert.FailNow(t, "case %d: should not call createLoginSource", n) + return nil + }, + updateLoginSource: func(loginSource *models.LoginSource) error { + updatedLoginSource = loginSource + return nil + }, + getLoginSourceByID: func(id int64) (*models.LoginSource, error) { + if c.id != 0 { + assert.Equal(t, c.id, id, "case %d: wrong id", n) + } + if c.existingLoginSource != nil { + return c.existingLoginSource, nil + } + return &models.LoginSource{ + Type: models.LoginLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, nil + }, + } + + // Create a copy of command to test + app := cli.NewApp() + app.Flags = cmdAuthUpdateLdapBindDn.Flags + app.Action = service.updateLdapBindDn + + // Run it + err := app.Run(c.args) + if c.errMsg != "" { + assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) + } else { + assert.NoError(t, err, "case %d: should have no errors", n) + assert.Equal(t, c.loginSource, updatedLoginSource, "case %d: wrong loginSource", n) + } + } +} + +func TestUpdateLdapSimpleAuth(t *testing.T) { + // Mock cli functions to do not exit on error + var osExiter = cli.OsExiter + defer func() { cli.OsExiter = osExiter }() + cli.OsExiter = func(code int) {} + + // Test cases + var cases = []struct { + args []string + id int64 + existingLoginSource *models.LoginSource + loginSource *models.LoginSource + errMsg string + }{ + // case 0 + { + args: []string{ + "ldap-test", + "--id", "7", + "--name", "ldap (simple auth) source full", + "--not-active", + "--security-protocol", "starttls", + "--skip-tls-verify", + "--host", "ldap-simple-server full", + "--port", "987", + "--user-search-base", "ou=Users,dc=full-domain-simple,dc=org", + "--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))", + "--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)", + "--username-attribute", "uid-simple full", + "--firstname-attribute", "givenName-simple full", + "--surname-attribute", "sn-simple full", + "--email-attribute", "mail-simple full", + "--public-ssh-key-attribute", "publickey-simple full", + "--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org", + }, + id: 7, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Name: "ldap (simple auth) source full", + IsActived: false, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (simple auth) source full", + Host: "ldap-simple-server full", + Port: 987, + SecurityProtocol: ldap.SecurityProtocol(2), + SkipVerify: true, + UserDN: "cn=%s,ou=Users,dc=full-domain-simple,dc=org", + UserBase: "ou=Users,dc=full-domain-simple,dc=org", + AttributeUsername: "uid-simple full", + AttributeName: "givenName-simple full", + AttributeSurname: "sn-simple full", + AttributeMail: "mail-simple full", + AttributeSSHPublicKey: "publickey-simple full", + Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))", + AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)", + }, + }, + }, + }, + // case 1 + { + args: []string{ + "ldap-test", + "--id", "1", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + }, + // case 2 + { + args: []string{ + "ldap-test", + "--id", "1", + "--name", "ldap (simple auth) source", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Name: "ldap (simple auth) source", + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Name: "ldap (simple auth) source", + }, + }, + }, + }, + // case 3 + { + args: []string{ + "ldap-test", + "--id", "1", + "--not-active", + }, + existingLoginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + IsActived: true, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + IsActived: false, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + }, + // case 4 + { + args: []string{ + "ldap-test", + "--id", "1", + "--security-protocol", "starttls", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + SecurityProtocol: ldap.SecurityProtocol(2), + }, + }, + }, + }, + // case 5 + { + args: []string{ + "ldap-test", + "--id", "1", + "--skip-tls-verify", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + SkipVerify: true, + }, + }, + }, + }, + // case 6 + { + args: []string{ + "ldap-test", + "--id", "1", + "--host", "ldap-server", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Host: "ldap-server", + }, + }, + }, + }, + // case 7 + { + args: []string{ + "ldap-test", + "--id", "1", + "--port", "987", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Port: 987, + }, + }, + }, + }, + // case 8 + { + args: []string{ + "ldap-test", + "--id", "1", + "--user-search-base", "ou=Users,dc=domain,dc=org", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + UserBase: "ou=Users,dc=domain,dc=org", + }, + }, + }, + }, + // case 9 + { + args: []string{ + "ldap-test", + "--id", "1", + "--user-filter", "(&(objectClass=posixAccount)(cn=%s))", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + Filter: "(&(objectClass=posixAccount)(cn=%s))", + }, + }, + }, + }, + // case 10 + { + args: []string{ + "ldap-test", + "--id", "1", + "--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)", + }, + }, + }, + }, + // case 11 + { + args: []string{ + "ldap-test", + "--id", "1", + "--username-attribute", "uid", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeUsername: "uid", + }, + }, + }, + }, + // case 12 + { + args: []string{ + "ldap-test", + "--id", "1", + "--firstname-attribute", "givenName", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeName: "givenName", + }, + }, + }, + }, + // case 13 + { + args: []string{ + "ldap-test", + "--id", "1", + "--surname-attribute", "sn", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeSurname: "sn", + }, + }, + }, + }, + // case 14 + { + args: []string{ + "ldap-test", + "--id", "1", + "--email-attribute", "mail", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeMail: "mail", + }, + }, + }, + }, + // case 15 + { + args: []string{ + "ldap-test", + "--id", "1", + "--public-ssh-key-attribute", "publickey", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + AttributeSSHPublicKey: "publickey", + }, + }, + }, + }, + // case 16 + { + args: []string{ + "ldap-test", + "--id", "1", + "--user-dn", "cn=%s,ou=Users,dc=domain,dc=org", + }, + loginSource: &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{ + UserDN: "cn=%s,ou=Users,dc=domain,dc=org", + }, + }, + }, + }, + // case 17 + { + args: []string{ + "ldap-test", + "--id", "1", + "--security-protocol", "xxxxx", + }, + errMsg: "Unknown security protocol name: xxxxx", + }, + // case 18 + { + args: []string{ + "ldap-test", + }, + errMsg: "id is not set", + }, + // case 19 + { + args: []string{ + "ldap-test", + "--id", "1", + }, + existingLoginSource: &models.LoginSource{ + Type: models.LoginPAM, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, + errMsg: "Invalid authentication type. expected: LDAP (simple auth), actual: PAM", + }, + } + + for n, c := range cases { + // Mock functions. + var updatedLoginSource *models.LoginSource + service := &authService{ + initDB: func() error { + return nil + }, + createLoginSource: func(loginSource *models.LoginSource) error { + assert.FailNow(t, "case %d: should not call createLoginSource", n) + return nil + }, + updateLoginSource: func(loginSource *models.LoginSource) error { + updatedLoginSource = loginSource + return nil + }, + getLoginSourceByID: func(id int64) (*models.LoginSource, error) { + if c.id != 0 { + assert.Equal(t, c.id, id, "case %d: wrong id", n) + } + if c.existingLoginSource != nil { + return c.existingLoginSource, nil + } + return &models.LoginSource{ + Type: models.LoginDLDAP, + Cfg: &models.LDAPConfig{ + Source: &ldap.Source{}, + }, + }, nil + }, + } + + // Create a copy of command to test + app := cli.NewApp() + app.Flags = cmdAuthUpdateLdapSimpleAuth.Flags + app.Action = service.updateLdapSimpleAuth + + // Run it + err := app.Run(c.args) + if c.errMsg != "" { + assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) + } else { + assert.NoError(t, err, "case %d: should have no errors", n) + assert.Equal(t, c.loginSource, updatedLoginSource, "case %d: wrong loginSource", n) + } + } +} diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index 516e46ff0b..0955680af2 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -123,6 +123,94 @@ Admin operations: - `--custom-email-url`: Use a custom Email URL (option for GitHub). - Examples: - `gitea admin auth update-oauth --id 1 --name external-github-updated` + - `add-ldap`: Add new LDAP (via Bind DN) authentication source + - Options: + - `--name value`: Authentication name. Required. + - `--not-active`: Deactivate the authentication source. + - `--security-protocol value`: Security protocol name. Required. + - `--skip-tls-verify`: Disable TLS verification. + - `--host value`: The address where the LDAP server can be reached. Required. + - `--port value`: The port to use when connecting to the LDAP server. Required. + - `--user-search-base value`: The LDAP base at which user accounts will be searched for. Required. + - `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required. + - `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges. + - `--username-attribute value`: The attribute of the user’s LDAP record containing the user name. + - `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name. + - `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname. + - `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required. + - `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key. + - `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user. + - `--bind-password value`: The password for the Bind DN, if any. + - `--attributes-in-bind`: Fetch attributes in bind DN context. + - `--synchronize-users`: Enable user synchronization. + - `--page-size value`: Search page size. + - Examples: + - `gitea admin auth add-ldap --name ldap --security-protocol unencrypted --host mydomain.org --port 389 --user-search-base "ou=Users,dc=mydomain,dc=org" --user-filter "(&(objectClass=posixAccount)(uid=%s))" --email-attribute mail` + - `update-ldap`: Update existing LDAP (via Bind DN) authentication source + - Options: + - `--id value`: ID of authentication source. Required. + - `--name value`: Authentication name. + - `--not-active`: Deactivate the authentication source. + - `--security-protocol value`: Security protocol name. + - `--skip-tls-verify`: Disable TLS verification. + - `--host value`: The address where the LDAP server can be reached. + - `--port value`: The port to use when connecting to the LDAP server. + - `--user-search-base value`: The LDAP base at which user accounts will be searched for. + - `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. + - `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges. + - `--username-attribute value`: The attribute of the user’s LDAP record containing the user name. + - `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name. + - `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname. + - `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. + - `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key. + - `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user. + - `--bind-password value`: The password for the Bind DN, if any. + - `--attributes-in-bind`: Fetch attributes in bind DN context. + - `--synchronize-users`: Enable user synchronization. + - `--page-size value`: Search page size. + - Examples: + - `gitea admin auth update-ldap --id 1 --name "my ldap auth source"` + - `gitea admin auth update-ldap --id 1 --username-attribute uid --firstname-attribute givenName --surname-attribute sn` + - `add-ldap-simple`: Add new LDAP (simple auth) authentication source + - Options: + - `--name value`: Authentication name. Required. + - `--not-active`: Deactivate the authentication source. + - `--security-protocol value`: Security protocol name. Required. + - `--skip-tls-verify`: Disable TLS verification. + - `--host value`: The address where the LDAP server can be reached. Required. + - `--port value`: The port to use when connecting to the LDAP server. Required. + - `--user-search-base value`: The LDAP base at which user accounts will be searched for. + - `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required. + - `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges. + - `--username-attribute value`: The attribute of the user’s LDAP record containing the user name. + - `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name. + - `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname. + - `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required. + - `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key. + - `--user-dn value`: The user’s DN. Required. + - Examples: + - `gitea admin auth add-ldap-simple --name ldap --security-protocol unencrypted --host mydomain.org --port 389 --user-dn "cn=%s,ou=Users,dc=mydomain,dc=org" --user-filter "(&(objectClass=posixAccount)(cn=%s))" --email-attribute mail` + - `update-ldap-simple`: Update existing LDAP (simple auth) authentication source + - Options: + - `--id value`: ID of authentication source. Required. + - `--name value`: Authentication name. + - `--not-active`: Deactivate the authentication source. + - `--security-protocol value`: Security protocol name. + - `--skip-tls-verify`: Disable TLS verification. + - `--host value`: The address where the LDAP server can be reached. + - `--port value`: The port to use when connecting to the LDAP server. + - `--user-search-base value`: The LDAP base at which user accounts will be searched for. + - `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. + - `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges. + - `--username-attribute value`: The attribute of the user’s LDAP record containing the user name. + - `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name. + - `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname. + - `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. + - `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key. + - `--user-dn value`: The user’s DN. + - Examples: + - `gitea admin auth update-ldap-simple --id 1 --name "my ldap auth source"` + - `gitea admin auth update-ldap-simple --id 1 --username-attribute uid --firstname-attribute givenName --surname-attribute sn` #### cert From 2e5da98ecb9f20b4d9464d3dd78159731ea16676 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Mon, 17 Jun 2019 13:42:14 -0500 Subject: [PATCH 125/220] Changelog 1.8.3 (#7230) (#7231) * Changelog 1.8.3 Signed-off-by: jolheiser * Suggestion Co-Authored-By: zeripath --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b7547e1ac..f66d08ec4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.8.3](https://github.com/go-gitea/gitea/releases/tag/v1.8.3) - 2019-06-17 +* BUGFIXES + * Always set userID on LFS authentication (#7224) (Part of #6993) + * Fix LFS Locks over SSH (#6999) (#7223) + * Fix duplicated file on pull request conflicted files (#7211) (#7214) + * Detect noreply email address as user (#7133) (#7195) + * Don't get milestone from DB if ID is zero (#7169) (#7174) + * Allow archived repos to be (un)starred and (un)watched (#7163) (#7168) + * Fix GCArgs load from ini (#7156) (#7157) + ## [1.8.2](https://github.com/go-gitea/gitea/releases/tag/v1.8.2) - 2019-05-29 * BUGFIXES * Fix possbile mysql invalid connnection error (#7051) (#7071) From 6d0f78542f4c8bc9ca73dde0c6ed3671251fed20 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Mon, 17 Jun 2019 22:52:03 -0400 Subject: [PATCH 126/220] Add docs for `INTERNAL_TOKEN_URI` (#7234) --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index ecc196c86e..12cad995e5 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -195,6 +195,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `DISABLE_GIT_HOOKS`: **false**: Set to `true` to prevent all users (including admin) from creating custom git hooks. - `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server. +- `INTERNAL_TOKEN`: **\**: Secret used to validate communication within Gitea binary. +- `INTERNAL_TOKEN_URI`: ****: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`) ## OpenID (`openid`) From 2d097655a64c4ce0b295d5cd5c897f6cad43fa17 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Tue, 18 Jun 2019 04:57:48 +0200 Subject: [PATCH 127/220] Fix relref link in docs (#7233) --- docs/content/doc/advanced/hacking-on-gitea.en-us.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/doc/advanced/hacking-on-gitea.en-us.md b/docs/content/doc/advanced/hacking-on-gitea.en-us.md index 48a4510545..481f26dcf8 100644 --- a/docs/content/doc/advanced/hacking-on-gitea.en-us.md +++ b/docs/content/doc/advanced/hacking-on-gitea.en-us.md @@ -209,7 +209,7 @@ OpenAPI 3 documentation. When creating new configuration options, it is not enough to add them to the `modules/setting` files. You should add information to `custom/conf/app.ini` and to the -configuration cheat sheet +configuration cheat sheet found in `docs/content/doc/advanced/config-cheat-sheet.en-us.md` ### Changing the logo From 954d24c121eb35f6c07259cde2f2d75c628d1c82 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 18 Jun 2019 15:17:00 +0100 Subject: [PATCH 128/220] Update css (#7240) Remove -o-tab-size selectors from tab-sze-1 css --- public/css/index.css | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 8f575fcd95..02cd400b2f 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -783,22 +783,22 @@ footer .ui.left,footer .ui.right{line-height:40px} #avatar-arrow:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} #avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} #delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important} -.tab-size-1{-moz-tab-size:1!important;-o-tab-size:1!important;tab-size:1!important} -.tab-size-2{-moz-tab-size:2!important;-o-tab-size:2!important;tab-size:2!important} -.tab-size-3{-moz-tab-size:3!important;-o-tab-size:3!important;tab-size:3!important} -.tab-size-4{-moz-tab-size:4!important;-o-tab-size:4!important;tab-size:4!important} -.tab-size-5{-moz-tab-size:5!important;-o-tab-size:5!important;tab-size:5!important} -.tab-size-6{-moz-tab-size:6!important;-o-tab-size:6!important;tab-size:6!important} -.tab-size-7{-moz-tab-size:7!important;-o-tab-size:7!important;tab-size:7!important} -.tab-size-8{-moz-tab-size:8!important;-o-tab-size:8!important;tab-size:8!important} -.tab-size-9{-moz-tab-size:9!important;-o-tab-size:9!important;tab-size:9!important} -.tab-size-10{-moz-tab-size:10!important;-o-tab-size:10!important;tab-size:10!important} -.tab-size-11{-moz-tab-size:11!important;-o-tab-size:11!important;tab-size:11!important} -.tab-size-12{-moz-tab-size:12!important;-o-tab-size:12!important;tab-size:12!important} -.tab-size-13{-moz-tab-size:13!important;-o-tab-size:13!important;tab-size:13!important} -.tab-size-14{-moz-tab-size:14!important;-o-tab-size:14!important;tab-size:14!important} -.tab-size-15{-moz-tab-size:15!important;-o-tab-size:15!important;tab-size:15!important} -.tab-size-16{-moz-tab-size:16!important;-o-tab-size:16!important;tab-size:16!important} +.tab-size-1{-moz-tab-size:1!important;tab-size:1!important} +.tab-size-2{-moz-tab-size:2!important;tab-size:2!important} +.tab-size-3{-moz-tab-size:3!important;tab-size:3!important} +.tab-size-4{-moz-tab-size:4!important;tab-size:4!important} +.tab-size-5{-moz-tab-size:5!important;tab-size:5!important} +.tab-size-6{-moz-tab-size:6!important;tab-size:6!important} +.tab-size-7{-moz-tab-size:7!important;tab-size:7!important} +.tab-size-8{-moz-tab-size:8!important;tab-size:8!important} +.tab-size-9{-moz-tab-size:9!important;tab-size:9!important} +.tab-size-10{-moz-tab-size:10!important;tab-size:10!important} +.tab-size-11{-moz-tab-size:11!important;tab-size:11!important} +.tab-size-12{-moz-tab-size:12!important;tab-size:12!important} +.tab-size-13{-moz-tab-size:13!important;tab-size:13!important} +.tab-size-14{-moz-tab-size:14!important;tab-size:14!important} +.tab-size-15{-moz-tab-size:15!important;tab-size:15!important} +.tab-size-16{-moz-tab-size:16!important;tab-size:16!important} .stats-table{display:table;width:100%} .stats-table .table-cell{display:table-cell} .stats-table .table-cell.tiny{height:.5em} From 392fe6c943c9fcd70857d1f5bff177bdf7c5f69e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 19 Jun 2019 00:15:39 +0800 Subject: [PATCH 129/220] Fix migration panic when Head.User is not exist (#7226) * fix migration panic when Head.User is not exist * fix test --- modules/migrations/github.go | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 21c1becedf..6847787ace 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -416,17 +416,36 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq merged = true } - var headRepoName string - var cloneURL string + var ( + headRepoName string + cloneURL string + headRef string + headSHA string + ) if pr.Head.Repo != nil { - headRepoName = *pr.Head.Repo.Name - cloneURL = *pr.Head.Repo.CloneURL + if pr.Head.Repo.Name != nil { + headRepoName = *pr.Head.Repo.Name + } + if pr.Head.Repo.CloneURL != nil { + cloneURL = *pr.Head.Repo.CloneURL + } + } + if pr.Head.Ref != nil { + headRef = *pr.Head.Ref + } + if pr.Head.SHA != nil { + headSHA = *pr.Head.SHA } var mergeCommitSHA string if pr.MergeCommitSHA != nil { mergeCommitSHA = *pr.MergeCommitSHA } + var headUserName string + if pr.Head.User != nil && pr.Head.User.Login != nil { + headUserName = *pr.Head.User.Login + } + allPRs = append(allPRs, &base.PullRequest{ Title: *pr.Title, Number: int64(*pr.Number), @@ -443,10 +462,10 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq MergedTime: pr.MergedAt, IsLocked: pr.ActiveLockReason != nil, Head: base.PullRequestBranch{ - Ref: *pr.Head.Ref, - SHA: *pr.Head.SHA, + Ref: headRef, + SHA: headSHA, RepoName: headRepoName, - OwnerName: *pr.Head.User.Login, + OwnerName: headUserName, CloneURL: cloneURL, }, Base: base.PullRequestBranch{ From a205155e9d984f050eb081aa4904fad6a0598ab6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 18 Jun 2019 21:32:49 +0200 Subject: [PATCH 130/220] add self to MAINTAINERS (#7245) --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1934acce49..b97a452db6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29,3 +29,4 @@ Andrew Thornton (@zeripath) John Olheiser (@jolheiser) Richard Mahn (@richmahn) Mrsdizzie (@mrsdizzie) +silverwind (@silverwind) From b209531959104cb6d5a8079ec567386720f3aaf3 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 19 Jun 2019 00:31:31 +0200 Subject: [PATCH 131/220] fix hljs unintenionally highlighting commit links (#7244) * fix hljs unintenionally highlighting commit links * fix unit tests --- modules/markup/html.go | 1 + modules/markup/html_internal_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index dbfc8dbe85..3e976929c7 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -323,6 +323,7 @@ func createCodeLink(href, content string) *html.Node { code := &html.Node{ Type: html.ElementNode, Data: atom.Code.String(), + Attr: []html.Attribute{{Key: "class", Val: "nohighlight"}}, } code.AppendChild(text) diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go index 10bc4973cd..f0d894532b 100644 --- a/modules/markup/html_internal_test.go +++ b/modules/markup/html_internal_test.go @@ -197,13 +197,13 @@ func TestRender_AutoLink(t *testing.T) { // render valid commit URLs tmp := util.URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae") - test(tmp, "d8a994ef24") + test(tmp, "d8a994ef24") tmp += "#diff-2" - test(tmp, "d8a994ef24 (diff-2)") + test(tmp, "d8a994ef24 (diff-2)") // render other commit URLs - tmp = "https://external-link.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2" - test(tmp, "d8a994ef24 (diff-2)") + tmp = "https://external-link.gitea.io/go-gitea/gitea/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2" + test(tmp, "d8a994ef24 (diff-2)") } func TestRender_FullIssueURLs(t *testing.T) { From 33ad5548002156f7fb7779870571600c0a181c85 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Tue, 18 Jun 2019 22:14:15 -0400 Subject: [PATCH 132/220] update go-git to v4.12.0 - fixes #7248 (#7249) --- go.mod | 14 +- go.sum | 54 +- .../mitchellh/go-homedir/homedir.go | 10 + vendor/github.com/xanzy/ssh-agent/go.mod | 6 + vendor/github.com/xanzy/ssh-agent/go.sum | 4 + .../x/crypto/acme/autocert/autocert.go | 21 +- vendor/golang.org/x/crypto/ed25519/ed25519.go | 5 + .../x/crypto/ed25519/ed25519_go113.go | 73 + .../x/crypto/internal/chacha20/asm_ppc64le.s | 668 ++ .../crypto/internal/chacha20/chacha_noasm.go | 2 +- .../internal/chacha20/chacha_ppc64le.go | 52 + vendor/golang.org/x/crypto/openpgp/keys.go | 14 +- .../x/crypto/openpgp/packet/private_key.go | 26 +- .../golang.org/x/crypto/poly1305/mac_noasm.go | 2 +- .../golang.org/x/crypto/poly1305/sum_noasm.go | 2 +- .../x/crypto/poly1305/sum_ppc64le.go | 68 + .../x/crypto/poly1305/sum_ppc64le.s | 247 + vendor/golang.org/x/crypto/ssh/client_auth.go | 114 + vendor/golang.org/x/crypto/ssh/common.go | 7 + vendor/golang.org/x/crypto/ssh/kex.go | 249 + vendor/golang.org/x/crypto/ssh/messages.go | 74 + vendor/golang.org/x/crypto/ssh/server.go | 124 +- vendor/golang.org/x/crypto/ssh/ssh_gss.go | 139 + .../x/net/context/ctxhttp/ctxhttp.go | 5 +- .../x/net/context/ctxhttp/ctxhttp_pre17.go | 147 - vendor/golang.org/x/net/html/node.go | 2 +- vendor/golang.org/x/net/html/parse.go | 158 +- vendor/golang.org/x/net/idna/idna10.0.0.go | 734 ++ vendor/golang.org/x/net/idna/idna9.0.0.go | 682 ++ vendor/golang.org/x/net/idna/punycode.go | 203 + vendor/golang.org/x/net/idna/tables10.0.0.go | 4559 ++++++++++ vendor/golang.org/x/net/idna/tables11.0.0.go | 4653 ++++++++++ vendor/golang.org/x/net/idna/tables9.0.0.go | 4486 ++++++++++ vendor/golang.org/x/net/idna/trie.go | 72 + vendor/golang.org/x/net/idna/trieval.go | 119 + .../golang.org/x/net/internal/socks/client.go | 168 + .../golang.org/x/net/internal/socks/socks.go | 317 + vendor/golang.org/x/net/proxy/dial.go | 54 + vendor/golang.org/x/net/proxy/direct.go | 31 + vendor/golang.org/x/net/proxy/per_host.go | 155 + vendor/golang.org/x/net/proxy/proxy.go | 149 + vendor/golang.org/x/net/proxy/socks5.go | 42 + vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 17 + vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go | 10 +- .../x/sys/cpu/syscall_aix_ppc64_gc.go | 36 + .../golang.org/x/sys/unix/asm_linux_riscv64.s | 54 + .../golang.org/x/sys/unix/asm_openbsd_arm64.s | 29 + vendor/golang.org/x/sys/unix/mkall.sh | 29 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 7 +- vendor/golang.org/x/sys/unix/mkpost.go | 16 + .../x/sys/unix/mksyscall_aix_ppc.go | 13 +- .../x/sys/unix/mksyscall_aix_ppc64.go | 14 +- .../golang.org/x/sys/unix/mksysctl_openbsd.go | 355 + .../golang.org/x/sys/unix/mksysctl_openbsd.pl | 265 - vendor/golang.org/x/sys/unix/mksysnum.go | 2 +- .../{openbsd_pledge.go => pledge_openbsd.go} | 3 - vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 11 +- vendor/golang.org/x/sys/unix/syscall.go | 1 - vendor/golang.org/x/sys/unix/syscall_aix.go | 28 +- .../golang.org/x/sys/unix/syscall_aix_ppc.go | 16 + .../x/sys/unix/syscall_aix_ppc64.go | 47 + .../golang.org/x/sys/unix/syscall_freebsd.go | 50 +- vendor/golang.org/x/sys/unix/syscall_linux.go | 88 +- .../x/sys/unix/syscall_linux_arm.go | 13 + .../golang.org/x/sys/unix/syscall_netbsd.go | 25 +- .../golang.org/x/sys/unix/syscall_openbsd.go | 25 +- .../x/sys/unix/syscall_openbsd_arm64.go | 37 + vendor/golang.org/x/sys/unix/syscall_unix.go | 6 +- vendor/golang.org/x/sys/unix/types_aix.go | 27 +- .../{openbsd_unveil.go => unveil_openbsd.go} | 2 - .../golang.org/x/sys/unix/zerrors_aix_ppc.go | 2 + .../x/sys/unix/zerrors_aix_ppc64.go | 4 +- .../x/sys/unix/zerrors_linux_386.go | 110 + .../x/sys/unix/zerrors_linux_amd64.go | 110 + .../x/sys/unix/zerrors_linux_arm.go | 110 + .../x/sys/unix/zerrors_linux_arm64.go | 110 + .../x/sys/unix/zerrors_linux_mips.go | 110 + .../x/sys/unix/zerrors_linux_mips64.go | 110 + .../x/sys/unix/zerrors_linux_mips64le.go | 110 + .../x/sys/unix/zerrors_linux_mipsle.go | 110 + .../x/sys/unix/zerrors_linux_ppc64.go | 110 + .../x/sys/unix/zerrors_linux_ppc64le.go | 110 + .../x/sys/unix/zerrors_linux_riscv64.go | 110 + .../x/sys/unix/zerrors_linux_s390x.go | 110 + .../x/sys/unix/zerrors_linux_sparc64.go | 110 + .../x/sys/unix/zerrors_openbsd_arm64.go | 1789 ++++ .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 52 +- .../x/sys/unix/zsyscall_aix_ppc64.go | 40 +- .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 44 +- .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 35 +- .../x/sys/unix/zsyscall_freebsd_386.go | 2 +- .../x/sys/unix/zsyscall_freebsd_amd64.go | 2 +- .../x/sys/unix/zsyscall_freebsd_arm.go | 2 +- .../x/sys/unix/zsyscall_freebsd_arm64.go | 2 +- .../x/sys/unix/zsyscall_linux_386.go | 34 +- .../x/sys/unix/zsyscall_linux_amd64.go | 34 +- .../x/sys/unix/zsyscall_linux_arm.go | 49 +- .../x/sys/unix/zsyscall_linux_arm64.go | 34 +- .../x/sys/unix/zsyscall_linux_mips.go | 34 +- .../x/sys/unix/zsyscall_linux_mips64.go | 34 +- .../x/sys/unix/zsyscall_linux_mips64le.go | 34 +- .../x/sys/unix/zsyscall_linux_mipsle.go | 34 +- .../x/sys/unix/zsyscall_linux_ppc64.go | 34 +- .../x/sys/unix/zsyscall_linux_ppc64le.go | 34 +- .../x/sys/unix/zsyscall_linux_riscv64.go | 34 +- .../x/sys/unix/zsyscall_linux_s390x.go | 34 +- .../x/sys/unix/zsyscall_linux_sparc64.go | 34 +- .../x/sys/unix/zsyscall_netbsd_386.go | 2 +- .../x/sys/unix/zsyscall_netbsd_amd64.go | 2 +- .../x/sys/unix/zsyscall_netbsd_arm.go | 2 +- .../x/sys/unix/zsyscall_netbsd_arm64.go | 2 +- .../x/sys/unix/zsyscall_openbsd_386.go | 2 +- .../x/sys/unix/zsyscall_openbsd_amd64.go | 2 +- .../x/sys/unix/zsyscall_openbsd_arm.go | 2 +- .../x/sys/unix/zsyscall_openbsd_arm64.go | 1692 ++++ .../x/sys/unix/zsysctl_openbsd_386.go | 2 + .../x/sys/unix/zsysctl_openbsd_amd64.go | 2 +- .../x/sys/unix/zsysctl_openbsd_arm.go | 4 +- .../x/sys/unix/zsysctl_openbsd_arm64.go | 275 + .../x/sys/unix/zsysnum_freebsd_386.go | 23 +- .../x/sys/unix/zsysnum_freebsd_amd64.go | 23 +- .../x/sys/unix/zsysnum_freebsd_arm.go | 23 +- .../x/sys/unix/zsysnum_freebsd_arm64.go | 445 +- .../x/sys/unix/zsysnum_linux_386.go | 800 +- .../x/sys/unix/zsysnum_linux_amd64.go | 4 + .../x/sys/unix/zsysnum_linux_arm.go | 736 +- .../x/sys/unix/zsysnum_linux_arm64.go | 4 + .../x/sys/unix/zsysnum_linux_mips.go | 770 +- .../x/sys/unix/zsysnum_linux_mips64.go | 4 + .../x/sys/unix/zsysnum_linux_mips64le.go | 4 + .../x/sys/unix/zsysnum_linux_mipsle.go | 770 +- .../x/sys/unix/zsysnum_linux_ppc64.go | 15 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 15 + .../x/sys/unix/zsysnum_linux_riscv64.go | 4 + .../x/sys/unix/zsysnum_linux_s390x.go | 18 + .../x/sys/unix/zsysnum_linux_sparc64.go | 19 + .../x/sys/unix/zsysnum_openbsd_arm64.go | 217 + .../golang.org/x/sys/unix/ztypes_aix_ppc.go | 45 +- .../golang.org/x/sys/unix/ztypes_aix_ppc64.go | 50 +- .../x/sys/unix/ztypes_darwin_386.go | 36 +- .../x/sys/unix/ztypes_darwin_amd64.go | 38 +- .../x/sys/unix/ztypes_darwin_arm.go | 36 +- .../x/sys/unix/ztypes_darwin_arm64.go | 38 +- .../x/sys/unix/ztypes_dragonfly_amd64.go | 38 +- .../x/sys/unix/ztypes_freebsd_386.go | 82 +- .../x/sys/unix/ztypes_freebsd_amd64.go | 72 +- .../x/sys/unix/ztypes_freebsd_arm.go | 72 +- .../x/sys/unix/ztypes_freebsd_arm64.go | 72 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 652 +- .../x/sys/unix/ztypes_linux_amd64.go | 652 +- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 652 +- .../x/sys/unix/ztypes_linux_arm64.go | 652 +- .../x/sys/unix/ztypes_linux_mips.go | 652 +- .../x/sys/unix/ztypes_linux_mips64.go | 652 +- .../x/sys/unix/ztypes_linux_mips64le.go | 652 +- .../x/sys/unix/ztypes_linux_mipsle.go | 652 +- .../x/sys/unix/ztypes_linux_ppc64.go | 652 +- .../x/sys/unix/ztypes_linux_ppc64le.go | 652 +- .../x/sys/unix/ztypes_linux_riscv64.go | 652 +- .../x/sys/unix/ztypes_linux_s390x.go | 652 +- .../x/sys/unix/ztypes_linux_sparc64.go | 652 +- .../x/sys/unix/ztypes_netbsd_386.go | 34 +- .../x/sys/unix/ztypes_netbsd_amd64.go | 40 +- .../x/sys/unix/ztypes_netbsd_arm.go | 40 +- .../x/sys/unix/ztypes_netbsd_arm64.go | 40 +- .../x/sys/unix/ztypes_openbsd_arm64.go | 564 ++ .../golang.org/x/sys/windows/env_windows.go | 34 +- vendor/golang.org/x/sys/windows/mkerrors.bash | 63 + .../x/sys/windows/mkknownfolderids.bash | 27 + vendor/golang.org/x/sys/windows/mksyscall.go | 2 + .../x/sys/windows/security_windows.go | 235 +- vendor/golang.org/x/sys/windows/service.go | 72 +- .../golang.org/x/sys/windows/svc/service.go | 3 +- .../x/sys/windows/syscall_windows.go | 115 +- .../golang.org/x/sys/windows/types_windows.go | 268 +- .../x/sys/windows/zerrors_windows.go | 6853 +++++++++++++++ .../x/sys/windows/zknownfolderids_windows.go | 149 + .../x/sys/windows/zsyscall_windows.go | 589 +- vendor/golang.org/x/text/encoding/encoding.go | 2 +- .../x/text/encoding/htmlindex/tables.go | 1 + .../text/encoding/internal/identifier/gen.go | 7 +- .../internal/identifier/identifier.go | 2 +- .../text/encoding/internal/identifier/mib.go | 96 +- .../x/text/encoding/japanese/maketables.go | 4 +- .../x/text/encoding/unicode/unicode.go | 2 +- .../x/text/{ => internal}/language/common.go | 12 +- .../x/text/internal/language/compact.go | 29 + .../text/internal/language/compact/compact.go | 61 + .../x/text/internal/language/compact/gen.go | 64 + .../internal/language/compact/gen_index.go | 113 + .../internal/language/compact/gen_parents.go | 54 + .../internal/language/compact/language.go | 260 + .../text/internal/language/compact/parents.go | 120 + .../text/internal/language/compact/tables.go | 1015 +++ .../x/text/internal/language/compact/tags.go | 91 + .../x/text/internal/language/compose.go | 167 + .../x/text/internal/language/coverage.go | 28 + .../x/text/internal/language/gen.go | 1520 ++++ .../{ => internal}/language/gen_common.go | 12 +- .../x/text/internal/language/language.go | 596 ++ .../x/text/{ => internal}/language/lookup.go | 120 +- .../x/text/internal/language/match.go | 226 + .../x/text/internal/language/parse.go | 594 ++ .../x/text/internal/language/tables.go | 3431 ++++++++ .../x/text/internal/language/tags.go | 48 + vendor/golang.org/x/text/language/Makefile | 16 - vendor/golang.org/x/text/language/coverage.go | 34 +- vendor/golang.org/x/text/language/gen.go | 1515 +--- .../golang.org/x/text/language/gen_index.go | 162 - vendor/golang.org/x/text/language/index.go | 783 -- vendor/golang.org/x/text/language/language.go | 716 +- vendor/golang.org/x/text/language/match.go | 422 +- vendor/golang.org/x/text/language/parse.go | 735 +- vendor/golang.org/x/text/language/tables.go | 3442 +------- vendor/golang.org/x/text/language/tags.go | 160 +- .../x/text/secure/bidirule/bidirule.go | 336 + .../x/text/secure/bidirule/bidirule10.0.0.go | 11 + .../x/text/secure/bidirule/bidirule9.0.0.go | 14 + .../golang.org/x/text/transform/transform.go | 6 +- vendor/golang.org/x/text/unicode/bidi/bidi.go | 198 + .../golang.org/x/text/unicode/bidi/bracket.go | 335 + vendor/golang.org/x/text/unicode/bidi/core.go | 1058 +++ vendor/golang.org/x/text/unicode/bidi/gen.go | 133 + .../x/text/unicode/bidi/gen_ranges.go | 57 + .../x/text/unicode/bidi/gen_trieval.go | 64 + vendor/golang.org/x/text/unicode/bidi/prop.go | 206 + .../x/text/unicode/bidi/tables10.0.0.go | 1815 ++++ .../x/text/unicode/bidi/tables11.0.0.go | 1887 ++++ .../x/text/unicode/bidi/tables9.0.0.go | 1781 ++++ .../golang.org/x/text/unicode/bidi/trieval.go | 60 + .../x/text/unicode/norm/composition.go | 8 +- .../x/text/unicode/norm/forminfo.go | 19 + vendor/golang.org/x/text/unicode/norm/iter.go | 3 +- .../x/text/unicode/norm/maketables.go | 20 +- .../x/text/unicode/norm/normalize.go | 4 +- .../x/text/unicode/norm/readwriter.go | 4 +- .../x/text/unicode/norm/tables10.0.0.go | 1892 ++-- .../x/text/unicode/norm/tables11.0.0.go | 7693 +++++++++++++++++ .../x/text/unicode/norm/tables9.0.0.go | 1890 ++-- .../x/text/unicode/norm/transform.go | 10 +- .../gopkg.in/src-d/go-git.v4/COMPATIBILITY.md | 2 +- .../gopkg.in/src-d/go-git.v4/config/branch.go | 23 +- .../gopkg.in/src-d/go-git.v4/config/config.go | 1 + .../src-d/go-git.v4/config/refspec.go | 6 +- vendor/gopkg.in/src-d/go-git.v4/go.mod | 23 +- vendor/gopkg.in/src-d/go-git.v4/go.sum | 56 +- vendor/gopkg.in/src-d/go-git.v4/options.go | 5 + .../plumbing/format/idxfile/idxfile.go | 109 +- .../plumbing/format/index/decoder.go | 37 +- .../plumbing/format/packfile/common.go | 10 + .../plumbing/format/packfile/diff_delta.go | 13 +- .../plumbing/format/packfile/packfile.go | 189 +- .../plumbing/format/packfile/scanner.go | 195 +- .../src-d/go-git.v4/plumbing/object/commit.go | 11 +- .../object/commit_walker_bfs_filtered.go | 176 + .../src-d/go-git.v4/plumbing/object/common.go | 12 + .../go-git.v4/plumbing/object/merge_base.go | 210 + .../src-d/go-git.v4/plumbing/object/patch.go | 4 + .../src-d/go-git.v4/plumbing/object/tag.go | 13 +- .../src-d/go-git.v4/plumbing/object/tree.go | 23 +- .../plumbing/transport/ssh/common.go | 27 +- vendor/gopkg.in/src-d/go-git.v4/remote.go | 5 +- vendor/gopkg.in/src-d/go-git.v4/repository.go | 91 +- .../storage/filesystem/dotgit/dotgit.go | 20 +- .../go-git.v4/storage/filesystem/index.go | 3 +- .../go-git.v4/storage/filesystem/object.go | 145 +- .../go-git.v4/storage/filesystem/storage.go | 4 +- .../src-d/go-git.v4/utils/binary/read.go | 15 + vendor/gopkg.in/src-d/go-git.v4/worktree.go | 4 +- vendor/modules.txt | 23 +- 270 files changed, 71049 insertions(+), 14434 deletions(-) create mode 100644 vendor/github.com/xanzy/ssh-agent/go.mod create mode 100644 vendor/github.com/xanzy/ssh-agent/go.sum create mode 100644 vendor/golang.org/x/crypto/ed25519/ed25519_go113.go create mode 100644 vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s create mode 100644 vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s create mode 100644 vendor/golang.org/x/crypto/ssh/ssh_gss.go delete mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go create mode 100644 vendor/golang.org/x/net/idna/idna10.0.0.go create mode 100644 vendor/golang.org/x/net/idna/idna9.0.0.go create mode 100644 vendor/golang.org/x/net/idna/punycode.go create mode 100644 vendor/golang.org/x/net/idna/tables10.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables11.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables9.0.0.go create mode 100644 vendor/golang.org/x/net/idna/trie.go create mode 100644 vendor/golang.org/x/net/idna/trieval.go create mode 100644 vendor/golang.org/x/net/internal/socks/client.go create mode 100644 vendor/golang.org/x/net/internal/socks/socks.go create mode 100644 vendor/golang.org/x/net/proxy/dial.go create mode 100644 vendor/golang.org/x/net/proxy/direct.go create mode 100644 vendor/golang.org/x/net/proxy/per_host.go create mode 100644 vendor/golang.org/x/net/proxy/proxy.go create mode 100644 vendor/golang.org/x/net/proxy/socks5.go create mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_riscv64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/mksysctl_openbsd.go delete mode 100644 vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl rename vendor/golang.org/x/sys/unix/{openbsd_pledge.go => pledge_openbsd.go} (98%) create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go rename vendor/golang.org/x/sys/unix/{openbsd_unveil.go => unveil_openbsd.go} (98%) create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/windows/mkerrors.bash create mode 100644 vendor/golang.org/x/sys/windows/mkknownfolderids.bash create mode 100644 vendor/golang.org/x/sys/windows/zerrors_windows.go create mode 100644 vendor/golang.org/x/sys/windows/zknownfolderids_windows.go rename vendor/golang.org/x/text/{ => internal}/language/common.go (50%) create mode 100644 vendor/golang.org/x/text/internal/language/compact.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/compact.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/gen.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/gen_index.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/gen_parents.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/language.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/parents.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/tables.go create mode 100644 vendor/golang.org/x/text/internal/language/compact/tags.go create mode 100644 vendor/golang.org/x/text/internal/language/compose.go create mode 100644 vendor/golang.org/x/text/internal/language/coverage.go create mode 100644 vendor/golang.org/x/text/internal/language/gen.go rename vendor/golang.org/x/text/{ => internal}/language/gen_common.go (60%) create mode 100644 vendor/golang.org/x/text/internal/language/language.go rename vendor/golang.org/x/text/{ => internal}/language/lookup.go (80%) create mode 100644 vendor/golang.org/x/text/internal/language/match.go create mode 100644 vendor/golang.org/x/text/internal/language/parse.go create mode 100644 vendor/golang.org/x/text/internal/language/tables.go create mode 100644 vendor/golang.org/x/text/internal/language/tags.go delete mode 100644 vendor/golang.org/x/text/language/Makefile delete mode 100644 vendor/golang.org/x/text/language/gen_index.go delete mode 100644 vendor/golang.org/x/text/language/index.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/bidi.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/bracket.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/core.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/gen.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/gen_ranges.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/gen_trieval.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/prop.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/trieval.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables11.0.0.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs_filtered.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/common.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/merge_base.go diff --git a/go.mod b/go.mod index 4f68a6b964..b1a638ed74 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 // indirect github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect + github.com/gliderlabs/ssh v0.1.4 // indirect github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd // indirect github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 @@ -60,6 +61,7 @@ require ( github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 github.com/gogo/protobuf v1.2.1 // indirect + github.com/google/go-cmp v0.3.0 // indirect github.com/google/go-github/v24 v24.0.1 github.com/gorilla/context v1.1.1 github.com/issue9/assert v1.3.2 // indirect @@ -90,7 +92,6 @@ require ( github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 github.com/oliamb/cutter v0.2.2 github.com/philhofer/fwd v1.0.0 // indirect - github.com/pkg/errors v0.8.1 // indirect github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e github.com/prometheus/client_golang v0.9.0 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect @@ -115,11 +116,12 @@ require ( github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 go.etcd.io/bbolt v1.3.2 // indirect - golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 - golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 + golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 + golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 - golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e - golang.org/x/text v0.3.0 + golang.org/x/sys v0.0.0-20190618155005-516e3c20635f + golang.org/x/text v0.3.2 + golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect @@ -130,7 +132,7 @@ require ( gopkg.in/macaron.v1 v1.3.2 gopkg.in/redis.v2 v2.3.2 // indirect gopkg.in/src-d/go-billy.v4 v4.3.0 - gopkg.in/src-d/go-git.v4 v4.11.0 + gopkg.in/src-d/go-git.v4 v4.12.0 gopkg.in/testfixtures.v2 v2.5.0 mvdan.cc/xurls/v2 v2.0.0 strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a diff --git a/go.sum b/go.sum index 7f042aecf1..f6542fbe49 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 h1:4jHLmof+Hb github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470/go.mod h1:3I+3V7B6gTBYfdpYgIG2ymALS9H+5VDKUl3lHH7ToM4= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= @@ -62,7 +64,6 @@ github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac h1:xrQJVwQCGqDvOO github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/etcd-io/bbolt v1.3.2 h1:RLRQ0TKLX7DlBRXAJHvbmXL17Q3KNnTBtZ9B6Qo+/Y0= @@ -89,8 +90,9 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjr github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.1.4 h1:5N8AYXpaQAPy0L7linKa5aI+WRfyYagAhjksVzxh+mI= +github.com/gliderlabs/ssh v0.1.4/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y= @@ -138,6 +140,8 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v24 v24.0.1 h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju57UR4Q4= @@ -230,8 +234,8 @@ github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a h1:d18LCO3ctH2kugUqt0pEyKKP8L+IYrocaPqGFilhTKk= github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY= @@ -315,8 +319,8 @@ github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 h1:E8u341JM/N8LCnPXBV6ZFD1RKo/j+qHl1XOqSV+GstA= github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= -github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 h1:HsIQ6yAjfjQ3IxPGrTusxp6Qxn92gNVq2x5CbvQvx3w= github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53/go.mod h1:f6elajwZV+xceiaqgRL090YzLEDGSbqr3poGL3ZgXYo= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= @@ -324,32 +328,51 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 h1:x6rhz8Y9CjbgQkccRGmELH6K+LJj7tOoh3XWeC1yaQM= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h5Hmyb5+VDjEiMufAEAM04= golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190618155005-516e3c20635f h1:dHNZYIYdq2QuU6w73vZ/DzesPbVlZVYZTtTZmrnsbQ8= +golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635 h1:2eB4G6bDQDeP69ZXbOKC00S2Kf6TIiRS+DzfKsKeQU0= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a h1:aQmaYPOmKItb96VioBrTlYay5tSNUdKAFEhPCWMeLSM= +golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -376,13 +399,12 @@ gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= gopkg.in/macaron.v1 v1.3.2/go.mod h1:PrsiawTWAGZs6wFbT5hlr7SQ2Ns9h7cUVtcUu4lQOVo= gopkg.in/redis.v2 v2.3.2 h1:GPVIIB/JnL1wvfULefy3qXmPu1nfNu2d0yA09FHgwfs= gopkg.in/redis.v2 v2.3.2/go.mod h1:4wl9PJ/CqzeHk3LVq1hNLHH8krm3+AXEgut4jVc++LU= -gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek= gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= -gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs= -gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU= -gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8= +gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4= gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M= gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU= gopkg.in/testfixtures.v2 v2.5.0 h1:N08B7l2GzFQenyYbzqthDnKAA+cmb17iAZhhFxr7JHw= diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go index fb87bef94f..25378537ea 100644 --- a/vendor/github.com/mitchellh/go-homedir/homedir.go +++ b/vendor/github.com/mitchellh/go-homedir/homedir.go @@ -76,6 +76,16 @@ func Expand(path string) (string, error) { return filepath.Join(dir, path[1:]), nil } +// Reset clears the cache, forcing the next call to Dir to re-detect +// the home directory. This generally never has to be called, but can be +// useful in tests if you're modifying the home directory via the HOME +// env var or something. +func Reset() { + cacheLock.Lock() + defer cacheLock.Unlock() + homedirCache = "" +} + func dirUnix() (string, error) { homeEnv := "HOME" if runtime.GOOS == "plan9" { diff --git a/vendor/github.com/xanzy/ssh-agent/go.mod b/vendor/github.com/xanzy/ssh-agent/go.mod new file mode 100644 index 0000000000..6664c4888e --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/go.mod @@ -0,0 +1,6 @@ +module github.com/xanzy/ssh-agent + +require ( + golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 + golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 // indirect +) diff --git a/vendor/github.com/xanzy/ssh-agent/go.sum b/vendor/github.com/xanzy/ssh-agent/go.sum new file mode 100644 index 0000000000..a9a0016921 --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/go.sum @@ -0,0 +1,4 @@ +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 h1:NwxKRvbkH5MsNkvOtPZi3/3kmI8CAzs3mtv+GLQMkNo= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 h1:bzeyCHgoAyjZjAhvTpks+qM7sdlh4cCSitmXeCEO3B4= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go index a50d9bfc95..e562609cc7 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go @@ -32,6 +32,7 @@ import ( "time" "golang.org/x/crypto/acme" + "golang.org/x/net/idna" ) // createCertRetryAfter is how much time to wait before removing a failed state @@ -62,10 +63,16 @@ type HostPolicy func(ctx context.Context, host string) error // HostWhitelist returns a policy where only the specified host names are allowed. // Only exact matches are currently supported. Subdomains, regexp or wildcard // will not match. +// +// Note that all hosts will be converted to Punycode via idna.Lookup.ToASCII so that +// Manager.GetCertificate can handle the Unicode IDN and mixedcase hosts correctly. +// Invalid hosts will be silently ignored. func HostWhitelist(hosts ...string) HostPolicy { whitelist := make(map[string]bool, len(hosts)) for _, h := range hosts { - whitelist[h] = true + if h, err := idna.Lookup.ToASCII(h); err == nil { + whitelist[h] = true + } } return func(_ context.Context, host string) error { if !whitelist[host] { @@ -243,7 +250,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, if !strings.Contains(strings.Trim(name, "."), ".") { return nil, errors.New("acme/autocert: server name component count invalid") } - if strings.ContainsAny(name, `+/\`) { + + // Note that this conversion is necessary because some server names in the handshakes + // started by some clients (such as cURL) are not converted to Punycode, which will + // prevent us from obtaining certificates for them. In addition, we should also treat + // example.com and EXAMPLE.COM as equivalent and return the same certificate for them. + // Fortunately, this conversion also helped us deal with this kind of mixedcase problems. + // + // Due to the "σςΣ" problem (see https://unicode.org/faq/idn.html#22), we can't use + // idna.Punycode.ToASCII (or just idna.ToASCII) here. + name, err := idna.Lookup.ToASCII(name) + if err != nil { return nil, errors.New("acme/autocert: server name contains invalid character") } diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go index d6f683ba3f..c7f8c7e64e 100644 --- a/vendor/golang.org/x/crypto/ed25519/ed25519.go +++ b/vendor/golang.org/x/crypto/ed25519/ed25519.go @@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// In Go 1.13, the ed25519 package was promoted to the standard library as +// crypto/ed25519, and this package became a wrapper for the standard library one. +// +// +build !go1.13 + // Package ed25519 implements the Ed25519 signature algorithm. See // https://ed25519.cr.yp.to/. // diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519_go113.go b/vendor/golang.org/x/crypto/ed25519/ed25519_go113.go new file mode 100644 index 0000000000..d1448d8d22 --- /dev/null +++ b/vendor/golang.org/x/crypto/ed25519/ed25519_go113.go @@ -0,0 +1,73 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.13 + +// Package ed25519 implements the Ed25519 signature algorithm. See +// https://ed25519.cr.yp.to/. +// +// These functions are also compatible with the “Ed25519” function defined in +// RFC 8032. However, unlike RFC 8032's formulation, this package's private key +// representation includes a public key suffix to make multiple signing +// operations with the same key more efficient. This package refers to the RFC +// 8032 private key as the “seed”. +// +// Beginning with Go 1.13, the functionality of this package was moved to the +// standard library as crypto/ed25519. This package only acts as a compatibility +// wrapper. +package ed25519 + +import ( + "crypto/ed25519" + "io" +) + +const ( + // PublicKeySize is the size, in bytes, of public keys as used in this package. + PublicKeySize = 32 + // PrivateKeySize is the size, in bytes, of private keys as used in this package. + PrivateKeySize = 64 + // SignatureSize is the size, in bytes, of signatures generated and verified by this package. + SignatureSize = 64 + // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. + SeedSize = 32 +) + +// PublicKey is the type of Ed25519 public keys. +// +// This type is an alias for crypto/ed25519's PublicKey type. +// See the crypto/ed25519 package for the methods on this type. +type PublicKey = ed25519.PublicKey + +// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. +// +// This type is an alias for crypto/ed25519's PrivateKey type. +// See the crypto/ed25519 package for the methods on this type. +type PrivateKey = ed25519.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { + return ed25519.GenerateKey(rand) +} + +// NewKeyFromSeed calculates a private key from a seed. It will panic if +// len(seed) is not SeedSize. This function is provided for interoperability +// with RFC 8032. RFC 8032's private keys correspond to seeds in this +// package. +func NewKeyFromSeed(seed []byte) PrivateKey { + return ed25519.NewKeyFromSeed(seed) +} + +// Sign signs the message with privateKey and returns a signature. It will +// panic if len(privateKey) is not PrivateKeySize. +func Sign(privateKey PrivateKey, message []byte) []byte { + return ed25519.Sign(privateKey, message) +} + +// Verify reports whether sig is a valid signature of message by publicKey. It +// will panic if len(publicKey) is not PublicKeySize. +func Verify(publicKey PublicKey, message, sig []byte) bool { + return ed25519.Verify(publicKey, message, sig) +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s b/vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s new file mode 100644 index 0000000000..cde3fc989b --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s @@ -0,0 +1,668 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Based on CRYPTOGAMS code with the following comment: +// # ==================================================================== +// # Written by Andy Polyakov for the OpenSSL +// # project. The module is, however, dual licensed under OpenSSL and +// # CRYPTOGAMS licenses depending on where you obtain it. For further +// # details see http://www.openssl.org/~appro/cryptogams/. +// # ==================================================================== + +// Original code can be found at the link below: +// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff + +// There are some differences between CRYPTOGAMS code and this one. The round +// loop for "_int" isn't the same as the original. Some adjustments were +// necessary because there are less vector registers available. For example, some +// X variables (r12, r13, r14, and r15) share the same register used by the +// counter. The original code uses ctr to name the counter. Here we use CNT +// because golang uses CTR as the counter register name. + +// +build ppc64le,!gccgo,!appengine + +#include "textflag.h" + +#define OUT R3 +#define INP R4 +#define LEN R5 +#define KEY R6 +#define CNT R7 + +#define TEMP R8 + +#define X0 R11 +#define X1 R12 +#define X2 R14 +#define X3 R15 +#define X4 R16 +#define X5 R17 +#define X6 R18 +#define X7 R19 +#define X8 R20 +#define X9 R21 +#define X10 R22 +#define X11 R23 +#define X12 R24 +#define X13 R25 +#define X14 R26 +#define X15 R27 + +#define CON0 X0 +#define CON1 X1 +#define CON2 X2 +#define CON3 X3 + +#define KEY0 X4 +#define KEY1 X5 +#define KEY2 X6 +#define KEY3 X7 +#define KEY4 X8 +#define KEY5 X9 +#define KEY6 X10 +#define KEY7 X11 + +#define CNT0 X12 +#define CNT1 X13 +#define CNT2 X14 +#define CNT3 X15 + +#define TMP0 R9 +#define TMP1 R10 +#define TMP2 R28 +#define TMP3 R29 + +#define CONSTS R8 + +#define A0 V0 +#define B0 V1 +#define C0 V2 +#define D0 V3 +#define A1 V4 +#define B1 V5 +#define C1 V6 +#define D1 V7 +#define A2 V8 +#define B2 V9 +#define C2 V10 +#define D2 V11 +#define T0 V12 +#define T1 V13 +#define T2 V14 + +#define K0 V15 +#define K1 V16 +#define K2 V17 +#define K3 V18 +#define K4 V19 +#define K5 V20 + +#define FOUR V21 +#define SIXTEEN V22 +#define TWENTY4 V23 +#define TWENTY V24 +#define TWELVE V25 +#define TWENTY5 V26 +#define SEVEN V27 + +#define INPPERM V28 +#define OUTPERM V29 +#define OUTMASK V30 + +#define DD0 V31 +#define DD1 SEVEN +#define DD2 T0 +#define DD3 T1 +#define DD4 T2 + +DATA ·consts+0x00(SB)/8, $0x3320646e61707865 +DATA ·consts+0x08(SB)/8, $0x6b20657479622d32 +DATA ·consts+0x10(SB)/8, $0x0000000000000001 +DATA ·consts+0x18(SB)/8, $0x0000000000000000 +DATA ·consts+0x20(SB)/8, $0x0000000000000004 +DATA ·consts+0x28(SB)/8, $0x0000000000000000 +DATA ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d +DATA ·consts+0x38(SB)/8, $0x0203000106070405 +DATA ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c +DATA ·consts+0x48(SB)/8, $0x0102030005060704 +GLOBL ·consts(SB), RODATA, $80 + +//func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte) +TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0 + // Load the arguments inside the registers + MOVD out+0(FP), OUT + MOVD inp+8(FP), INP + MOVD len+16(FP), LEN + MOVD key+24(FP), KEY + MOVD counter+32(FP), CNT + + MOVD $·consts(SB), CONSTS // point to consts addr + + MOVD $16, X0 + MOVD $32, X1 + MOVD $48, X2 + MOVD $64, X3 + MOVD $31, X4 + MOVD $15, X5 + + // Load key + LVX (KEY)(R0), K1 + LVSR (KEY)(R0), T0 + LVX (KEY)(X0), K2 + LVX (KEY)(X4), DD0 + + // Load counter + LVX (CNT)(R0), K3 + LVSR (CNT)(R0), T1 + LVX (CNT)(X5), DD1 + + // Load constants + LVX (CONSTS)(R0), K0 + LVX (CONSTS)(X0), K5 + LVX (CONSTS)(X1), FOUR + LVX (CONSTS)(X2), SIXTEEN + LVX (CONSTS)(X3), TWENTY4 + + // Align key and counter + VPERM K2, K1, T0, K1 + VPERM DD0, K2, T0, K2 + VPERM DD1, K3, T1, K3 + + // Load counter to GPR + MOVWZ 0(CNT), CNT0 + MOVWZ 4(CNT), CNT1 + MOVWZ 8(CNT), CNT2 + MOVWZ 12(CNT), CNT3 + + // Adjust vectors for the initial state + VADDUWM K3, K5, K3 + VADDUWM K3, K5, K4 + VADDUWM K4, K5, K5 + + // Synthesized constants + VSPLTISW $-12, TWENTY + VSPLTISW $12, TWELVE + VSPLTISW $-7, TWENTY5 + + VXOR T0, T0, T0 + VSPLTISW $-1, OUTMASK + LVSR (INP)(R0), INPPERM + LVSL (OUT)(R0), OUTPERM + VPERM OUTMASK, T0, OUTPERM, OUTMASK + +loop_outer_vmx: + // Load constant + MOVD $0x61707865, CON0 + MOVD $0x3320646e, CON1 + MOVD $0x79622d32, CON2 + MOVD $0x6b206574, CON3 + + VOR K0, K0, A0 + VOR K0, K0, A1 + VOR K0, K0, A2 + VOR K1, K1, B0 + + MOVD $10, TEMP + + // Load key to GPR + MOVWZ 0(KEY), X4 + MOVWZ 4(KEY), X5 + MOVWZ 8(KEY), X6 + MOVWZ 12(KEY), X7 + VOR K1, K1, B1 + VOR K1, K1, B2 + MOVWZ 16(KEY), X8 + MOVWZ 0(CNT), X12 + MOVWZ 20(KEY), X9 + MOVWZ 4(CNT), X13 + VOR K2, K2, C0 + VOR K2, K2, C1 + MOVWZ 24(KEY), X10 + MOVWZ 8(CNT), X14 + VOR K2, K2, C2 + VOR K3, K3, D0 + MOVWZ 28(KEY), X11 + MOVWZ 12(CNT), X15 + VOR K4, K4, D1 + VOR K5, K5, D2 + + MOVD X4, TMP0 + MOVD X5, TMP1 + MOVD X6, TMP2 + MOVD X7, TMP3 + VSPLTISW $7, SEVEN + + MOVD TEMP, CTR + +loop_vmx: + // CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible + // using assembly macros. Therefore, the macro expansion result was used + // in order to maintain the algorithm efficiency. + // This loop generates three keystream blocks using VMX instructions and, + // in parallel, one keystream block using scalar instructions. + ADD X4, X0, X0 + ADD X5, X1, X1 + VADDUWM A0, B0, A0 + VADDUWM A1, B1, A1 + ADD X6, X2, X2 + ADD X7, X3, X3 + VADDUWM A2, B2, A2 + VXOR D0, A0, D0 + XOR X0, X12, X12 + XOR X1, X13, X13 + VXOR D1, A1, D1 + VXOR D2, A2, D2 + XOR X2, X14, X14 + XOR X3, X15, X15 + VPERM D0, D0, SIXTEEN, D0 + VPERM D1, D1, SIXTEEN, D1 + ROTLW $16, X12, X12 + ROTLW $16, X13, X13 + VPERM D2, D2, SIXTEEN, D2 + VADDUWM C0, D0, C0 + ROTLW $16, X14, X14 + ROTLW $16, X15, X15 + VADDUWM C1, D1, C1 + VADDUWM C2, D2, C2 + ADD X12, X8, X8 + ADD X13, X9, X9 + VXOR B0, C0, T0 + VXOR B1, C1, T1 + ADD X14, X10, X10 + ADD X15, X11, X11 + VXOR B2, C2, T2 + VRLW T0, TWELVE, B0 + XOR X8, X4, X4 + XOR X9, X5, X5 + VRLW T1, TWELVE, B1 + VRLW T2, TWELVE, B2 + XOR X10, X6, X6 + XOR X11, X7, X7 + VADDUWM A0, B0, A0 + VADDUWM A1, B1, A1 + ROTLW $12, X4, X4 + ROTLW $12, X5, X5 + VADDUWM A2, B2, A2 + VXOR D0, A0, D0 + ROTLW $12, X6, X6 + ROTLW $12, X7, X7 + VXOR D1, A1, D1 + VXOR D2, A2, D2 + ADD X4, X0, X0 + ADD X5, X1, X1 + VPERM D0, D0, TWENTY4, D0 + VPERM D1, D1, TWENTY4, D1 + ADD X6, X2, X2 + ADD X7, X3, X3 + VPERM D2, D2, TWENTY4, D2 + VADDUWM C0, D0, C0 + XOR X0, X12, X12 + XOR X1, X13, X13 + VADDUWM C1, D1, C1 + VADDUWM C2, D2, C2 + XOR X2, X14, X14 + XOR X3, X15, X15 + VXOR B0, C0, T0 + VXOR B1, C1, T1 + ROTLW $8, X12, X12 + ROTLW $8, X13, X13 + VXOR B2, C2, T2 + VRLW T0, SEVEN, B0 + ROTLW $8, X14, X14 + ROTLW $8, X15, X15 + VRLW T1, SEVEN, B1 + VRLW T2, SEVEN, B2 + ADD X12, X8, X8 + ADD X13, X9, X9 + VSLDOI $8, C0, C0, C0 + VSLDOI $8, C1, C1, C1 + ADD X14, X10, X10 + ADD X15, X11, X11 + VSLDOI $8, C2, C2, C2 + VSLDOI $12, B0, B0, B0 + XOR X8, X4, X4 + XOR X9, X5, X5 + VSLDOI $12, B1, B1, B1 + VSLDOI $12, B2, B2, B2 + XOR X10, X6, X6 + XOR X11, X7, X7 + VSLDOI $4, D0, D0, D0 + VSLDOI $4, D1, D1, D1 + ROTLW $7, X4, X4 + ROTLW $7, X5, X5 + VSLDOI $4, D2, D2, D2 + VADDUWM A0, B0, A0 + ROTLW $7, X6, X6 + ROTLW $7, X7, X7 + VADDUWM A1, B1, A1 + VADDUWM A2, B2, A2 + ADD X5, X0, X0 + ADD X6, X1, X1 + VXOR D0, A0, D0 + VXOR D1, A1, D1 + ADD X7, X2, X2 + ADD X4, X3, X3 + VXOR D2, A2, D2 + VPERM D0, D0, SIXTEEN, D0 + XOR X0, X15, X15 + XOR X1, X12, X12 + VPERM D1, D1, SIXTEEN, D1 + VPERM D2, D2, SIXTEEN, D2 + XOR X2, X13, X13 + XOR X3, X14, X14 + VADDUWM C0, D0, C0 + VADDUWM C1, D1, C1 + ROTLW $16, X15, X15 + ROTLW $16, X12, X12 + VADDUWM C2, D2, C2 + VXOR B0, C0, T0 + ROTLW $16, X13, X13 + ROTLW $16, X14, X14 + VXOR B1, C1, T1 + VXOR B2, C2, T2 + ADD X15, X10, X10 + ADD X12, X11, X11 + VRLW T0, TWELVE, B0 + VRLW T1, TWELVE, B1 + ADD X13, X8, X8 + ADD X14, X9, X9 + VRLW T2, TWELVE, B2 + VADDUWM A0, B0, A0 + XOR X10, X5, X5 + XOR X11, X6, X6 + VADDUWM A1, B1, A1 + VADDUWM A2, B2, A2 + XOR X8, X7, X7 + XOR X9, X4, X4 + VXOR D0, A0, D0 + VXOR D1, A1, D1 + ROTLW $12, X5, X5 + ROTLW $12, X6, X6 + VXOR D2, A2, D2 + VPERM D0, D0, TWENTY4, D0 + ROTLW $12, X7, X7 + ROTLW $12, X4, X4 + VPERM D1, D1, TWENTY4, D1 + VPERM D2, D2, TWENTY4, D2 + ADD X5, X0, X0 + ADD X6, X1, X1 + VADDUWM C0, D0, C0 + VADDUWM C1, D1, C1 + ADD X7, X2, X2 + ADD X4, X3, X3 + VADDUWM C2, D2, C2 + VXOR B0, C0, T0 + XOR X0, X15, X15 + XOR X1, X12, X12 + VXOR B1, C1, T1 + VXOR B2, C2, T2 + XOR X2, X13, X13 + XOR X3, X14, X14 + VRLW T0, SEVEN, B0 + VRLW T1, SEVEN, B1 + ROTLW $8, X15, X15 + ROTLW $8, X12, X12 + VRLW T2, SEVEN, B2 + VSLDOI $8, C0, C0, C0 + ROTLW $8, X13, X13 + ROTLW $8, X14, X14 + VSLDOI $8, C1, C1, C1 + VSLDOI $8, C2, C2, C2 + ADD X15, X10, X10 + ADD X12, X11, X11 + VSLDOI $4, B0, B0, B0 + VSLDOI $4, B1, B1, B1 + ADD X13, X8, X8 + ADD X14, X9, X9 + VSLDOI $4, B2, B2, B2 + VSLDOI $12, D0, D0, D0 + XOR X10, X5, X5 + XOR X11, X6, X6 + VSLDOI $12, D1, D1, D1 + VSLDOI $12, D2, D2, D2 + XOR X8, X7, X7 + XOR X9, X4, X4 + ROTLW $7, X5, X5 + ROTLW $7, X6, X6 + ROTLW $7, X7, X7 + ROTLW $7, X4, X4 + BC 0x10, 0, loop_vmx + + SUB $256, LEN, LEN + + // Accumulate key block + ADD $0x61707865, X0, X0 + ADD $0x3320646e, X1, X1 + ADD $0x79622d32, X2, X2 + ADD $0x6b206574, X3, X3 + ADD TMP0, X4, X4 + ADD TMP1, X5, X5 + ADD TMP2, X6, X6 + ADD TMP3, X7, X7 + MOVWZ 16(KEY), TMP0 + MOVWZ 20(KEY), TMP1 + MOVWZ 24(KEY), TMP2 + MOVWZ 28(KEY), TMP3 + ADD TMP0, X8, X8 + ADD TMP1, X9, X9 + ADD TMP2, X10, X10 + ADD TMP3, X11, X11 + + MOVWZ 12(CNT), TMP0 + MOVWZ 8(CNT), TMP1 + MOVWZ 4(CNT), TMP2 + MOVWZ 0(CNT), TEMP + ADD TMP0, X15, X15 + ADD TMP1, X14, X14 + ADD TMP2, X13, X13 + ADD TEMP, X12, X12 + + // Accumulate key block + VADDUWM A0, K0, A0 + VADDUWM A1, K0, A1 + VADDUWM A2, K0, A2 + VADDUWM B0, K1, B0 + VADDUWM B1, K1, B1 + VADDUWM B2, K1, B2 + VADDUWM C0, K2, C0 + VADDUWM C1, K2, C1 + VADDUWM C2, K2, C2 + VADDUWM D0, K3, D0 + VADDUWM D1, K4, D1 + VADDUWM D2, K5, D2 + + // Increment counter + ADD $4, TEMP, TEMP + MOVW TEMP, 0(CNT) + + VADDUWM K3, FOUR, K3 + VADDUWM K4, FOUR, K4 + VADDUWM K5, FOUR, K5 + + // XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3). + + // Load input (aligned or not) + MOVWZ 0(INP), TMP0 + MOVWZ 4(INP), TMP1 + MOVWZ 8(INP), TMP2 + MOVWZ 12(INP), TMP3 + + // XOR with input + XOR TMP0, X0, X0 + XOR TMP1, X1, X1 + XOR TMP2, X2, X2 + XOR TMP3, X3, X3 + MOVWZ 16(INP), TMP0 + MOVWZ 20(INP), TMP1 + MOVWZ 24(INP), TMP2 + MOVWZ 28(INP), TMP3 + XOR TMP0, X4, X4 + XOR TMP1, X5, X5 + XOR TMP2, X6, X6 + XOR TMP3, X7, X7 + MOVWZ 32(INP), TMP0 + MOVWZ 36(INP), TMP1 + MOVWZ 40(INP), TMP2 + MOVWZ 44(INP), TMP3 + XOR TMP0, X8, X8 + XOR TMP1, X9, X9 + XOR TMP2, X10, X10 + XOR TMP3, X11, X11 + MOVWZ 48(INP), TMP0 + MOVWZ 52(INP), TMP1 + MOVWZ 56(INP), TMP2 + MOVWZ 60(INP), TMP3 + XOR TMP0, X12, X12 + XOR TMP1, X13, X13 + XOR TMP2, X14, X14 + XOR TMP3, X15, X15 + + // Store output (aligned or not) + MOVW X0, 0(OUT) + MOVW X1, 4(OUT) + MOVW X2, 8(OUT) + MOVW X3, 12(OUT) + + ADD $64, INP, INP // INP points to the end of the slice for the alignment code below + + MOVW X4, 16(OUT) + MOVD $16, TMP0 + MOVW X5, 20(OUT) + MOVD $32, TMP1 + MOVW X6, 24(OUT) + MOVD $48, TMP2 + MOVW X7, 28(OUT) + MOVD $64, TMP3 + MOVW X8, 32(OUT) + MOVW X9, 36(OUT) + MOVW X10, 40(OUT) + MOVW X11, 44(OUT) + MOVW X12, 48(OUT) + MOVW X13, 52(OUT) + MOVW X14, 56(OUT) + MOVW X15, 60(OUT) + ADD $64, OUT, OUT + + // Load input + LVX (INP)(R0), DD0 + LVX (INP)(TMP0), DD1 + LVX (INP)(TMP1), DD2 + LVX (INP)(TMP2), DD3 + LVX (INP)(TMP3), DD4 + ADD $64, INP, INP + + VPERM DD1, DD0, INPPERM, DD0 // Align input + VPERM DD2, DD1, INPPERM, DD1 + VPERM DD3, DD2, INPPERM, DD2 + VPERM DD4, DD3, INPPERM, DD3 + VXOR A0, DD0, A0 // XOR with input + VXOR B0, DD1, B0 + LVX (INP)(TMP0), DD1 // Keep loading input + VXOR C0, DD2, C0 + LVX (INP)(TMP1), DD2 + VXOR D0, DD3, D0 + LVX (INP)(TMP2), DD3 + LVX (INP)(TMP3), DD0 + ADD $64, INP, INP + MOVD $63, TMP3 // 63 is not a typo + VPERM A0, A0, OUTPERM, A0 + VPERM B0, B0, OUTPERM, B0 + VPERM C0, C0, OUTPERM, C0 + VPERM D0, D0, OUTPERM, D0 + + VPERM DD1, DD4, INPPERM, DD4 // Align input + VPERM DD2, DD1, INPPERM, DD1 + VPERM DD3, DD2, INPPERM, DD2 + VPERM DD0, DD3, INPPERM, DD3 + VXOR A1, DD4, A1 + VXOR B1, DD1, B1 + LVX (INP)(TMP0), DD1 // Keep loading + VXOR C1, DD2, C1 + LVX (INP)(TMP1), DD2 + VXOR D1, DD3, D1 + LVX (INP)(TMP2), DD3 + + // Note that the LVX address is always rounded down to the nearest 16-byte + // boundary, and that it always points to at most 15 bytes beyond the end of + // the slice, so we cannot cross a page boundary. + LVX (INP)(TMP3), DD4 // Redundant in aligned case. + ADD $64, INP, INP + VPERM A1, A1, OUTPERM, A1 // Pre-misalign output + VPERM B1, B1, OUTPERM, B1 + VPERM C1, C1, OUTPERM, C1 + VPERM D1, D1, OUTPERM, D1 + + VPERM DD1, DD0, INPPERM, DD0 // Align Input + VPERM DD2, DD1, INPPERM, DD1 + VPERM DD3, DD2, INPPERM, DD2 + VPERM DD4, DD3, INPPERM, DD3 + VXOR A2, DD0, A2 + VXOR B2, DD1, B2 + VXOR C2, DD2, C2 + VXOR D2, DD3, D2 + VPERM A2, A2, OUTPERM, A2 + VPERM B2, B2, OUTPERM, B2 + VPERM C2, C2, OUTPERM, C2 + VPERM D2, D2, OUTPERM, D2 + + ANDCC $15, OUT, X1 // Is out aligned? + MOVD OUT, X0 + + VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output + VSEL B0, C0, OUTMASK, DD1 + VSEL C0, D0, OUTMASK, DD2 + VSEL D0, A1, OUTMASK, DD3 + VSEL A1, B1, OUTMASK, B0 + VSEL B1, C1, OUTMASK, C0 + VSEL C1, D1, OUTMASK, D0 + VSEL D1, A2, OUTMASK, A1 + VSEL A2, B2, OUTMASK, B1 + VSEL B2, C2, OUTMASK, C1 + VSEL C2, D2, OUTMASK, D1 + + STVX DD0, (OUT+TMP0) + STVX DD1, (OUT+TMP1) + STVX DD2, (OUT+TMP2) + ADD $64, OUT, OUT + STVX DD3, (OUT+R0) + STVX B0, (OUT+TMP0) + STVX C0, (OUT+TMP1) + STVX D0, (OUT+TMP2) + ADD $64, OUT, OUT + STVX A1, (OUT+R0) + STVX B1, (OUT+TMP0) + STVX C1, (OUT+TMP1) + STVX D1, (OUT+TMP2) + ADD $64, OUT, OUT + + BEQ aligned_vmx + + SUB X1, OUT, X2 // in misaligned case edges + MOVD $0, X3 // are written byte-by-byte + +unaligned_tail_vmx: + STVEBX D2, (X2+X3) + ADD $1, X3, X3 + CMPW X3, X1 + BNE unaligned_tail_vmx + SUB X1, X0, X2 + +unaligned_head_vmx: + STVEBX A0, (X2+X1) + CMPW X1, $15 + ADD $1, X1, X1 + BNE unaligned_head_vmx + + CMPU LEN, $255 // done with 256-byte block yet? + BGT loop_outer_vmx + + JMP done_vmx + +aligned_vmx: + STVX A0, (X0+R0) + CMPU LEN, $255 // done with 256-byte block yet? + BGT loop_outer_vmx + +done_vmx: + RET diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go index 47eac0314c..bf8beba670 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !arm64,!s390x arm64,!go1.11 gccgo appengine +// +build !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine package chacha20 diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go new file mode 100644 index 0000000000..638cb5e5de --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go @@ -0,0 +1,52 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ppc64le,!gccgo,!appengine + +package chacha20 + +import "encoding/binary" + +const ( + bufSize = 256 + haveAsm = true +) + +//go:noescape +func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32) + +func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { + if len(src) >= bufSize { + chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter) + } + if len(src)%bufSize != 0 { + chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter) + start := len(src) - len(src)%bufSize + ts, td, tb := src[start:], dst[start:], c.buf[:] + // Unroll loop to XOR 32 bytes per iteration. + for i := 0; i < len(ts)-32; i += 32 { + td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination + s0 := binary.LittleEndian.Uint64(ts[0:8]) + s1 := binary.LittleEndian.Uint64(ts[8:16]) + s2 := binary.LittleEndian.Uint64(ts[16:24]) + s3 := binary.LittleEndian.Uint64(ts[24:32]) + b0 := binary.LittleEndian.Uint64(tb[0:8]) + b1 := binary.LittleEndian.Uint64(tb[8:16]) + b2 := binary.LittleEndian.Uint64(tb[16:24]) + b3 := binary.LittleEndian.Uint64(tb[24:32]) + binary.LittleEndian.PutUint64(td[0:8], s0^b0) + binary.LittleEndian.PutUint64(td[8:16], s1^b1) + binary.LittleEndian.PutUint64(td[16:24], s2^b2) + binary.LittleEndian.PutUint64(td[24:32], s3^b3) + ts, td, tb = ts[32:], td[32:], tb[32:] + } + td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination + for i, v := range ts { + td[i] = tb[i] ^ v + } + c.len = bufSize - (len(src) % bufSize) + + } + +} diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go index 3e2518600e..faa2fb3693 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ b/vendor/golang.org/x/crypto/openpgp/keys.go @@ -504,7 +504,7 @@ const defaultRSAKeyBits = 2048 // which may be empty but must not contain any of "()<>\x00". // If config is nil, sensible defaults will be used. func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { - currentTime := config.Now() + creationTime := config.Now() bits := defaultRSAKeyBits if config != nil && config.RSABits != 0 { @@ -525,8 +525,8 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err } e := &Entity{ - PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey), - PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv), + PrimaryKey: packet.NewRSAPublicKey(creationTime, &signingPriv.PublicKey), + PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv), Identities: make(map[string]*Identity), } isPrimaryId := true @@ -534,7 +534,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err Name: uid.Id, UserId: uid, SelfSignature: &packet.Signature{ - CreationTime: currentTime, + CreationTime: creationTime, SigType: packet.SigTypePositiveCert, PubKeyAlgo: packet.PubKeyAlgoRSA, Hash: config.Hash(), @@ -563,10 +563,10 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err e.Subkeys = make([]Subkey, 1) e.Subkeys[0] = Subkey{ - PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), - PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv), + PublicKey: packet.NewRSAPublicKey(creationTime, &encryptingPriv.PublicKey), + PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv), Sig: &packet.Signature{ - CreationTime: currentTime, + CreationTime: creationTime, SigType: packet.SigTypeSubkeyBinding, PubKeyAlgo: packet.PubKeyAlgoRSA, Hash: config.Hash(), diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go index bd31cceac6..6f8ec09384 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go @@ -36,49 +36,49 @@ type PrivateKey struct { iv []byte } -func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey { +func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey { pk := new(PrivateKey) - pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey) + pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey) pk.PrivateKey = priv return pk } -func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey { +func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey { pk := new(PrivateKey) - pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey) + pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey) pk.PrivateKey = priv return pk } -func NewElGamalPrivateKey(currentTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { +func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { pk := new(PrivateKey) - pk.PublicKey = *NewElGamalPublicKey(currentTime, &priv.PublicKey) + pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey) pk.PrivateKey = priv return pk } -func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { +func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { pk := new(PrivateKey) - pk.PublicKey = *NewECDSAPublicKey(currentTime, &priv.PublicKey) + pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey) pk.PrivateKey = priv return pk } // NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that // implements RSA or ECDSA. -func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { +func NewSignerPrivateKey(creationTime time.Time, signer crypto.Signer) *PrivateKey { pk := new(PrivateKey) // In general, the public Keys should be used as pointers. We still // type-switch on the values, for backwards-compatibility. switch pubkey := signer.Public().(type) { case *rsa.PublicKey: - pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) + pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey) case rsa.PublicKey: - pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) + pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey) case *ecdsa.PublicKey: - pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) + pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey) case ecdsa.PublicKey: - pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) + pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey) default: panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") } diff --git a/vendor/golang.org/x/crypto/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/poly1305/mac_noasm.go index 8387d29998..a8dd589ae3 100644 --- a/vendor/golang.org/x/crypto/poly1305/mac_noasm.go +++ b/vendor/golang.org/x/crypto/poly1305/mac_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 gccgo appengine +// +build !amd64,!ppc64le gccgo appengine package poly1305 diff --git a/vendor/golang.org/x/crypto/poly1305/sum_noasm.go b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go index fcdef46ab6..8a9c2070b9 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_noasm.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build s390x,!go1.11 !arm,!amd64,!s390x gccgo appengine nacl +// +build s390x,!go1.11 !arm,!amd64,!s390x,!ppc64le gccgo appengine nacl package poly1305 diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go new file mode 100644 index 0000000000..2402b6371b --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go @@ -0,0 +1,68 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ppc64le,!gccgo,!appengine + +package poly1305 + +//go:noescape +func initialize(state *[7]uint64, key *[32]byte) + +//go:noescape +func update(state *[7]uint64, msg []byte) + +//go:noescape +func finalize(tag *[TagSize]byte, state *[7]uint64) + +// Sum generates an authenticator for m using a one-time key and puts the +// 16-byte result into out. Authenticating two different messages with the same +// key allows an attacker to forge messages at will. +func Sum(out *[16]byte, m []byte, key *[32]byte) { + h := newMAC(key) + h.Write(m) + h.Sum(out) +} + +func newMAC(key *[32]byte) (h mac) { + initialize(&h.state, key) + return +} + +type mac struct { + state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 } + + buffer [TagSize]byte + offset int +} + +func (h *mac) Write(p []byte) (n int, err error) { + n = len(p) + if h.offset > 0 { + remaining := TagSize - h.offset + if n < remaining { + h.offset += copy(h.buffer[h.offset:], p) + return n, nil + } + copy(h.buffer[h.offset:], p[:remaining]) + p = p[remaining:] + h.offset = 0 + update(&h.state, h.buffer[:]) + } + if nn := len(p) - (len(p) % TagSize); nn > 0 { + update(&h.state, p[:nn]) + p = p[nn:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return n, nil +} + +func (h *mac) Sum(out *[16]byte) { + state := h.state + if h.offset > 0 { + update(&state, h.buffer[:h.offset]) + } + finalize(out, &state) +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s new file mode 100644 index 0000000000..55c7167ec9 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s @@ -0,0 +1,247 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ppc64le,!gccgo,!appengine + +#include "textflag.h" + +// This was ported from the amd64 implementation. + +#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \ + MOVD (msg), t0; \ + MOVD 8(msg), t1; \ + MOVD $1, t2; \ + ADDC t0, h0, h0; \ + ADDE t1, h1, h1; \ + ADDE t2, h2; \ + ADD $16, msg + +#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ + MULLD r0, h0, t0; \ + MULLD r0, h1, t4; \ + MULHDU r0, h0, t1; \ + MULHDU r0, h1, t5; \ + ADDC t4, t1, t1; \ + MULLD r0, h2, t2; \ + ADDZE t5; \ + MULHDU r1, h0, t4; \ + MULLD r1, h0, h0; \ + ADD t5, t2, t2; \ + ADDC h0, t1, t1; \ + MULLD h2, r1, t3; \ + ADDZE t4, h0; \ + MULHDU r1, h1, t5; \ + MULLD r1, h1, t4; \ + ADDC t4, t2, t2; \ + ADDE t5, t3, t3; \ + ADDC h0, t2, t2; \ + MOVD $-4, t4; \ + MOVD t0, h0; \ + MOVD t1, h1; \ + ADDZE t3; \ + ANDCC $3, t2, h2; \ + AND t2, t4, t0; \ + ADDC t0, h0, h0; \ + ADDE t3, h1, h1; \ + SLD $62, t3, t4; \ + SRD $2, t2; \ + ADDZE h2; \ + OR t4, t2, t2; \ + SRD $2, t3; \ + ADDC t2, h0, h0; \ + ADDE t3, h1, h1; \ + ADDZE h2 + +DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF +DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC +GLOBL ·poly1305Mask<>(SB), RODATA, $16 + +// func update(state *[7]uint64, msg []byte) + +TEXT ·update(SB), $0-32 + MOVD state+0(FP), R3 + MOVD msg_base+8(FP), R4 + MOVD msg_len+16(FP), R5 + + MOVD 0(R3), R8 // h0 + MOVD 8(R3), R9 // h1 + MOVD 16(R3), R10 // h2 + MOVD 24(R3), R11 // r0 + MOVD 32(R3), R12 // r1 + + CMP R5, $16 + BLT bytes_between_0_and_15 + +loop: + POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) + +multiply: + POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) + ADD $-16, R5 + CMP R5, $16 + BGE loop + +bytes_between_0_and_15: + CMP $0, R5 + BEQ done + MOVD $0, R16 // h0 + MOVD $0, R17 // h1 + +flush_buffer: + CMP R5, $8 + BLE just1 + + MOVD $8, R21 + SUB R21, R5, R21 + + // Greater than 8 -- load the rightmost remaining bytes in msg + // and put into R17 (h1) + MOVD (R4)(R21), R17 + MOVD $16, R22 + + // Find the offset to those bytes + SUB R5, R22, R22 + SLD $3, R22 + + // Shift to get only the bytes in msg + SRD R22, R17, R17 + + // Put 1 at high end + MOVD $1, R23 + SLD $3, R21 + SLD R21, R23, R23 + OR R23, R17, R17 + + // Remainder is 8 + MOVD $8, R5 + +just1: + CMP R5, $8 + BLT less8 + + // Exactly 8 + MOVD (R4), R16 + + CMP $0, R17 + + // Check if we've already set R17; if not + // set 1 to indicate end of msg. + BNE carry + MOVD $1, R17 + BR carry + +less8: + MOVD $0, R16 // h0 + MOVD $0, R22 // shift count + CMP R5, $4 + BLT less4 + MOVWZ (R4), R16 + ADD $4, R4 + ADD $-4, R5 + MOVD $32, R22 + +less4: + CMP R5, $2 + BLT less2 + MOVHZ (R4), R21 + SLD R22, R21, R21 + OR R16, R21, R16 + ADD $16, R22 + ADD $-2, R5 + ADD $2, R4 + +less2: + CMP $0, R5 + BEQ insert1 + MOVBZ (R4), R21 + SLD R22, R21, R21 + OR R16, R21, R16 + ADD $8, R22 + +insert1: + // Insert 1 at end of msg + MOVD $1, R21 + SLD R22, R21, R21 + OR R16, R21, R16 + +carry: + // Add new values to h0, h1, h2 + ADDC R16, R8 + ADDE R17, R9 + ADDE $0, R10 + MOVD $16, R5 + ADD R5, R4 + BR multiply + +done: + // Save h0, h1, h2 in state + MOVD R8, 0(R3) + MOVD R9, 8(R3) + MOVD R10, 16(R3) + RET + +// func initialize(state *[7]uint64, key *[32]byte) +TEXT ·initialize(SB), $0-16 + MOVD state+0(FP), R3 + MOVD key+8(FP), R4 + + // state[0...7] is initialized with zero + // Load key + MOVD 0(R4), R5 + MOVD 8(R4), R6 + MOVD 16(R4), R7 + MOVD 24(R4), R8 + + // Address of key mask + MOVD $·poly1305Mask<>(SB), R9 + + // Save original key in state + MOVD R7, 40(R3) + MOVD R8, 48(R3) + + // Get mask + MOVD (R9), R7 + MOVD 8(R9), R8 + + // And with key + AND R5, R7, R5 + AND R6, R8, R6 + + // Save masked key in state + MOVD R5, 24(R3) + MOVD R6, 32(R3) + RET + +// func finalize(tag *[TagSize]byte, state *[7]uint64) +TEXT ·finalize(SB), $0-16 + MOVD tag+0(FP), R3 + MOVD state+8(FP), R4 + + // Get h0, h1, h2 from state + MOVD 0(R4), R5 + MOVD 8(R4), R6 + MOVD 16(R4), R7 + + // Save h0, h1 + MOVD R5, R8 + MOVD R6, R9 + MOVD $3, R20 + MOVD $-1, R21 + SUBC $-5, R5 + SUBE R21, R6 + SUBE R20, R7 + MOVD $0, R21 + SUBZE R21 + + // Check for carry + CMP $0, R21 + ISEL $2, R5, R8, R5 + ISEL $2, R6, R9, R6 + MOVD 40(R4), R8 + MOVD 48(R4), R9 + ADDC R8, R5 + ADDE R9, R6 + MOVD R5, 0(R3) + MOVD R6, 8(R3) + RET diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go index 5f44b77403..0590070e22 100644 --- a/vendor/golang.org/x/crypto/ssh/client_auth.go +++ b/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -523,3 +523,117 @@ func (r *retryableAuthMethod) method() string { func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod { return &retryableAuthMethod{authMethod: auth, maxTries: maxTries} } + +// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication. +// See RFC 4462 section 3 +// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details. +// target is the server host you want to log in to. +func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod { + if gssAPIClient == nil { + panic("gss-api client must be not nil with enable gssapi-with-mic") + } + return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target} +} + +type gssAPIWithMICCallback struct { + gssAPIClient GSSAPIClient + target string +} + +func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { + m := &userAuthRequestMsg{ + User: user, + Service: serviceSSH, + Method: g.method(), + } + // The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST. + // See RFC 4462 section 3.2. + m.Payload = appendU32(m.Payload, 1) + m.Payload = appendString(m.Payload, string(krb5OID)) + if err := c.writePacket(Marshal(m)); err != nil { + return authFailure, nil, err + } + // The server responds to the SSH_MSG_USERAUTH_REQUEST with either an + // SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or + // with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE. + // See RFC 4462 section 3.3. + // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check + // selected mech if it is valid. + packet, err := c.readPacket() + if err != nil { + return authFailure, nil, err + } + userAuthGSSAPIResp := &userAuthGSSAPIResponse{} + if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil { + return authFailure, nil, err + } + // Start the loop into the exchange token. + // See RFC 4462 section 3.4. + var token []byte + defer g.gssAPIClient.DeleteSecContext() + for { + // Initiates the establishment of a security context between the application and a remote peer. + nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false) + if err != nil { + return authFailure, nil, err + } + if len(nextToken) > 0 { + if err := c.writePacket(Marshal(&userAuthGSSAPIToken{ + Token: nextToken, + })); err != nil { + return authFailure, nil, err + } + } + if !needContinue { + break + } + packet, err = c.readPacket() + if err != nil { + return authFailure, nil, err + } + switch packet[0] { + case msgUserAuthFailure: + var msg userAuthFailureMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil + case msgUserAuthGSSAPIError: + userAuthGSSAPIErrorResp := &userAuthGSSAPIError{} + if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil { + return authFailure, nil, err + } + return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+ + "Major Status: %d\n"+ + "Minor Status: %d\n"+ + "Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus, + userAuthGSSAPIErrorResp.Message) + case msgUserAuthGSSAPIToken: + userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} + if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { + return authFailure, nil, err + } + token = userAuthGSSAPITokenReq.Token + } + } + // Binding Encryption Keys. + // See RFC 4462 section 3.5. + micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic") + micToken, err := g.gssAPIClient.GetMIC(micField) + if err != nil { + return authFailure, nil, err + } + if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{ + MIC: micToken, + })); err != nil { + return authFailure, nil, err + } + return handleAuthResponse(c) +} + +func (g *gssAPIWithMICCallback) method() string { + return "gssapi-with-mic" +} diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go index d97415d2d3..e55fe0ad62 100644 --- a/vendor/golang.org/x/crypto/ssh/common.go +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -51,6 +51,13 @@ var supportedKexAlgos = []string{ kexAlgoDH14SHA1, kexAlgoDH1SHA1, } +// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden +// for the server half. +var serverForbiddenKexAlgos = map[string]struct{}{ + kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests + kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests +} + // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods // of authenticating servers) in preference order. var supportedHostKeyAlgos = []string{ diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go index f34bcc0133..16072004b1 100644 --- a/vendor/golang.org/x/crypto/ssh/kex.go +++ b/vendor/golang.org/x/crypto/ssh/kex.go @@ -10,7 +10,9 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/subtle" + "encoding/binary" "errors" + "fmt" "io" "math/big" @@ -24,6 +26,12 @@ const ( kexAlgoECDH384 = "ecdh-sha2-nistp384" kexAlgoECDH521 = "ecdh-sha2-nistp521" kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" + + // For the following kex only the client half contains a production + // ready implementation. The server half only consists of a minimal + // implementation to satisfy the automated tests. + kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1" + kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256" ) // kexResult captures the outcome of a key exchange. @@ -402,6 +410,8 @@ func init() { kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} + kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} + kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} } // curve25519sha256 implements the curve25519-sha256@libssh.org key @@ -538,3 +548,242 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh Hash: crypto.SHA256, }, nil } + +// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and +// diffie-hellman-group-exchange-sha256 key agreement protocols, +// as described in RFC 4419 +type dhGEXSHA struct { + g, p *big.Int + hashFunc crypto.Hash +} + +const numMRTests = 64 + +const ( + dhGroupExchangeMinimumBits = 2048 + dhGroupExchangePreferredBits = 2048 + dhGroupExchangeMaximumBits = 8192 +) + +func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { + if theirPublic.Sign() <= 0 || theirPublic.Cmp(gex.p) >= 0 { + return nil, fmt.Errorf("ssh: DH parameter out of bounds") + } + return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil +} + +func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { + // Send GexRequest + kexDHGexRequest := kexDHGexRequestMsg{ + MinBits: dhGroupExchangeMinimumBits, + PreferedBits: dhGroupExchangePreferredBits, + MaxBits: dhGroupExchangeMaximumBits, + } + if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil { + return nil, err + } + + // Receive GexGroup + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var kexDHGexGroup kexDHGexGroupMsg + if err = Unmarshal(packet, &kexDHGexGroup); err != nil { + return nil, err + } + + // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits + if kexDHGexGroup.P.BitLen() < dhGroupExchangeMinimumBits || kexDHGexGroup.P.BitLen() > dhGroupExchangeMaximumBits { + return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", kexDHGexGroup.P.BitLen()) + } + + gex.p = kexDHGexGroup.P + gex.g = kexDHGexGroup.G + + // Check if p is safe by verifing that p and (p-1)/2 are primes + one := big.NewInt(1) + var pHalf = &big.Int{} + pHalf.Rsh(gex.p, 1) + if !gex.p.ProbablyPrime(numMRTests) || !pHalf.ProbablyPrime(numMRTests) { + return nil, fmt.Errorf("ssh: server provided gex p is not safe") + } + + // Check if g is safe by verifing that g > 1 and g < p - 1 + var pMinusOne = &big.Int{} + pMinusOne.Sub(gex.p, one) + if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 { + return nil, fmt.Errorf("ssh: server provided gex g is not safe") + } + + // Send GexInit + x, err := rand.Int(randSource, pHalf) + if err != nil { + return nil, err + } + X := new(big.Int).Exp(gex.g, x, gex.p) + kexDHGexInit := kexDHGexInitMsg{ + X: X, + } + if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil { + return nil, err + } + + // Receive GexReply + packet, err = c.readPacket() + if err != nil { + return nil, err + } + + var kexDHGexReply kexDHGexReplyMsg + if err = Unmarshal(packet, &kexDHGexReply); err != nil { + return nil, err + } + + kInt, err := gex.diffieHellman(kexDHGexReply.Y, x) + if err != nil { + return nil, err + } + + // Check if k is safe by verifing that k > 1 and k < p - 1 + if kInt.Cmp(one) != 1 && kInt.Cmp(pMinusOne) != -1 { + return nil, fmt.Errorf("ssh: derived k is not safe") + } + + h := gex.hashFunc.New() + magics.write(h) + writeString(h, kexDHGexReply.HostKey) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) + writeInt(h, gex.p) + writeInt(h, gex.g) + writeInt(h, X) + writeInt(h, kexDHGexReply.Y) + K := make([]byte, intLength(kInt)) + marshalInt(K, kInt) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: kexDHGexReply.HostKey, + Signature: kexDHGexReply.Signature, + Hash: gex.hashFunc, + }, nil +} + +// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. +// +// This is a minimal implementation to satisfy the automated tests. +func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { + // Receive GexRequest + packet, err := c.readPacket() + if err != nil { + return + } + var kexDHGexRequest kexDHGexRequestMsg + if err = Unmarshal(packet, &kexDHGexRequest); err != nil { + return + } + + // smoosh the user's preferred size into our own limits + if kexDHGexRequest.PreferedBits > dhGroupExchangeMaximumBits { + kexDHGexRequest.PreferedBits = dhGroupExchangeMaximumBits + } + if kexDHGexRequest.PreferedBits < dhGroupExchangeMinimumBits { + kexDHGexRequest.PreferedBits = dhGroupExchangeMinimumBits + } + // fix min/max if they're inconsistent. technically, we could just pout + // and hang up, but there's no harm in giving them the benefit of the + // doubt and just picking a bitsize for them. + if kexDHGexRequest.MinBits > kexDHGexRequest.PreferedBits { + kexDHGexRequest.MinBits = kexDHGexRequest.PreferedBits + } + if kexDHGexRequest.MaxBits < kexDHGexRequest.PreferedBits { + kexDHGexRequest.MaxBits = kexDHGexRequest.PreferedBits + } + + // Send GexGroup + // This is the group called diffie-hellman-group14-sha1 in RFC + // 4253 and Oakley Group 14 in RFC 3526. + p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) + gex.p = p + gex.g = big.NewInt(2) + + kexDHGexGroup := kexDHGexGroupMsg{ + P: gex.p, + G: gex.g, + } + if err := c.writePacket(Marshal(&kexDHGexGroup)); err != nil { + return nil, err + } + + // Receive GexInit + packet, err = c.readPacket() + if err != nil { + return + } + var kexDHGexInit kexDHGexInitMsg + if err = Unmarshal(packet, &kexDHGexInit); err != nil { + return + } + + var pHalf = &big.Int{} + pHalf.Rsh(gex.p, 1) + + y, err := rand.Int(randSource, pHalf) + if err != nil { + return + } + + Y := new(big.Int).Exp(gex.g, y, gex.p) + kInt, err := gex.diffieHellman(kexDHGexInit.X, y) + if err != nil { + return nil, err + } + + hostKeyBytes := priv.PublicKey().Marshal() + + h := gex.hashFunc.New() + magics.write(h) + writeString(h, hostKeyBytes) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) + writeInt(h, gex.p) + writeInt(h, gex.g) + writeInt(h, kexDHGexInit.X) + writeInt(h, Y) + + K := make([]byte, intLength(kInt)) + marshalInt(K, kInt) + h.Write(K) + + H := h.Sum(nil) + + // H is already a hash, but the hostkey signing will apply its + // own key-specific hash algorithm. + sig, err := signAndMarshal(priv, randSource, H) + if err != nil { + return nil, err + } + + kexDHGexReply := kexDHGexReplyMsg{ + HostKey: hostKeyBytes, + Y: Y, + Signature: sig, + } + packet = Marshal(&kexDHGexReply) + + err = c.writePacket(packet) + + return &kexResult{ + H: H, + K: K, + HostKey: hostKeyBytes, + Signature: sig, + Hash: gex.hashFunc, + }, err +} diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go index 5ec42afa3b..ac41a4168b 100644 --- a/vendor/golang.org/x/crypto/ssh/messages.go +++ b/vendor/golang.org/x/crypto/ssh/messages.go @@ -97,6 +97,36 @@ type kexDHReplyMsg struct { Signature []byte } +// See RFC 4419, section 5. +const msgKexDHGexGroup = 31 + +type kexDHGexGroupMsg struct { + P *big.Int `sshtype:"31"` + G *big.Int +} + +const msgKexDHGexInit = 32 + +type kexDHGexInitMsg struct { + X *big.Int `sshtype:"32"` +} + +const msgKexDHGexReply = 33 + +type kexDHGexReplyMsg struct { + HostKey []byte `sshtype:"33"` + Y *big.Int + Signature []byte +} + +const msgKexDHGexRequest = 34 + +type kexDHGexRequestMsg struct { + MinBits uint32 `sshtype:"34"` + PreferedBits uint32 + MaxBits uint32 +} + // See RFC 4253, section 10. const msgServiceRequest = 5 @@ -275,6 +305,42 @@ type userAuthPubKeyOkMsg struct { PubKey []byte } +// See RFC 4462, section 3 +const msgUserAuthGSSAPIResponse = 60 + +type userAuthGSSAPIResponse struct { + SupportMech []byte `sshtype:"60"` +} + +const msgUserAuthGSSAPIToken = 61 + +type userAuthGSSAPIToken struct { + Token []byte `sshtype:"61"` +} + +const msgUserAuthGSSAPIMIC = 66 + +type userAuthGSSAPIMIC struct { + MIC []byte `sshtype:"66"` +} + +// See RFC 4462, section 3.9 +const msgUserAuthGSSAPIErrTok = 64 + +type userAuthGSSAPIErrTok struct { + ErrorToken []byte `sshtype:"64"` +} + +// See RFC 4462, section 3.8 +const msgUserAuthGSSAPIError = 65 + +type userAuthGSSAPIError struct { + MajorStatus uint32 `sshtype:"65"` + MinorStatus uint32 + Message string + LanguageTag string +} + // typeTags returns the possible type bytes for the given reflect.Type, which // should be a struct. The possible values are separated by a '|' character. func typeTags(structType reflect.Type) (tags []byte) { @@ -756,6 +822,14 @@ func decode(packet []byte) (interface{}, error) { msg = new(channelRequestSuccessMsg) case msgChannelFailure: msg = new(channelRequestFailureMsg) + case msgUserAuthGSSAPIToken: + msg = new(userAuthGSSAPIToken) + case msgUserAuthGSSAPIMIC: + msg = new(userAuthGSSAPIMIC) + case msgUserAuthGSSAPIErrTok: + msg = new(userAuthGSSAPIErrTok) + case msgUserAuthGSSAPIError: + msg = new(userAuthGSSAPIError) default: return nil, unexpectedMessageError(0, packet[0]) } diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index e86e89661a..7a5a1d7ad3 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -45,6 +45,20 @@ type Permissions struct { Extensions map[string]string } +type GSSAPIWithMICConfig struct { + // AllowLogin, must be set, is called when gssapi-with-mic + // authentication is selected (RFC 4462 section 3). The srcName is from the + // results of the GSS-API authentication. The format is username@DOMAIN. + // GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions. + // This callback is called after the user identity is established with GSSAPI to decide if the user can login with + // which permissions. If the user is allowed to login, it should return a nil error. + AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error) + + // Server must be set. It's the implementation + // of the GSSAPIServer interface. See GSSAPIServer interface for details. + Server GSSAPIServer +} + // ServerConfig holds server specific configuration data. type ServerConfig struct { // Config contains configuration shared between client and server. @@ -99,6 +113,10 @@ type ServerConfig struct { // BannerCallback, if present, is called and the return string is sent to // the client after key exchange completed but before authentication. BannerCallback func(conn ConnMetadata) string + + // GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used + // when gssapi-with-mic authentication is selected (RFC 4462 section 3). + GSSAPIWithMICConfig *GSSAPIWithMICConfig } // AddHostKey adds a private key as a host key. If an existing host @@ -175,6 +193,12 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha if fullConf.MaxAuthTries == 0 { fullConf.MaxAuthTries = 6 } + // Check if the config contains any unsupported key exchanges + for _, kex := range fullConf.KeyExchanges { + if _, ok := serverForbiddenKexAlgos[kex]; ok { + return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex) + } + } s := &connection{ sshConn: sshConn{conn: c}, @@ -204,7 +228,9 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) return nil, errors.New("ssh: server has no host keys") } - if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil { + if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && + config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil || + config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) { return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") } @@ -295,6 +321,55 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error { return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) } +func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection, + sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) { + gssAPIServer := gssapiConfig.Server + defer gssAPIServer.DeleteSecContext() + var srcName string + for { + var ( + outToken []byte + needContinue bool + ) + outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken) + if err != nil { + return err, nil, nil + } + if len(outToken) != 0 { + if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{ + Token: outToken, + })); err != nil { + return nil, nil, err + } + } + if !needContinue { + break + } + packet, err := s.transport.readPacket() + if err != nil { + return nil, nil, err + } + userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} + if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { + return nil, nil, err + } + } + packet, err := s.transport.readPacket() + if err != nil { + return nil, nil, err + } + userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{} + if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil { + return nil, nil, err + } + mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method) + if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil { + return err, nil, nil + } + perms, authErr = gssapiConfig.AllowLogin(s, srcName) + return authErr, perms, nil +} + // ServerAuthError represents server authentication errors and is // sometimes returned by NewServerConn. It appends any authentication // errors that may occur, and is returned if all of the authentication @@ -496,6 +571,49 @@ userAuthLoop: authErr = candidate.result perms = candidate.perms } + case "gssapi-with-mic": + gssapiConfig := config.GSSAPIWithMICConfig + userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload) + if err != nil { + return nil, parseError(msgUserAuthRequest) + } + // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication. + if userAuthRequestGSSAPI.N == 0 { + authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported") + break + } + var i uint32 + present := false + for i = 0; i < userAuthRequestGSSAPI.N; i++ { + if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) { + present = true + break + } + } + if !present { + authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism") + break + } + // Initial server response, see RFC 4462 section 3.3. + if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{ + SupportMech: krb5OID, + })); err != nil { + return nil, err + } + // Exchange token, see RFC 4462 section 3.4. + packet, err := s.transport.readPacket() + if err != nil { + return nil, err + } + userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} + if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { + return nil, err + } + authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID, + userAuthReq) + if err != nil { + return nil, err + } default: authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) } @@ -522,6 +640,10 @@ userAuthLoop: if config.KeyboardInteractiveCallback != nil { failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") } + if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil && + config.GSSAPIWithMICConfig.AllowLogin != nil { + failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic") + } if len(failureMsg.Methods) == 0 { return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") diff --git a/vendor/golang.org/x/crypto/ssh/ssh_gss.go b/vendor/golang.org/x/crypto/ssh/ssh_gss.go new file mode 100644 index 0000000000..24bd7c8e83 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/ssh_gss.go @@ -0,0 +1,139 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "encoding/asn1" + "errors" +) + +var krb5OID []byte + +func init() { + krb5OID, _ = asn1.Marshal(krb5Mesh) +} + +// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins. +type GSSAPIClient interface { + // InitSecContext initiates the establishment of a security context for GSS-API between the + // ssh client and ssh server. Initially the token parameter should be specified as nil. + // The routine may return a outputToken which should be transferred to + // the ssh server, where the ssh server will present it to + // AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting + // needContinue to false. To complete the context + // establishment, one or more reply tokens may be required from the ssh + // server;if so, InitSecContext will return a needContinue which is true. + // In this case, InitSecContext should be called again when the + // reply token is received from the ssh server, passing the reply + // token to InitSecContext via the token parameters. + // See RFC 2743 section 2.2.1 and RFC 4462 section 3.4. + InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error) + // GetMIC generates a cryptographic MIC for the SSH2 message, and places + // the MIC in a token for transfer to the ssh server. + // The contents of the MIC field are obtained by calling GSS_GetMIC() + // over the following, using the GSS-API context that was just + // established: + // string session identifier + // byte SSH_MSG_USERAUTH_REQUEST + // string user name + // string service + // string "gssapi-with-mic" + // See RFC 2743 section 2.3.1 and RFC 4462 3.5. + GetMIC(micFiled []byte) ([]byte, error) + // Whenever possible, it should be possible for + // DeleteSecContext() calls to be successfully processed even + // if other calls cannot succeed, thereby enabling context-related + // resources to be released. + // In addition to deleting established security contexts, + // gss_delete_sec_context must also be able to delete "half-built" + // security contexts resulting from an incomplete sequence of + // InitSecContext()/AcceptSecContext() calls. + // See RFC 2743 section 2.2.3. + DeleteSecContext() error +} + +// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins. +type GSSAPIServer interface { + // AcceptSecContext allows a remotely initiated security context between the application + // and a remote peer to be established by the ssh client. The routine may return a + // outputToken which should be transferred to the ssh client, + // where the ssh client will present it to InitSecContext. + // If no token need be sent, AcceptSecContext will indicate this + // by setting the needContinue to false. To + // complete the context establishment, one or more reply tokens may be + // required from the ssh client. if so, AcceptSecContext + // will return a needContinue which is true, in which case it + // should be called again when the reply token is received from the ssh + // client, passing the token to AcceptSecContext via the + // token parameters. + // The srcName return value is the authenticated username. + // See RFC 2743 section 2.2.2 and RFC 4462 section 3.4. + AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error) + // VerifyMIC verifies that a cryptographic MIC, contained in the token parameter, + // fits the supplied message is received from the ssh client. + // See RFC 2743 section 2.3.2. + VerifyMIC(micField []byte, micToken []byte) error + // Whenever possible, it should be possible for + // DeleteSecContext() calls to be successfully processed even + // if other calls cannot succeed, thereby enabling context-related + // resources to be released. + // In addition to deleting established security contexts, + // gss_delete_sec_context must also be able to delete "half-built" + // security contexts resulting from an incomplete sequence of + // InitSecContext()/AcceptSecContext() calls. + // See RFC 2743 section 2.2.3. + DeleteSecContext() error +} + +var ( + // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication, + // so we also support the krb5 mechanism only. + // See RFC 1964 section 1. + krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2} +) + +// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST +// See RFC 4462 section 3.2. +type userAuthRequestGSSAPI struct { + N uint32 + OIDS []asn1.ObjectIdentifier +} + +func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) { + n, rest, ok := parseUint32(payload) + if !ok { + return nil, errors.New("parse uint32 failed") + } + s := &userAuthRequestGSSAPI{ + N: n, + OIDS: make([]asn1.ObjectIdentifier, n), + } + for i := 0; i < int(n); i++ { + var ( + desiredMech []byte + err error + ) + desiredMech, rest, ok = parseString(rest) + if !ok { + return nil, errors.New("parse string failed") + } + if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil { + return nil, err + } + + } + return s, nil +} + +// See RFC 4462 section 3.6. +func buildMIC(sessionID string, username string, service string, authMethod string) []byte { + out := make([]byte, 0, 0) + out = appendString(out, sessionID) + out = append(out, msgUserAuthRequest) + out = appendString(out, username) + out = appendString(out, service) + out = appendString(out, authMethod) + return out +} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go index 606cf1f972..37dc0cfdb5 100644 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go +++ b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go @@ -2,18 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.7 - // Package ctxhttp provides helper functions for performing context-aware HTTP requests. package ctxhttp // import "golang.org/x/net/context/ctxhttp" import ( + "context" "io" "net/http" "net/url" "strings" - - "golang.org/x/net/context" ) // Do sends an HTTP request with the provided http.Client and returns diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go deleted file mode 100644 index 926870cc23..0000000000 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.7 - -package ctxhttp // import "golang.org/x/net/context/ctxhttp" - -import ( - "io" - "net/http" - "net/url" - "strings" - - "golang.org/x/net/context" -) - -func nop() {} - -var ( - testHookContextDoneBeforeHeaders = nop - testHookDoReturned = nop - testHookDidBodyClose = nop -) - -// Do sends an HTTP request with the provided http.Client and returns an HTTP response. -// If the client is nil, http.DefaultClient is used. -// If the context is canceled or times out, ctx.Err() will be returned. -func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { - if client == nil { - client = http.DefaultClient - } - - // TODO(djd): Respect any existing value of req.Cancel. - cancel := make(chan struct{}) - req.Cancel = cancel - - type responseAndError struct { - resp *http.Response - err error - } - result := make(chan responseAndError, 1) - - // Make local copies of test hooks closed over by goroutines below. - // Prevents data races in tests. - testHookDoReturned := testHookDoReturned - testHookDidBodyClose := testHookDidBodyClose - - go func() { - resp, err := client.Do(req) - testHookDoReturned() - result <- responseAndError{resp, err} - }() - - var resp *http.Response - - select { - case <-ctx.Done(): - testHookContextDoneBeforeHeaders() - close(cancel) - // Clean up after the goroutine calling client.Do: - go func() { - if r := <-result; r.resp != nil { - testHookDidBodyClose() - r.resp.Body.Close() - } - }() - return nil, ctx.Err() - case r := <-result: - var err error - resp, err = r.resp, r.err - if err != nil { - return resp, err - } - } - - c := make(chan struct{}) - go func() { - select { - case <-ctx.Done(): - close(cancel) - case <-c: - // The response's Body is closed. - } - }() - resp.Body = ¬ifyingReader{resp.Body, c} - - return resp, nil -} - -// Get issues a GET request via the Do function. -func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Head issues a HEAD request via the Do function. -func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Post issues a POST request via the Do function. -func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", url, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", bodyType) - return Do(ctx, client, req) -} - -// PostForm issues a POST request via the Do function. -func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { - return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) -} - -// notifyingReader is an io.ReadCloser that closes the notify channel after -// Close is called or a Read fails on the underlying ReadCloser. -type notifyingReader struct { - io.ReadCloser - notify chan<- struct{} -} - -func (r *notifyingReader) Read(p []byte) (int, error) { - n, err := r.ReadCloser.Read(p) - if err != nil && r.notify != nil { - close(r.notify) - r.notify = nil - } - return n, err -} - -func (r *notifyingReader) Close() error { - err := r.ReadCloser.Close() - if r.notify != nil { - close(r.notify) - r.notify = nil - } - return err -} diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go index 2c1cade607..633ee15dc5 100644 --- a/vendor/golang.org/x/net/html/node.go +++ b/vendor/golang.org/x/net/html/node.go @@ -177,7 +177,7 @@ func (s *nodeStack) index(n *Node) int { // contains returns whether a is within s. func (s *nodeStack) contains(a atom.Atom) bool { for _, n := range *s { - if n.DataAtom == a { + if n.DataAtom == a && n.Namespace == "" { return true } } diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 64a5793725..992cff2a33 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -439,9 +439,6 @@ func (p *parser) resetInsertionMode() { case a.Select: if !last { for ancestor, first := n, p.oe[0]; ancestor != first; { - if ancestor == first { - break - } ancestor = p.oe[p.oe.index(ancestor)-1] switch ancestor.DataAtom { case a.Template: @@ -633,7 +630,16 @@ func inHeadIM(p *parser) bool { p.oe.pop() p.acknowledgeSelfClosingTag() return true - case a.Script, a.Title, a.Noscript, a.Noframes, a.Style: + case a.Noscript: + p.addElement() + if p.scripting { + p.setOriginalIM() + p.im = textIM + } else { + p.im = inHeadNoscriptIM + } + return true + case a.Script, a.Title, a.Noframes, a.Style: p.addElement() p.setOriginalIM() p.im = textIM @@ -695,6 +701,49 @@ func inHeadIM(p *parser) bool { return false } +// 12.2.6.4.5. +func inHeadNoscriptIM(p *parser) bool { + switch p.tok.Type { + case DoctypeToken: + // Ignore the token. + return true + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style: + return inHeadIM(p) + case a.Head, a.Noscript: + // Ignore the token. + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Noscript, a.Br: + default: + // Ignore the token. + return true + } + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) == 0 { + // It was all whitespace. + return inHeadIM(p) + } + case CommentToken: + return inHeadIM(p) + } + p.oe.pop() + if p.top().DataAtom != a.Head { + panic("html: the new current node will be a head element.") + } + p.im = inHeadIM + if p.tok.DataAtom == a.Noscript { + return true + } + return false +} + // Section 12.2.6.4.6. func afterHeadIM(p *parser) bool { switch p.tok.Type { @@ -904,7 +953,7 @@ func inBodyIM(p *parser) bool { case a.A: for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- { if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A { - p.inBodyEndTagFormatting(a.A) + p.inBodyEndTagFormatting(a.A, "a") p.oe.remove(n) p.afe.remove(n) break @@ -918,7 +967,7 @@ func inBodyIM(p *parser) bool { case a.Nobr: p.reconstructActiveFormattingElements() if p.elementInScope(defaultScope, a.Nobr) { - p.inBodyEndTagFormatting(a.Nobr) + p.inBodyEndTagFormatting(a.Nobr, "nobr") p.reconstructActiveFormattingElements() } p.addFormattingElement() @@ -1126,7 +1175,7 @@ func inBodyIM(p *parser) bool { case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6: p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6) case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U: - p.inBodyEndTagFormatting(p.tok.DataAtom) + p.inBodyEndTagFormatting(p.tok.DataAtom, p.tok.Data) case a.Applet, a.Marquee, a.Object: if p.popUntil(defaultScope, p.tok.DataAtom) { p.clearActiveFormattingElements() @@ -1137,7 +1186,7 @@ func inBodyIM(p *parser) bool { case a.Template: return inHeadIM(p) default: - p.inBodyEndTagOther(p.tok.DataAtom) + p.inBodyEndTagOther(p.tok.DataAtom, p.tok.Data) } case CommentToken: p.addChild(&Node{ @@ -1164,7 +1213,7 @@ func inBodyIM(p *parser) bool { return true } -func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) { +func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) { // This is the "adoption agency" algorithm, described at // https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency @@ -1186,7 +1235,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) { } } if formattingElement == nil { - p.inBodyEndTagOther(tagAtom) + p.inBodyEndTagOther(tagAtom, tagName) return } feIndex := p.oe.index(formattingElement) @@ -1291,9 +1340,17 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) { // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. // "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign -func (p *parser) inBodyEndTagOther(tagAtom a.Atom) { +func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) { for i := len(p.oe) - 1; i >= 0; i-- { - if p.oe[i].DataAtom == tagAtom { + // Two element nodes have the same tag if they have the same Data (a + // string-typed field). As an optimization, for common HTML tags, each + // Data string is assigned a unique, non-zero DataAtom (a uint32-typed + // field), since integer comparison is faster than string comparison. + // Uncommon (custom) tags get a zero DataAtom. + // + // The if condition here is equivalent to (p.oe[i].Data == tagName). + if (p.oe[i].DataAtom == tagAtom) && + ((tagAtom != 0) || (p.oe[i].Data == tagName)) { p.oe = p.oe[:i] break } @@ -1687,8 +1744,9 @@ func inCellIM(p *parser) bool { return true } // Close the cell and reprocess. - p.popUntil(tableScope, a.Td, a.Th) - p.clearActiveFormattingElements() + if p.popUntil(tableScope, a.Td, a.Th) { + p.clearActiveFormattingElements() + } p.im = inRowIM return false } @@ -1719,8 +1777,12 @@ func inSelectIM(p *parser) bool { } p.addElement() case a.Select: - p.tok.Type = EndTagToken - return false + if p.popUntil(selectScope, a.Select) { + p.resetInsertionMode() + } else { + // Ignore the token. + return true + } case a.Input, a.Keygen, a.Textarea: if p.elementInScope(selectScope, a.Select) { p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) @@ -1750,6 +1812,9 @@ func inSelectIM(p *parser) bool { case a.Select: if p.popUntil(selectScope, a.Select) { p.resetInsertionMode() + } else { + // Ignore the token. + return true } case a.Template: return inHeadIM(p) @@ -1775,13 +1840,22 @@ func inSelectInTableIM(p *parser) bool { case StartTagToken, EndTagToken: switch p.tok.DataAtom { case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th: - if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) { - p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) - return false - } else { + if p.tok.Type == EndTagToken && !p.elementInScope(tableScope, p.tok.DataAtom) { // Ignore the token. return true } + // This is like p.popUntil(selectScope, a.Select), but it also + // matches , not just
    ' + data + '
    '; + preview.innerHTML = '
    ' + data + '
    '; emojify.run($('.editor-preview')[0]); } ); @@ -1224,7 +1224,7 @@ function setSimpleMDE($editArea) { "text": plainText }, function (data) { - preview.innerHTML = '
    ' + data + '
    '; + preview.innerHTML = '
    ' + data + '
    '; emojify.run($('.editor-preview')[0]); } ); diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index 6d13bb2e52..d2fe2982d7 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -501,7 +501,36 @@ a.ui.basic.green.label:hover { } .markdown:not(code) table tr:nth-child(2n) { - background-color: #474d61; + background-color: #2a2e39; +} + +.markdown:not(code) table tr:nth-child(2n-1) { + background-color: #383b44; +} + +.markdown:not(code) table thead tr:nth-child(2n-1) { + background-color: #464c5d !important; +} + +.markdown:not(code) table td, +.markdown:not(code) table th { + border-color: #4c505c !important; +} + +.repository.file.editor.edit, +.repository.wiki.new .CodeMirror { + border-right: 1px solid rgba(187,187,187, 0.6); + border-left: 1px solid rgba(187,187,187, 0.6); + border-bottom: 1px solid rgba(187,187,187, 0.6); + + .editor-preview, + .editor-preview-side { + background: #353945; + + .markdown:not(code).ui.segment { + border-width: 0; + } + } } .ui.dropdown .menu { From baefea311f1a66a97f9a2779ad3342f4f8167d28 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 22 Jun 2019 18:35:34 +0100 Subject: [PATCH 139/220] Fix #732: Add LFS objects to base repository on merging (#7082) On merge we walk the merge history and ensure that all lfs objects pointed to in the history are added to the base repository. This switches from relying on having git-lfs installed on the server, (and in fact .gitattributes being correctly installed.) --- .../api_helper_for_declarative_test.go | 38 ++ integrations/git_test.go | 43 ++- models/pull.go | 288 +-------------- modules/pull/lfs.go | 226 ++++++++++++ modules/pull/merge.go | 339 ++++++++++++++++++ routers/api/v1/repo/pull.go | 3 +- routers/repo/pull.go | 3 +- 7 files changed, 648 insertions(+), 292 deletions(-) create mode 100644 modules/pull/lfs.go create mode 100644 modules/pull/merge.go diff --git a/integrations/api_helper_for_declarative_test.go b/integrations/api_helper_for_declarative_test.go index 85f0ab621f..42c271e3af 100644 --- a/integrations/api_helper_for_declarative_test.go +++ b/integrations/api_helper_for_declarative_test.go @@ -66,6 +66,44 @@ func doAPICreateRepository(ctx APITestContext, empty bool, callback ...func(*tes } } +func doAPIAddCollaborator(ctx APITestContext, username string, mode models.AccessMode) func(*testing.T) { + return func(t *testing.T) { + permission := "read" + + if mode == models.AccessModeAdmin { + permission = "admin" + } else if mode > models.AccessModeRead { + permission = "write" + } + addCollaboratorOption := &api.AddCollaboratorOption{ + Permission: &permission, + } + req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/collaborators/%s?token=%s", ctx.Username, ctx.Reponame, username, ctx.Token), addCollaboratorOption) + if ctx.ExpectedCode != 0 { + ctx.Session.MakeRequest(t, req, ctx.ExpectedCode) + return + } + ctx.Session.MakeRequest(t, req, http.StatusNoContent) + } +} + +func doAPIForkRepository(ctx APITestContext, username string, callback ...func(*testing.T, api.Repository)) func(*testing.T) { + return func(t *testing.T) { + createForkOption := &api.CreateForkOption{} + req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/forks?token=%s", username, ctx.Reponame, ctx.Token), createForkOption) + if ctx.ExpectedCode != 0 { + ctx.Session.MakeRequest(t, req, ctx.ExpectedCode) + return + } + resp := ctx.Session.MakeRequest(t, req, http.StatusAccepted) + var repository api.Repository + DecodeJSON(t, resp, &repository) + if len(callback) > 0 { + callback[0](t, repository) + } + } +} + func doAPIGetRepository(ctx APITestContext, callback ...func(*testing.T, api.Repository)) func(*testing.T) { return func(t *testing.T) { urlStr := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", ctx.Username, ctx.Reponame, ctx.Token) diff --git a/integrations/git_test.go b/integrations/git_test.go index ce5aee493d..8578fb86d5 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -39,17 +39,23 @@ func testGit(t *testing.T, u *url.URL) { u.Path = baseAPITestContext.GitPath() + forkedUserCtx := NewAPITestContext(t, "user4", "repo1") + t.Run("HTTP", func(t *testing.T) { PrintCurrentTest(t) + ensureAnonymousClone(t, u) httpContext := baseAPITestContext httpContext.Reponame = "repo-tmp-17" + forkedUserCtx.Reponame = httpContext.Reponame dstPath, err := ioutil.TempDir("", httpContext.Reponame) assert.NoError(t, err) defer os.RemoveAll(dstPath) - t.Run("CreateRepo", doAPICreateRepository(httpContext, false)) - ensureAnonymousClone(t, u) + t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false)) + t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, httpContext.Username, models.AccessModeRead)) + + t.Run("ForkFromDifferentUser", doAPIForkRepository(httpContext, forkedUserCtx.Username)) u.Path = httpContext.GitPath() u.User = url.UserPassword(username, userPassword) @@ -62,12 +68,23 @@ func testGit(t *testing.T, u *url.URL) { mediaTest(t, &httpContext, little, big, littleLFS, bigLFS) t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath)) + t.Run("MergeFork", func(t *testing.T) { + t.Run("CreatePRAndMerge", doMergeFork(httpContext, forkedUserCtx, "master", httpContext.Username+":master")) + t.Run("DeleteRepository", doAPIDeleteRepository(httpContext)) + rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) + mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) + }) }) t.Run("SSH", func(t *testing.T) { PrintCurrentTest(t) sshContext := baseAPITestContext sshContext.Reponame = "repo-tmp-18" keyname := "my-testing-key" + forkedUserCtx.Reponame = sshContext.Reponame + t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false)) + t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, sshContext.Username, models.AccessModeRead)) + t.Run("ForkFromDifferentUser", doAPIForkRepository(sshContext, forkedUserCtx.Username)) + //Setup key the user ssh key withKeyFile(t, keyname, func(keyFile string) { t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile)) @@ -81,8 +98,6 @@ func testGit(t *testing.T, u *url.URL) { assert.NoError(t, err) defer os.RemoveAll(dstPath) - t.Run("CreateRepo", doAPICreateRepository(sshContext, false)) - t.Run("Clone", doGitClone(dstPath, sshURL)) little, big := standardCommitAndPushTest(t, dstPath) @@ -91,8 +106,13 @@ func testGit(t *testing.T, u *url.URL) { mediaTest(t, &sshContext, little, big, littleLFS, bigLFS) t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath)) + t.Run("MergeFork", func(t *testing.T) { + t.Run("CreatePRAndMerge", doMergeFork(sshContext, forkedUserCtx, "master", sshContext.Username+":master")) + t.Run("DeleteRepository", doAPIDeleteRepository(sshContext)) + rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) + mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) + }) }) - }) } @@ -341,3 +361,16 @@ func doProtectBranch(ctx APITestContext, branch string, userToWhitelist string) assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527"+url.QueryEscape(branch)+"%2527%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value) } } + +func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) func(t *testing.T) { + return func(t *testing.T) { + var pr api.PullRequest + var err error + t.Run("CreatePullRequest", func(t *testing.T) { + pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, baseBranch, headBranch)(t) + assert.NoError(t, err) + }) + t.Run("MergePR", doAPIMergePullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + + } +} diff --git a/models/pull.go b/models/pull.go index e5d421e6ba..38976d37ec 100644 --- a/models/pull.go +++ b/models/pull.go @@ -7,7 +7,6 @@ package models import ( "bufio" - "bytes" "fmt" "io/ioutil" "os" @@ -18,7 +17,6 @@ import ( "time" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" @@ -368,288 +366,8 @@ func (pr *PullRequest) CheckUserAllowedToMerge(doer *User) (err error) { return nil } -func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) { - getDiffTreeFromBranch := func(repoPath, baseBranch, headBranch string) (string, error) { - var outbuf, errbuf strings.Builder - // Compute the diff-tree for sparse-checkout - // The branch argument must be enclosed with double-quotes ("") in case it contains slashes (e.g "feature/test") - if err := git.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "--root", baseBranch, headBranch).RunInDirPipeline(repoPath, &outbuf, &errbuf); err != nil { - return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String()) - } - return outbuf.String(), nil - } - - list, err := getDiffTreeFromBranch(repoPath, baseBranch, headBranch) - if err != nil { - return "", err - } - - // Prefixing '/' for each entry, otherwise all files with the same name in subdirectories would be matched. - out := bytes.Buffer{} - scanner := bufio.NewScanner(strings.NewReader(list)) - for scanner.Scan() { - fmt.Fprintf(&out, "/%s\n", scanner.Text()) - } - return out.String(), nil -} - -// Merge merges pull request to base repository. -// FIXME: add repoWorkingPull make sure two merges does not happen at same time. -func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle MergeStyle, message string) (err error) { - if err = pr.GetHeadRepo(); err != nil { - return fmt.Errorf("GetHeadRepo: %v", err) - } else if err = pr.GetBaseRepo(); err != nil { - return fmt.Errorf("GetBaseRepo: %v", err) - } - - prUnit, err := pr.BaseRepo.GetUnit(UnitTypePullRequests) - if err != nil { - return err - } - prConfig := prUnit.PullRequestsConfig() - - if err := pr.CheckUserAllowedToMerge(doer); err != nil { - return fmt.Errorf("CheckUserAllowedToMerge: %v", err) - } - - // Check if merge style is correct and allowed - if !prConfig.IsMergeStyleAllowed(mergeStyle) { - return ErrInvalidMergeStyle{pr.BaseRepo.ID, mergeStyle} - } - - defer func() { - go HookQueue.Add(pr.BaseRepo.ID) - go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false) - }() - - // Clone base repo. - tmpBasePath, err := CreateTemporaryPath("merge") - if err != nil { - return err - } - defer func() { - if err := RemoveTemporaryPath(tmpBasePath); err != nil { - log.Error("Merge: RemoveTemporaryPath: %s", err) - } - }() - - headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name) - - if err := git.Clone(baseGitRepo.Path, tmpBasePath, git.CloneRepoOptions{ - Shared: true, - NoCheckout: true, - Branch: pr.BaseBranch, - }); err != nil { - return fmt.Errorf("git clone: %v", err) - } - - remoteRepoName := "head_repo" - - // Add head repo remote. - addCacheRepo := func(staging, cache string) error { - p := filepath.Join(staging, ".git", "objects", "info", "alternates") - f, err := os.OpenFile(p, os.O_APPEND|os.O_WRONLY, 0600) - if err != nil { - return err - } - defer f.Close() - data := filepath.Join(cache, "objects") - if _, err := fmt.Fprintln(f, data); err != nil { - return err - } - return nil - } - - if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil { - return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err) - } - - var errbuf strings.Builder - if err := git.NewCommand("remote", "add", remoteRepoName, headRepoPath).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) - } - - // Fetch head branch - if err := git.NewCommand("fetch", remoteRepoName).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) - } - - trackingBranch := path.Join(remoteRepoName, pr.HeadBranch) - stagingBranch := fmt.Sprintf("%s_%s", remoteRepoName, pr.HeadBranch) - - // Enable sparse-checkout - sparseCheckoutList, err := getDiffTree(tmpBasePath, pr.BaseBranch, trackingBranch) - if err != nil { - return fmt.Errorf("getDiffTree: %v", err) - } - - infoPath := filepath.Join(tmpBasePath, ".git", "info") - if err := os.MkdirAll(infoPath, 0700); err != nil { - return fmt.Errorf("creating directory failed [%s]: %v", infoPath, err) - } - sparseCheckoutListPath := filepath.Join(infoPath, "sparse-checkout") - if err := ioutil.WriteFile(sparseCheckoutListPath, []byte(sparseCheckoutList), 0600); err != nil { - return fmt.Errorf("Writing sparse-checkout file to %s: %v", sparseCheckoutListPath, err) - } - - if err := git.NewCommand("config", "--local", "core.sparseCheckout", "true").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", errbuf.String()) - } - - // Read base branch index - if err := git.NewCommand("read-tree", "HEAD").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git read-tree HEAD: %s", errbuf.String()) - } - - // Merge commits. - switch mergeStyle { - case MergeStyleMerge: - if err := git.NewCommand("merge", "--no-ff", "--no-commit", trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) - } - - sig := doer.NewGitSig() - if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) - } - case MergeStyleRebase: - // Checkout head branch - if err := git.NewCommand("checkout", "-b", stagingBranch, trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git checkout: %s", errbuf.String()) - } - // Rebase before merging - if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) - } - // Checkout base branch again - if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git checkout: %s", errbuf.String()) - } - // Merge fast forward - if err := git.NewCommand("merge", "--ff-only", "-q", stagingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) - } - case MergeStyleRebaseMerge: - // Checkout head branch - if err := git.NewCommand("checkout", "-b", stagingBranch, trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git checkout: %s", errbuf.String()) - } - // Rebase before merging - if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) - } - // Checkout base branch again - if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git checkout: %s", errbuf.String()) - } - // Prepare merge with commit - if err := git.NewCommand("merge", "--no-ff", "--no-commit", "-q", stagingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git merge --no-ff [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) - } - - // Set custom message and author and create merge commit - sig := doer.NewGitSig() - if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) - } - - case MergeStyleSquash: - // Merge with squash - if err := git.NewCommand("merge", "-q", "--squash", trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) - } - sig := pr.Issue.Poster.NewGitSig() - if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) - } - default: - return ErrInvalidMergeStyle{pr.BaseRepo.ID, mergeStyle} - } - - env := PushingEnvironment(doer, pr.BaseRepo) - - // Push back to upstream. - if err := git.NewCommand("push", baseGitRepo.Path, pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git push: %s", errbuf.String()) - } - - pr.MergedCommitID, err = baseGitRepo.GetBranchCommitID(pr.BaseBranch) - if err != nil { - return fmt.Errorf("GetBranchCommit: %v", err) - } - - pr.MergedUnix = util.TimeStampNow() - pr.Merger = doer - pr.MergerID = doer.ID - - if err = pr.setMerged(); err != nil { - log.Error("setMerged [%d]: %v", pr.ID, err) - } - - if err = MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil { - log.Error("MergePullRequestAction [%d]: %v", pr.ID, err) - } - - // Reset cached commit count - cache.Remove(pr.Issue.Repo.GetCommitsCountCacheKey(pr.BaseBranch, true)) - - // Reload pull request information. - if err = pr.LoadAttributes(); err != nil { - log.Error("LoadAttributes: %v", err) - return nil - } - - mode, _ := AccessLevel(doer, pr.Issue.Repo) - if err = PrepareWebhooks(pr.Issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ - Action: api.HookIssueClosed, - Index: pr.Index, - PullRequest: pr.APIFormat(), - Repository: pr.Issue.Repo.APIFormat(mode), - Sender: doer.APIFormat(), - }); err != nil { - log.Error("PrepareWebhooks: %v", err) - } else { - go HookQueue.Add(pr.Issue.Repo.ID) - } - - l, err := baseGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase) - if err != nil { - log.Error("CommitsBetweenIDs: %v", err) - return nil - } - - // It is possible that head branch is not fully sync with base branch for merge commits, - // so we need to get latest head commit and append merge commit manually - // to avoid strange diff commits produced. - mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch) - if err != nil { - log.Error("GetBranchCommit: %v", err) - return nil - } - if mergeStyle == MergeStyleMerge { - l.PushFront(mergeCommit) - } - - p := &api.PushPayload{ - Ref: git.BranchPrefix + pr.BaseBranch, - Before: pr.MergeBase, - After: mergeCommit.ID.String(), - CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID), - Commits: ListToPushCommits(l).ToAPIPayloadCommits(pr.BaseRepo.HTMLURL()), - Repo: pr.BaseRepo.APIFormat(mode), - Pusher: pr.HeadRepo.MustOwner().APIFormat(), - Sender: doer.APIFormat(), - } - if err = PrepareWebhooks(pr.BaseRepo, HookEventPush, p); err != nil { - log.Error("PrepareWebhooks: %v", err) - } else { - go HookQueue.Add(pr.BaseRepo.ID) - } - return nil -} - -// setMerged sets a pull request to merged and closes the corresponding issue -func (pr *PullRequest) setMerged() (err error) { +// SetMerged sets a pull request to merged and closes the corresponding issue +func (pr *PullRequest) SetMerged() (err error) { if pr.HasMerged { return fmt.Errorf("PullRequest[%d] already merged", pr.Index) } @@ -716,7 +434,7 @@ func (pr *PullRequest) manuallyMerged() bool { pr.Merger = merger pr.MergerID = merger.ID - if err = pr.setMerged(); err != nil { + if err = pr.SetMerged(); err != nil { log.Error("PullRequest[%d].setMerged : %v", pr.ID, err) return false } diff --git a/modules/pull/lfs.go b/modules/pull/lfs.go new file mode 100644 index 0000000000..77890667d6 --- /dev/null +++ b/modules/pull/lfs.go @@ -0,0 +1,226 @@ +// Copyright 2019 The Gitea 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 pull + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strconv" + "strings" + "sync" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/lfs" + "code.gitea.io/gitea/modules/log" +) + +// LFSPush pushes lfs objects referred to in new commits in the head repository from the base repository +func LFSPush(tmpBasePath, mergeHeadSHA, mergeBaseSHA string, pr *models.PullRequest) error { + // Now we have to implement git lfs push + // git rev-list --objects --filter=blob:limit=1k HEAD --not base + // pass blob shas in to git cat-file --batch-check (possibly unnecessary) + // ensure only blobs and <=1k size then pass in to git cat-file --batch + // to read each sha and check each as a pointer + // Then if they are lfs -> add them to the baseRepo + revListReader, revListWriter := io.Pipe() + shasToCheckReader, shasToCheckWriter := io.Pipe() + catFileCheckReader, catFileCheckWriter := io.Pipe() + shasToBatchReader, shasToBatchWriter := io.Pipe() + catFileBatchReader, catFileBatchWriter := io.Pipe() + errChan := make(chan error, 1) + wg := sync.WaitGroup{} + wg.Add(6) + // Create the go-routines in reverse order. + + // 6. Take the output of cat-file --batch and check if each file in turn + // to see if they're pointers to files in the LFS store associated with + // the head repo and add them to the base repo if so + go readCatFileBatch(catFileBatchReader, &wg, pr) + + // 5. Take the shas of the blobs and batch read them + go doCatFileBatch(shasToBatchReader, catFileBatchWriter, &wg, tmpBasePath) + + // 4. From the provided objects restrict to blobs <=1k + go readCatFileBatchCheck(catFileCheckReader, shasToBatchWriter, &wg) + + // 3. Run batch-check on the objects retrieved from rev-list + go doCatFileBatchCheck(shasToCheckReader, catFileCheckWriter, &wg, tmpBasePath) + + // 2. Check each object retrieved rejecting those without names as they will be commits or trees + go readRevListObjects(revListReader, shasToCheckWriter, &wg) + + // 1. Run rev-list objects from mergeHead to mergeBase + go doRevListObjects(revListWriter, &wg, tmpBasePath, mergeHeadSHA, mergeBaseSHA, errChan) + + wg.Wait() + select { + case err, has := <-errChan: + if has { + return err + } + default: + } + return nil +} + +func doRevListObjects(revListWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath, headSHA, baseSHA string, errChan chan<- error) { + defer wg.Done() + defer revListWriter.Close() + stderr := new(bytes.Buffer) + var errbuf strings.Builder + cmd := git.NewCommand("rev-list", "--objects", headSHA, "--not", baseSHA) + if err := cmd.RunInDirPipeline(tmpBasePath, revListWriter, stderr); err != nil { + log.Error("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + errChan <- fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } +} + +func readRevListObjects(revListReader *io.PipeReader, shasToCheckWriter *io.PipeWriter, wg *sync.WaitGroup) { + defer wg.Done() + defer revListReader.Close() + defer shasToCheckWriter.Close() + scanner := bufio.NewScanner(revListReader) + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 { + continue + } + fields := strings.Split(line, " ") + if len(fields) < 2 || len(fields[1]) == 0 { + continue + } + toWrite := []byte(fields[0] + "\n") + for len(toWrite) > 0 { + n, err := shasToCheckWriter.Write(toWrite) + if err != nil { + _ = revListReader.CloseWithError(err) + break + } + toWrite = toWrite[n:] + } + } + _ = shasToCheckWriter.CloseWithError(scanner.Err()) +} + +func doCatFileBatchCheck(shasToCheckReader *io.PipeReader, catFileCheckWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) { + defer wg.Done() + defer shasToCheckReader.Close() + defer catFileCheckWriter.Close() + + stderr := new(bytes.Buffer) + var errbuf strings.Builder + cmd := git.NewCommand("cat-file", "--batch-check") + if err := cmd.RunInDirFullPipeline(tmpBasePath, catFileCheckWriter, stderr, shasToCheckReader); err != nil { + _ = catFileCheckWriter.CloseWithError(fmt.Errorf("git cat-file --batch-check [%s]: %v - %s", tmpBasePath, err, errbuf.String())) + } +} + +func readCatFileBatchCheck(catFileCheckReader *io.PipeReader, shasToBatchWriter *io.PipeWriter, wg *sync.WaitGroup) { + defer wg.Done() + defer catFileCheckReader.Close() + + scanner := bufio.NewScanner(catFileCheckReader) + defer func() { + _ = shasToBatchWriter.CloseWithError(scanner.Err()) + }() + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 { + continue + } + fields := strings.Split(line, " ") + if len(fields) < 3 || fields[1] != "blob" { + continue + } + size, _ := strconv.Atoi(string(fields[2])) + if size > 1024 { + continue + } + toWrite := []byte(fields[0] + "\n") + for len(toWrite) > 0 { + n, err := shasToBatchWriter.Write(toWrite) + if err != nil { + _ = catFileCheckReader.CloseWithError(err) + break + } + toWrite = toWrite[n:] + } + } +} + +func doCatFileBatch(shasToBatchReader *io.PipeReader, catFileBatchWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) { + defer wg.Done() + defer shasToBatchReader.Close() + defer catFileBatchWriter.Close() + + stderr := new(bytes.Buffer) + var errbuf strings.Builder + if err := git.NewCommand("cat-file", "--batch").RunInDirFullPipeline(tmpBasePath, catFileBatchWriter, stderr, shasToBatchReader); err != nil { + _ = shasToBatchReader.CloseWithError(fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())) + } +} + +func readCatFileBatch(catFileBatchReader *io.PipeReader, wg *sync.WaitGroup, pr *models.PullRequest) { + defer wg.Done() + defer catFileBatchReader.Close() + + bufferedReader := bufio.NewReader(catFileBatchReader) + buf := make([]byte, 1025) + for { + // File descriptor line: sha + _, err := bufferedReader.ReadString(' ') + if err != nil { + _ = catFileBatchReader.CloseWithError(err) + break + } + // Throw away the blob + if _, err := bufferedReader.ReadString(' '); err != nil { + _ = catFileBatchReader.CloseWithError(err) + break + } + sizeStr, err := bufferedReader.ReadString('\n') + if err != nil { + _ = catFileBatchReader.CloseWithError(err) + break + } + size, err := strconv.Atoi(sizeStr[:len(sizeStr)-1]) + if err != nil { + _ = catFileBatchReader.CloseWithError(err) + break + } + pointerBuf := buf[:size+1] + if _, err := io.ReadFull(bufferedReader, pointerBuf); err != nil { + _ = catFileBatchReader.CloseWithError(err) + break + } + pointerBuf = pointerBuf[:size] + // Now we need to check if the pointerBuf is an LFS pointer + pointer := lfs.IsPointerFile(&pointerBuf) + if pointer == nil { + continue + } + // Then we need to check that this pointer is in the db + if _, err := pr.HeadRepo.GetLFSMetaObjectByOid(pointer.Oid); err != nil { + if err == models.ErrLFSObjectNotExist { + log.Warn("During merge of: %d in %-v, there is a pointer to LFS Oid: %s which although present in the LFS store is not associated with the head repo %-v", pr.Index, pr.BaseRepo, pointer.Oid, pr.HeadRepo) + continue + } + _ = catFileBatchReader.CloseWithError(err) + break + } + // OK we have a pointer that is associated with the head repo + // and is actually a file in the LFS + // Therefore it should be associated with the base repo + pointer.RepositoryID = pr.BaseRepoID + if _, err := models.NewLFSMetaObject(pointer); err != nil { + _ = catFileBatchReader.CloseWithError(err) + break + } + } +} diff --git a/modules/pull/merge.go b/modules/pull/merge.go new file mode 100644 index 0000000000..e12ede81d6 --- /dev/null +++ b/modules/pull/merge.go @@ -0,0 +1,339 @@ +// Copyright 2019 The Gitea 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 pull + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" +) + +// Merge merges pull request to base repository. +// FIXME: add repoWorkingPull make sure two merges does not happen at same time. +func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repository, mergeStyle models.MergeStyle, message string) (err error) { + if err = pr.GetHeadRepo(); err != nil { + return fmt.Errorf("GetHeadRepo: %v", err) + } else if err = pr.GetBaseRepo(); err != nil { + return fmt.Errorf("GetBaseRepo: %v", err) + } + + prUnit, err := pr.BaseRepo.GetUnit(models.UnitTypePullRequests) + if err != nil { + return err + } + prConfig := prUnit.PullRequestsConfig() + + if err := pr.CheckUserAllowedToMerge(doer); err != nil { + return fmt.Errorf("CheckUserAllowedToMerge: %v", err) + } + + // Check if merge style is correct and allowed + if !prConfig.IsMergeStyleAllowed(mergeStyle) { + return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} + } + + defer func() { + go models.HookQueue.Add(pr.BaseRepo.ID) + go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false) + }() + + // Clone base repo. + tmpBasePath, err := models.CreateTemporaryPath("merge") + if err != nil { + return err + } + + defer func() { + if err := models.RemoveTemporaryPath(tmpBasePath); err != nil { + log.Error("Merge: RemoveTemporaryPath: %s", err) + } + }() + + headRepoPath := models.RepoPath(pr.HeadUserName, pr.HeadRepo.Name) + + if err := git.Clone(baseGitRepo.Path, tmpBasePath, git.CloneRepoOptions{ + Shared: true, + NoCheckout: true, + Branch: pr.BaseBranch, + }); err != nil { + return fmt.Errorf("git clone: %v", err) + } + + remoteRepoName := "head_repo" + + // Add head repo remote. + addCacheRepo := func(staging, cache string) error { + p := filepath.Join(staging, ".git", "objects", "info", "alternates") + f, err := os.OpenFile(p, os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + return err + } + defer f.Close() + data := filepath.Join(cache, "objects") + if _, err := fmt.Fprintln(f, data); err != nil { + return err + } + return nil + } + + if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil { + return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err) + } + + var errbuf strings.Builder + if err := git.NewCommand("remote", "add", remoteRepoName, headRepoPath).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + + // Fetch head branch + if err := git.NewCommand("fetch", remoteRepoName).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + + trackingBranch := path.Join(remoteRepoName, pr.HeadBranch) + stagingBranch := fmt.Sprintf("%s_%s", remoteRepoName, pr.HeadBranch) + + // Enable sparse-checkout + sparseCheckoutList, err := getDiffTree(tmpBasePath, pr.BaseBranch, trackingBranch) + if err != nil { + return fmt.Errorf("getDiffTree: %v", err) + } + + infoPath := filepath.Join(tmpBasePath, ".git", "info") + if err := os.MkdirAll(infoPath, 0700); err != nil { + return fmt.Errorf("creating directory failed [%s]: %v", infoPath, err) + } + sparseCheckoutListPath := filepath.Join(infoPath, "sparse-checkout") + if err := ioutil.WriteFile(sparseCheckoutListPath, []byte(sparseCheckoutList), 0600); err != nil { + return fmt.Errorf("Writing sparse-checkout file to %s: %v", sparseCheckoutListPath, err) + } + + // Switch off LFS process (set required, clean and smudge here also) + if err := git.NewCommand("config", "--local", "filter.lfs.process", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git config [filter.lfs.process -> <> ]: %v", errbuf.String()) + } + if err := git.NewCommand("config", "--local", "filter.lfs.required", "false").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git config [filter.lfs.required -> ]: %v", errbuf.String()) + } + if err := git.NewCommand("config", "--local", "filter.lfs.clean", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git config [filter.lfs.clean -> <> ]: %v", errbuf.String()) + } + if err := git.NewCommand("config", "--local", "filter.lfs.smudge", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git config [filter.lfs.smudge -> <> ]: %v", errbuf.String()) + } + + if err := git.NewCommand("config", "--local", "core.sparseCheckout", "true").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", errbuf.String()) + } + + // Read base branch index + if err := git.NewCommand("read-tree", "HEAD").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git read-tree HEAD: %s", errbuf.String()) + } + + // Merge commits. + switch mergeStyle { + case models.MergeStyleMerge: + if err := git.NewCommand("merge", "--no-ff", "--no-commit", trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } + + sig := doer.NewGitSig() + if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } + case models.MergeStyleRebase: + // Checkout head branch + if err := git.NewCommand("checkout", "-b", stagingBranch, trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) + } + // Rebase before merging + if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + // Checkout base branch again + if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) + } + // Merge fast forward + if err := git.NewCommand("merge", "--ff-only", "-q", stagingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + case models.MergeStyleRebaseMerge: + // Checkout head branch + if err := git.NewCommand("checkout", "-b", stagingBranch, trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) + } + // Rebase before merging + if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + // Checkout base branch again + if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git checkout: %s", errbuf.String()) + } + // Prepare merge with commit + if err := git.NewCommand("merge", "--no-ff", "--no-commit", "-q", stagingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --no-ff [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + + // Set custom message and author and create merge commit + sig := doer.NewGitSig() + if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } + + case models.MergeStyleSquash: + // Merge with squash + if err := git.NewCommand("merge", "-q", "--squash", trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + sig := pr.Issue.Poster.NewGitSig() + if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } + default: + return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} + } + + // OK we should cache our current head and origin/headbranch + mergeHeadSHA, err := git.GetFullCommitID(tmpBasePath, "HEAD") + if err != nil { + return fmt.Errorf("Failed to get full commit id for HEAD: %v", err) + } + mergeBaseSHA, err := git.GetFullCommitID(tmpBasePath, "origin/"+pr.BaseBranch) + if err != nil { + return fmt.Errorf("Failed to get full commit id for origin/%s: %v", pr.BaseBranch, err) + } + + // Now it's questionable about where this should go - either after or before the push + // I think in the interests of data safety - failures to push to the lfs should prevent + // the merge as you can always remerge. + if setting.LFS.StartServer { + if err := LFSPush(tmpBasePath, mergeHeadSHA, mergeBaseSHA, pr); err != nil { + return err + } + } + + env := models.PushingEnvironment(doer, pr.BaseRepo) + + // Push back to upstream. + if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git push: %s", errbuf.String()) + } + + pr.MergedCommitID, err = baseGitRepo.GetBranchCommitID(pr.BaseBranch) + if err != nil { + return fmt.Errorf("GetBranchCommit: %v", err) + } + + pr.MergedUnix = util.TimeStampNow() + pr.Merger = doer + pr.MergerID = doer.ID + + if err = pr.SetMerged(); err != nil { + log.Error("setMerged [%d]: %v", pr.ID, err) + } + + if err = models.MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil { + log.Error("MergePullRequestAction [%d]: %v", pr.ID, err) + } + + // Reset cached commit count + cache.Remove(pr.Issue.Repo.GetCommitsCountCacheKey(pr.BaseBranch, true)) + + // Reload pull request information. + if err = pr.LoadAttributes(); err != nil { + log.Error("LoadAttributes: %v", err) + return nil + } + + mode, _ := models.AccessLevel(doer, pr.Issue.Repo) + if err = models.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{ + Action: api.HookIssueClosed, + Index: pr.Index, + PullRequest: pr.APIFormat(), + Repository: pr.Issue.Repo.APIFormat(mode), + Sender: doer.APIFormat(), + }); err != nil { + log.Error("PrepareWebhooks: %v", err) + } else { + go models.HookQueue.Add(pr.Issue.Repo.ID) + } + + l, err := baseGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase) + if err != nil { + log.Error("CommitsBetweenIDs: %v", err) + return nil + } + + // It is possible that head branch is not fully sync with base branch for merge commits, + // so we need to get latest head commit and append merge commit manually + // to avoid strange diff commits produced. + mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch) + if err != nil { + log.Error("GetBranchCommit: %v", err) + return nil + } + if mergeStyle == models.MergeStyleMerge { + l.PushFront(mergeCommit) + } + + p := &api.PushPayload{ + Ref: git.BranchPrefix + pr.BaseBranch, + Before: pr.MergeBase, + After: mergeCommit.ID.String(), + CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID), + Commits: models.ListToPushCommits(l).ToAPIPayloadCommits(pr.BaseRepo.HTMLURL()), + Repo: pr.BaseRepo.APIFormat(mode), + Pusher: pr.HeadRepo.MustOwner().APIFormat(), + Sender: doer.APIFormat(), + } + if err = models.PrepareWebhooks(pr.BaseRepo, models.HookEventPush, p); err != nil { + log.Error("PrepareWebhooks: %v", err) + } else { + go models.HookQueue.Add(pr.BaseRepo.ID) + } + return nil +} + +func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) { + getDiffTreeFromBranch := func(repoPath, baseBranch, headBranch string) (string, error) { + var outbuf, errbuf strings.Builder + // Compute the diff-tree for sparse-checkout + // The branch argument must be enclosed with double-quotes ("") in case it contains slashes (e.g "feature/test") + if err := git.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "--root", baseBranch, headBranch).RunInDirPipeline(repoPath, &outbuf, &errbuf); err != nil { + return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String()) + } + return outbuf.String(), nil + } + + list, err := getDiffTreeFromBranch(repoPath, baseBranch, headBranch) + if err != nil { + return "", err + } + + // Prefixing '/' for each entry, otherwise all files with the same name in subdirectories would be matched. + out := bytes.Buffer{} + scanner := bufio.NewScanner(strings.NewReader(list)) + for scanner.Scan() { + fmt.Fprintf(&out, "/%s\n", scanner.Text()) + } + return out.String(), nil +} diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index b14b0b02b8..d99c9a00c9 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" + "code.gitea.io/gitea/modules/pull" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" ) @@ -595,7 +596,7 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) { message += "\n\n" + form.MergeMessageField } - if err := pr.Merge(ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil { + if err := pull.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil { if models.IsErrInvalidMergeStyle(err) { ctx.Status(405) return diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 5be8aa57c1..36b0d047b1 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" + "code.gitea.io/gitea/modules/pull" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -596,7 +597,7 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) { return } - if err = pr.Merge(ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil { + if err = pull.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil { if models.IsErrInvalidMergeStyle(err) { ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option")) ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index)) From aa7c34cf86081b71f796f6e5da60e62a3cda43ce Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 23 Jun 2019 23:22:43 +0800 Subject: [PATCH 140/220] Fix error log when loading issues caused by a xorm bug (#7271) * fix error log when loading issues caused by a xorm bug * upgrade packages * fix fmt * fix Consistency * fix tests --- go.mod | 17 +- go.sum | 26 +- models/action.go | 2 +- models/consistency.go | 2 +- models/issue.go | 3 +- models/issue_comment.go | 2 +- models/issue_list.go | 76 +- models/issue_reaction.go | 2 +- models/issue_tracked_time.go | 2 +- models/log.go | 2 +- models/login_source.go | 2 +- models/migrations/v31.go | 2 +- models/migrations/v38.go | 2 +- models/migrations/v75.go | 2 +- models/migrations/v78.go | 2 +- models/migrations/v85.go | 2 +- models/models.go | 2 +- models/org.go | 2 +- models/release.go | 2 +- models/repo.go | 2 +- models/repo_list.go | 2 +- models/repo_unit.go | 2 +- models/review.go | 4 +- models/ssh_key.go | 2 +- models/topic.go | 2 +- models/unit_tests.go | 2 +- models/user.go | 4 +- routers/admin/auths.go | 2 +- .../go-sql-driver/mysql/.travis.yml | 2 +- vendor/github.com/go-sql-driver/mysql/AUTHORS | 5 - .../go-sql-driver/mysql/CHANGELOG.md | 11 + .../github.com/go-sql-driver/mysql/README.md | 6 +- vendor/github.com/go-sql-driver/mysql/auth.go | 8 +- .../github.com/go-sql-driver/mysql/buffer.go | 49 +- .../go-sql-driver/mysql/connection.go | 210 +----- .../go-sql-driver/mysql/connection_go18.go | 207 ++++++ .../github.com/go-sql-driver/mysql/driver.go | 15 +- vendor/github.com/go-sql-driver/mysql/dsn.go | 2 +- .../github.com/go-sql-driver/mysql/packets.go | 60 +- .../github.com/go-sql-driver/mysql/utils.go | 31 +- .../go-sql-driver/mysql/utils_go17.go | 40 + .../go-sql-driver/mysql/utils_go18.go | 50 ++ vendor/github.com/go-xorm/builder/go.mod | 1 - vendor/github.com/go-xorm/core/circle.yml | 15 - vendor/github.com/go-xorm/core/db.go | 401 ---------- vendor/github.com/go-xorm/core/go.mod | 1 - vendor/github.com/go-xorm/xorm/.drone.yml | 4 +- vendor/github.com/go-xorm/xorm/README.md | 14 +- vendor/github.com/go-xorm/xorm/README_CN.md | 10 +- vendor/github.com/go-xorm/xorm/cache_lru.go | 2 +- .../go-xorm/xorm/cache_memory_store.go | 2 +- vendor/github.com/go-xorm/xorm/circle.yml | 41 -- .../github.com/go-xorm/xorm/dialect_mssql.go | 26 +- .../github.com/go-xorm/xorm/dialect_mysql.go | 5 +- .../github.com/go-xorm/xorm/dialect_oracle.go | 2 +- .../go-xorm/xorm/dialect_postgres.go | 18 +- .../go-xorm/xorm/dialect_sqlite3.go | 2 +- vendor/github.com/go-xorm/xorm/engine.go | 24 +- vendor/github.com/go-xorm/xorm/engine_cond.go | 13 +- .../github.com/go-xorm/xorm/engine_context.go | 28 + .../github.com/go-xorm/xorm/engine_group.go | 17 +- .../github.com/go-xorm/xorm/engine_table.go | 4 +- vendor/github.com/go-xorm/xorm/error.go | 2 + vendor/github.com/go-xorm/xorm/go.mod | 22 +- vendor/github.com/go-xorm/xorm/go.sum | 50 +- vendor/github.com/go-xorm/xorm/helpers.go | 2 +- vendor/github.com/go-xorm/xorm/interface.go | 12 +- vendor/github.com/go-xorm/xorm/json.go | 31 + vendor/github.com/go-xorm/xorm/logger.go | 2 +- vendor/github.com/go-xorm/xorm/rows.go | 37 +- vendor/github.com/go-xorm/xorm/session.go | 36 +- .../github.com/go-xorm/xorm/session_cols.go | 2 +- .../github.com/go-xorm/xorm/session_cond.go | 2 +- .../xorm/{context.go => session_context.go} | 13 +- .../go-xorm/xorm/session_convert.go | 23 +- .../github.com/go-xorm/xorm/session_delete.go | 6 +- .../github.com/go-xorm/xorm/session_exist.go | 18 +- .../github.com/go-xorm/xorm/session_find.go | 8 +- vendor/github.com/go-xorm/xorm/session_get.go | 6 +- .../github.com/go-xorm/xorm/session_insert.go | 181 ++++- .../go-xorm/xorm/session_iterate.go | 4 + .../github.com/go-xorm/xorm/session_query.go | 26 +- vendor/github.com/go-xorm/xorm/session_raw.go | 34 +- .../github.com/go-xorm/xorm/session_schema.go | 4 +- vendor/github.com/go-xorm/xorm/session_tx.go | 2 +- .../github.com/go-xorm/xorm/session_update.go | 56 +- vendor/github.com/go-xorm/xorm/statement.go | 48 +- vendor/github.com/go-xorm/xorm/syslogger.go | 2 +- vendor/github.com/go-xorm/xorm/tag.go | 2 +- vendor/github.com/go-xorm/xorm/test_mssql.sh | 2 +- vendor/github.com/go-xorm/xorm/test_tidb.sh | 1 + vendor/github.com/go-xorm/xorm/types.go | 6 +- vendor/github.com/go-xorm/xorm/xorm.go | 20 +- .../appengine/internal/api.go | 17 +- .../appengine/internal/api_pre17.go | 682 ------------------ .../appengine/internal/identity.go | 47 +- .../appengine/internal/identity_classic.go | 4 + .../appengine/internal/identity_flex.go | 11 + .../appengine/internal/main.go | 1 + .../appengine/internal/main_common.go | 7 + .../appengine/internal/main_vm.go | 21 + vendor/modules.txt | 16 +- .../go-xorm => xorm.io}/builder/.drone.yml | 0 .../go-xorm => xorm.io}/builder/LICENSE | 0 .../go-xorm => xorm.io}/builder/README.md | 0 .../go-xorm => xorm.io}/builder/builder.go | 0 .../builder/builder_delete.go | 0 .../builder/builder_insert.go | 0 .../builder/builder_limit.go | 0 .../builder/builder_select.go | 0 .../builder/builder_union.go | 0 .../builder/builder_update.go | 0 .../go-xorm => xorm.io}/builder/cond.go | 0 .../go-xorm => xorm.io}/builder/cond_and.go | 0 .../builder/cond_between.go | 0 .../builder/cond_compare.go | 0 .../go-xorm => xorm.io}/builder/cond_eq.go | 0 .../go-xorm => xorm.io}/builder/cond_expr.go | 0 vendor/xorm.io/builder/cond_if.go | 49 ++ .../go-xorm => xorm.io}/builder/cond_in.go | 0 .../go-xorm => xorm.io}/builder/cond_like.go | 0 .../go-xorm => xorm.io}/builder/cond_neq.go | 0 .../go-xorm => xorm.io}/builder/cond_not.go | 0 .../go-xorm => xorm.io}/builder/cond_notin.go | 0 .../go-xorm => xorm.io}/builder/cond_null.go | 0 .../go-xorm => xorm.io}/builder/cond_or.go | 0 .../go-xorm => xorm.io}/builder/doc.go | 0 .../go-xorm => xorm.io}/builder/error.go | 0 vendor/xorm.io/builder/go.mod | 6 + vendor/xorm.io/builder/go.sum | 9 + .../go-xorm => xorm.io}/builder/sql.go | 0 .../builder/string_builder.go | 0 .../go-xorm => xorm.io}/core/.gitignore | 0 .../go-xorm => xorm.io}/core/LICENSE | 0 .../go-xorm => xorm.io}/core/README.md | 0 .../go-xorm => xorm.io}/core/benchmark.sh | 0 .../go-xorm => xorm.io}/core/cache.go | 4 + .../go-xorm => xorm.io}/core/column.go | 11 +- .../go-xorm => xorm.io}/core/converstion.go | 4 + vendor/xorm.io/core/db.go | 223 ++++++ .../go-xorm => xorm.io}/core/dialect.go | 4 + .../go-xorm => xorm.io}/core/driver.go | 4 + .../go-xorm => xorm.io}/core/error.go | 4 + .../go-xorm => xorm.io}/core/filter.go | 4 + vendor/xorm.io/core/go.mod | 7 + vendor/xorm.io/core/go.sum | 9 + .../go-xorm => xorm.io}/core/ilogger.go | 4 + .../go-xorm => xorm.io}/core/index.go | 16 +- .../go-xorm => xorm.io}/core/mapper.go | 4 + .../go-xorm => xorm.io}/core/pk.go | 4 + .../go-xorm => xorm.io}/core/rows.go | 4 + .../go-xorm => xorm.io}/core/scan.go | 11 + vendor/xorm.io/core/stmt.go | 165 +++++ .../go-xorm => xorm.io}/core/table.go | 4 + vendor/xorm.io/core/tx.go | 153 ++++ .../go-xorm => xorm.io}/core/type.go | 18 +- 156 files changed, 1854 insertions(+), 1833 deletions(-) create mode 100644 vendor/github.com/go-sql-driver/mysql/connection_go18.go create mode 100644 vendor/github.com/go-sql-driver/mysql/utils_go17.go create mode 100644 vendor/github.com/go-sql-driver/mysql/utils_go18.go delete mode 100644 vendor/github.com/go-xorm/builder/go.mod delete mode 100644 vendor/github.com/go-xorm/core/circle.yml delete mode 100644 vendor/github.com/go-xorm/core/db.go delete mode 100644 vendor/github.com/go-xorm/core/go.mod delete mode 100644 vendor/github.com/go-xorm/xorm/circle.yml create mode 100644 vendor/github.com/go-xorm/xorm/engine_context.go create mode 100644 vendor/github.com/go-xorm/xorm/json.go rename vendor/github.com/go-xorm/xorm/{context.go => session_context.go} (60%) create mode 100644 vendor/github.com/go-xorm/xorm/test_tidb.sh delete mode 100644 vendor/google.golang.org/appengine/internal/api_pre17.go create mode 100644 vendor/google.golang.org/appengine/internal/identity_flex.go create mode 100644 vendor/google.golang.org/appengine/internal/main_common.go rename vendor/{github.com/go-xorm => xorm.io}/builder/.drone.yml (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/LICENSE (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/README.md (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/builder.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/builder_delete.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/builder_insert.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/builder_limit.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/builder_select.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/builder_union.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/builder_update.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_and.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_between.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_compare.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_eq.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_expr.go (100%) create mode 100644 vendor/xorm.io/builder/cond_if.go rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_in.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_like.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_neq.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_not.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_notin.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_null.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/cond_or.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/doc.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/error.go (100%) create mode 100644 vendor/xorm.io/builder/go.mod create mode 100644 vendor/xorm.io/builder/go.sum rename vendor/{github.com/go-xorm => xorm.io}/builder/sql.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/builder/string_builder.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/core/.gitignore (100%) rename vendor/{github.com/go-xorm => xorm.io}/core/LICENSE (100%) rename vendor/{github.com/go-xorm => xorm.io}/core/README.md (100%) rename vendor/{github.com/go-xorm => xorm.io}/core/benchmark.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/core/cache.go (92%) rename vendor/{github.com/go-xorm => xorm.io}/core/column.go (88%) rename vendor/{github.com/go-xorm => xorm.io}/core/converstion.go (59%) create mode 100644 vendor/xorm.io/core/db.go rename vendor/{github.com/go-xorm => xorm.io}/core/dialect.go (97%) rename vendor/{github.com/go-xorm => xorm.io}/core/driver.go (75%) rename vendor/{github.com/go-xorm => xorm.io}/core/error.go (51%) rename vendor/{github.com/go-xorm => xorm.io}/core/filter.go (90%) create mode 100644 vendor/xorm.io/core/go.mod create mode 100644 vendor/xorm.io/core/go.sum rename vendor/{github.com/go-xorm => xorm.io}/core/ilogger.go (78%) rename vendor/{github.com/go-xorm => xorm.io}/core/index.go (78%) rename vendor/{github.com/go-xorm => xorm.io}/core/mapper.go (96%) rename vendor/{github.com/go-xorm => xorm.io}/core/pk.go (72%) rename vendor/{github.com/go-xorm => xorm.io}/core/rows.go (97%) rename vendor/{github.com/go-xorm => xorm.io}/core/scan.go (79%) create mode 100644 vendor/xorm.io/core/stmt.go rename vendor/{github.com/go-xorm => xorm.io}/core/table.go (95%) create mode 100644 vendor/xorm.io/core/tx.go rename vendor/{github.com/go-xorm => xorm.io}/core/type.go (92%) diff --git a/go.mod b/go.mod index b1a638ed74..6087e52d3e 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f + github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect github.com/emirpasic/gods v1.12.0 @@ -54,10 +54,9 @@ require ( github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 github.com/go-macaron/toolbox v0.0.0-20180818072302-a77f45a7ce90 github.com/go-redis/redis v6.15.2+incompatible - github.com/go-sql-driver/mysql v1.4.0 - github.com/go-xorm/builder v0.3.3 - github.com/go-xorm/core v0.6.0 - github.com/go-xorm/xorm v0.0.0-20190116032649-a6300f2a45e0 + github.com/go-sql-driver/mysql v1.4.1 + github.com/go-xorm/core v0.6.0 // indirect + github.com/go-xorm/xorm v0.7.3-0.20190620151208-f1b4f8368459 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 github.com/gogo/protobuf v1.2.1 // indirect @@ -133,12 +132,12 @@ require ( gopkg.in/redis.v2 v2.3.2 // indirect gopkg.in/src-d/go-billy.v4 v4.3.0 gopkg.in/src-d/go-git.v4 v4.12.0 + gopkg.in/stretchr/testify.v1 v1.2.2 // indirect gopkg.in/testfixtures.v2 v2.5.0 mvdan.cc/xurls/v2 v2.0.0 strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a + xorm.io/builder v0.3.5 + xorm.io/core v0.6.3 ) -replace ( - github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 - github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f -) +replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 diff --git a/go.sum b/go.sum index f6542fbe49..9d5e2c9c50 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 h1:UsHpWO0Elp6NaWVARdZHjiYwkhrspHVEGsyIKPb9OI8= @@ -117,17 +119,14 @@ github.com/go-macaron/toolbox v0.0.0-20180818072302-a77f45a7ce90 h1:3wYKrRg9IjUM github.com/go-macaron/toolbox v0.0.0-20180818072302-a77f45a7ce90/go.mod h1:Ut/NmkIMGVYlEdJBzEZgWVWG5ZpYS9BLmUgXfAgi+qM= github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f h1:fbIzwEaXt5b2bl9mm+PIufKTSGKk6ZuwSSTQ7iZj7Lo= -github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-xorm/builder v0.3.2/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk= -github.com/go-xorm/builder v0.3.3 h1:v8grgrwOGv/iHXIEhIvOwHZIPLrpxRKSX8yWSMLFn/4= -github.com/go-xorm/builder v0.3.3/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-xorm/core v0.6.0 h1:tp6hX+ku4OD9khFZS8VGBDRY3kfVCtelPfmkgCyHxL0= github.com/go-xorm/core v0.6.0/go.mod h1:d8FJ9Br8OGyQl12MCclmYBuBqqxsyeedpXciV5Myih8= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/go-xorm/xorm v0.0.0-20190116032649-a6300f2a45e0 h1:GBnJjWjp2SGXBZsyZfYksyp7QocvQwf9vZQ0NRN2FXM= -github.com/go-xorm/xorm v0.0.0-20190116032649-a6300f2a45e0/go.mod h1:EHS1htMQFptzMaIHKyzqpHGw6C9Rtug75nsq6DA9unI= +github.com/go-xorm/xorm v0.7.3-0.20190620151208-f1b4f8368459 h1:JGEuhH169J7Wtm1hN/HFOGENsAq+6FDHfuhGEZj/1e4= +github.com/go-xorm/xorm v0.7.3-0.20190620151208-f1b4f8368459/go.mod h1:UK1YDlWscDspd23xW9HC24749jhvwO6riZ/HUt3gbHQ= github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA= github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 h1:EBTlva3AOSb80G3JSwY6ZMdILEZJ1JKuewrbqrNjWuE= @@ -170,8 +169,8 @@ github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c h1:A/PDn117UYld5m github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c/go.mod h1:5mTb/PQNkqmq2x3IxlQZE0aSnTksJg7fg/oWmJ5SKXQ= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY= -github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90= +github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06RVW8OMby+GrmW6K2nPO3AFHlEIdvJSd4= github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= @@ -225,7 +224,6 @@ github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d h1:m+dSK37rFf2fqppZhg15yI2IwC9BtucBiRwSDm9VL8g= github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d/go.mod h1:/M9VLO+lUPmxvoOK2PfWRZ8mTtB4q1Hy9lEGijv9Nr8= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -255,7 +253,6 @@ github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWo github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -328,6 +325,7 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190122013713-64072686203f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk= @@ -376,6 +374,8 @@ golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a/go.mod h1:/rFqwRUd4F7ZHNgw google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8KqxhFwKci30UxHy3HXPTyQ= @@ -419,3 +419,7 @@ mvdan.cc/xurls/v2 v2.0.0 h1:r1zSOSNS/kqtpmATyMMMvaZ4/djsesbYz5kr0+qMRWc= mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a h1:8q33ShxKXRwQ7JVd1ZnhIU3hZhwwn0Le+4fTeAackuM= strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= +xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A= +xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= +xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M= +xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo= diff --git a/models/action.go b/models/action.go index ee5d052509..89283930e9 100644 --- a/models/action.go +++ b/models/action.go @@ -24,7 +24,7 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" - "github.com/go-xorm/builder" + "xorm.io/builder" ) // ActionType represents the type of an action. diff --git a/models/consistency.go b/models/consistency.go index 0c279eaaf8..f9fa3028fd 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -39,7 +39,7 @@ func CheckConsistencyFor(t *testing.T, beansToCheck ...interface{}) { ptrToSliceValue := reflect.New(sliceType) ptrToSliceValue.Elem().Set(sliceValue) - assert.NoError(t, x.Where(bean).Find(ptrToSliceValue.Interface())) + assert.NoError(t, x.Table(bean).Find(ptrToSliceValue.Interface())) sliceValue = ptrToSliceValue.Elem() for i := 0; i < sliceValue.Len(); i++ { diff --git a/models/issue.go b/models/issue.go index 27298b8a86..b5504beb71 100644 --- a/models/issue.go +++ b/models/issue.go @@ -19,8 +19,8 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" + "xorm.io/builder" ) // Issue represents an issue or pull request of repository. @@ -1428,6 +1428,7 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { if err := sess.Find(&issues); err != nil { return nil, fmt.Errorf("Find: %v", err) } + sess.Close() if err := IssueList(issues).LoadAttributes(); err != nil { return nil, fmt.Errorf("LoadAttributes: %v", err) diff --git a/models/issue_comment.go b/models/issue_comment.go index d75d9d7db1..c9f1bd9d5f 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -15,8 +15,8 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "github.com/Unknwon/com" - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" + "xorm.io/builder" api "code.gitea.io/gitea/modules/structs" diff --git a/models/issue_list.go b/models/issue_list.go index 4ddb32da13..e3516b55b9 100644 --- a/models/issue_list.go +++ b/models/issue_list.go @@ -7,9 +7,7 @@ package models import ( "fmt" - "code.gitea.io/gitea/modules/log" - - "github.com/go-xorm/builder" + "xorm.io/builder" ) // IssueList defines a list of issues @@ -148,19 +146,17 @@ func (issues IssueList) loadLabels(e Engine) error { var labelIssue LabelIssue err = rows.Scan(&labelIssue) if err != nil { - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadLabels: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadLabels: Close: %v", err1) } return err } issueLabels[labelIssue.IssueLabel.IssueID] = append(issueLabels[labelIssue.IssueLabel.IssueID], labelIssue.Label) } - // When there are no rows left and we try to close it, xorm will complain with an error. + // When there are no rows left and we try to close it. // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadLabels: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadLabels: Close: %v", err1) } left -= limit issueIDs = issueIDs[limit:] @@ -241,20 +237,16 @@ func (issues IssueList) loadAssignees(e Engine) error { var assigneeIssue AssigneeIssue err = rows.Scan(&assigneeIssue) if err != nil { - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadAssignees: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadAssignees: Close: %v", err1) } return err } assignees[assigneeIssue.IssueAssignee.IssueID] = append(assignees[assigneeIssue.IssueAssignee.IssueID], assigneeIssue.Assignee) } - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadAssignees: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadAssignees: Close: %v", err1) } left -= limit issueIDs = issueIDs[limit:] @@ -300,19 +292,15 @@ func (issues IssueList) loadPullRequests(e Engine) error { var pr PullRequest err = rows.Scan(&pr) if err != nil { - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadPullRequests: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadPullRequests: Close: %v", err1) } return err } pullRequestMaps[pr.IssueID] = &pr } - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadPullRequests: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadPullRequests: Close: %v", err1) } left -= limit issuesIDs = issuesIDs[limit:] @@ -349,19 +337,15 @@ func (issues IssueList) loadAttachments(e Engine) (err error) { var attachment Attachment err = rows.Scan(&attachment) if err != nil { - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadAttachments: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadAttachments: Close: %v", err1) } return err } attachments[attachment.IssueID] = append(attachments[attachment.IssueID], &attachment) } - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadAttachments: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadAttachments: Close: %v", err1) } left -= limit issuesIDs = issuesIDs[limit:] @@ -399,19 +383,15 @@ func (issues IssueList) loadComments(e Engine, cond builder.Cond) (err error) { var comment Comment err = rows.Scan(&comment) if err != nil { - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadComments: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadComments: Close: %v", err1) } return err } comments[comment.IssueID] = append(comments[comment.IssueID], &comment) } - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadComments: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadComments: Close: %v", err1) } left -= limit issuesIDs = issuesIDs[limit:] @@ -461,19 +441,15 @@ func (issues IssueList) loadTotalTrackedTimes(e Engine) (err error) { var totalTime totalTimesByIssue err = rows.Scan(&totalTime) if err != nil { - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadTotalTrackedTimes: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadTotalTrackedTimes: Close: %v", err1) } return err } trackedTimes[totalTime.IssueID] = totalTime.Time } - // When there are no rows left and we try to close it, xorm will complain with an error. - // Since that is not relevant for us, we can safely ignore it. - if err := rows.Close(); err != nil { - log.Error("IssueList.loadTotalTrackedTimes: Close: %v", err) + if err1 := rows.Close(); err1 != nil { + return fmt.Errorf("IssueList.loadTotalTrackedTimes: Close: %v", err1) } left -= limit ids = ids[limit:] diff --git a/models/issue_reaction.go b/models/issue_reaction.go index 8f3ee7bfe2..e0df6f757b 100644 --- a/models/issue_reaction.go +++ b/models/issue_reaction.go @@ -11,8 +11,8 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" + "xorm.io/builder" ) // Reaction represents a reactions on issues and comments. diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go index 56ba525776..5482a45f2a 100644 --- a/models/issue_tracked_time.go +++ b/models/issue_tracked_time.go @@ -10,8 +10,8 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" + "xorm.io/builder" ) // TrackedTime represents a time that was spent for a specific issue. diff --git a/models/log.go b/models/log.go index 38d6caf07c..4caea9a8b7 100644 --- a/models/log.go +++ b/models/log.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/log" - "github.com/go-xorm/core" + "xorm.io/core" ) // XORMLogBridge a logger bridge from Logger to xorm diff --git a/models/login_source.go b/models/login_source.go index 8eefec4ae5..626c232772 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -15,8 +15,8 @@ import ( "strings" "github.com/Unknwon/com" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/core" "code.gitea.io/gitea/modules/auth/ldap" "code.gitea.io/gitea/modules/auth/oauth2" diff --git a/models/migrations/v31.go b/models/migrations/v31.go index b7ceecfc38..d6cea4c51b 100644 --- a/models/migrations/v31.go +++ b/models/migrations/v31.go @@ -8,8 +8,8 @@ import ( "fmt" "time" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/core" ) func addLoginSourceSyncEnabledColumn(x *xorm.Engine) error { diff --git a/models/migrations/v38.go b/models/migrations/v38.go index eb90f9fbff..6060b70fe8 100644 --- a/models/migrations/v38.go +++ b/models/migrations/v38.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/models" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/core" ) func removeCommitsUnitType(x *xorm.Engine) (err error) { diff --git a/models/migrations/v75.go b/models/migrations/v75.go index 62f92b77db..58d1d34c98 100644 --- a/models/migrations/v75.go +++ b/models/migrations/v75.go @@ -5,8 +5,8 @@ package migrations import ( - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" + "xorm.io/builder" ) func clearNonusedData(x *xorm.Engine) error { diff --git a/models/migrations/v78.go b/models/migrations/v78.go index 310c479d01..511a4f57fa 100644 --- a/models/migrations/v78.go +++ b/models/migrations/v78.go @@ -10,8 +10,8 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/core" ) func renameRepoIsBareToIsEmpty(x *xorm.Engine) error { diff --git a/models/migrations/v85.go b/models/migrations/v85.go index d511628b8d..b8d0ee5443 100644 --- a/models/migrations/v85.go +++ b/models/migrations/v85.go @@ -7,8 +7,8 @@ package migrations import ( "fmt" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/core" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/generate" diff --git a/models/models.go b/models/models.go index 5752a8edd6..3b3d8ec30a 100644 --- a/models/models.go +++ b/models/models.go @@ -20,8 +20,8 @@ import ( // Needed for the MySQL driver _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/core" // Needed for the Postgresql driver _ "github.com/lib/pq" diff --git a/models/org.go b/models/org.go index 65002eadff..d86109de57 100644 --- a/models/org.go +++ b/models/org.go @@ -15,8 +15,8 @@ import ( "code.gitea.io/gitea/modules/structs" "github.com/Unknwon/com" - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" + "xorm.io/builder" ) var ( diff --git a/models/release.go b/models/release.go index 28a2891013..036b5f78b9 100644 --- a/models/release.go +++ b/models/release.go @@ -16,7 +16,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - "github.com/go-xorm/builder" + "xorm.io/builder" ) // Release represents a release of repository. diff --git a/models/repo.go b/models/repo.go index 215222e279..2f732d0e26 100644 --- a/models/repo.go +++ b/models/repo.go @@ -37,9 +37,9 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" ini "gopkg.in/ini.v1" + "xorm.io/builder" ) var repoWorkingPool = sync.NewExclusivePool() diff --git a/models/repo_list.go b/models/repo_list.go index 5655404f7c..7460c4b0ed 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - "github.com/go-xorm/builder" + "xorm.io/builder" ) // RepositoryListDefaultPageSize is the default number of repositories diff --git a/models/repo_unit.go b/models/repo_unit.go index 430f5a242f..80126270de 100644 --- a/models/repo_unit.go +++ b/models/repo_unit.go @@ -10,8 +10,8 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/core" ) // RepoUnit describes all units of a repository diff --git a/models/review.go b/models/review.go index 5f856fbd89..458d58152e 100644 --- a/models/review.go +++ b/models/review.go @@ -11,9 +11,9 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" + "xorm.io/builder" + "xorm.io/core" ) // ReviewType defines the sort of feedback a review gives diff --git a/models/ssh_key.go b/models/ssh_key.go index 15a10826d8..ceb4d97560 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -25,9 +25,9 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" - "github.com/go-xorm/builder" "github.com/go-xorm/xorm" "golang.org/x/crypto/ssh" + "xorm.io/builder" ) const ( diff --git a/models/topic.go b/models/topic.go index da1815be76..666196ba8e 100644 --- a/models/topic.go +++ b/models/topic.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/util" - "github.com/go-xorm/builder" + "xorm.io/builder" ) func init() { diff --git a/models/unit_tests.go b/models/unit_tests.go index 19fc95ea65..330dc5ee4e 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -18,10 +18,10 @@ import ( "code.gitea.io/gitea/modules/setting" "github.com/Unknwon/com" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" "github.com/stretchr/testify/assert" "gopkg.in/testfixtures.v2" + "xorm.io/core" ) // NonexistentID an ID that will never exist diff --git a/models/user.go b/models/user.go index 4dc9aec650..aa392b1ea9 100644 --- a/models/user.go +++ b/models/user.go @@ -32,11 +32,11 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" "github.com/go-xorm/xorm" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/ssh" + "xorm.io/builder" + "xorm.io/core" ) // UserType defines the user type diff --git a/routers/admin/auths.go b/routers/admin/auths.go index 40b7df108d..81751f8955 100644 --- a/routers/admin/auths.go +++ b/routers/admin/auths.go @@ -17,7 +17,7 @@ import ( "code.gitea.io/gitea/modules/setting" "github.com/Unknwon/com" - "github.com/go-xorm/core" + "xorm.io/core" ) const ( diff --git a/vendor/github.com/go-sql-driver/mysql/.travis.yml b/vendor/github.com/go-sql-driver/mysql/.travis.yml index 75505f1440..cc1268c361 100644 --- a/vendor/github.com/go-sql-driver/mysql/.travis.yml +++ b/vendor/github.com/go-sql-driver/mysql/.travis.yml @@ -1,10 +1,10 @@ sudo: false language: go go: + - 1.7.x - 1.8.x - 1.9.x - 1.10.x - - 1.11.x - master before_install: diff --git a/vendor/github.com/go-sql-driver/mysql/AUTHORS b/vendor/github.com/go-sql-driver/mysql/AUTHORS index 5ce4f7eca1..73ff68fbcf 100644 --- a/vendor/github.com/go-sql-driver/mysql/AUTHORS +++ b/vendor/github.com/go-sql-driver/mysql/AUTHORS @@ -35,7 +35,6 @@ Hanno Braun Henri Yandell Hirotaka Yamamoto ICHINOSE Shogo -Ilia Cimpoes INADA Naoki Jacek Szwec James Harr @@ -73,9 +72,6 @@ Shuode Li Soroush Pour Stan Putrya Stanley Gunawan -Steven Hartland -Thomas Wodarek -Tom Jenkinson Xiangyu Hu Xiaobing Jiang Xiuming Chen @@ -91,4 +87,3 @@ Keybase Inc. Percona LLC Pivotal Inc. Stripe Inc. -Multiplay Ltd. diff --git a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md index 2d87d74c97..ce1b5330a9 100644 --- a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md +++ b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md @@ -1,3 +1,14 @@ +## Version 1.4.1 (2018-11-14) + +Bugfixes: + + - Fix TIME format for binary columns (#818) + - Fix handling of empty auth plugin names (#835) + - Fix caching_sha2_password with empty password (#826) + - Fix canceled context broke mysqlConn (#862) + - Fix OldAuthSwitchRequest support (#870) + - Fix Auth Response packet for cleartext password (#887) + ## Version 1.4 (2018-06-03) Changes: diff --git a/vendor/github.com/go-sql-driver/mysql/README.md b/vendor/github.com/go-sql-driver/mysql/README.md index 341d9194c1..2e9b07eeb2 100644 --- a/vendor/github.com/go-sql-driver/mysql/README.md +++ b/vendor/github.com/go-sql-driver/mysql/README.md @@ -40,7 +40,7 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac * Optional placeholder interpolation ## Requirements - * Go 1.8 or higher. We aim to support the 3 latest versions of Go. + * Go 1.7 or higher. We aim to support the 3 latest versions of Go. * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+) --------------------------------------- @@ -328,11 +328,11 @@ Timeout for establishing connections, aka dial timeout. The value must be a deci ``` Type: bool / string -Valid Values: true, false, skip-verify, preferred, +Valid Values: true, false, skip-verify, Default: false ``` -`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). +`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). ##### `writeTimeout` diff --git a/vendor/github.com/go-sql-driver/mysql/auth.go b/vendor/github.com/go-sql-driver/mysql/auth.go index fec7040d4a..14f678a87b 100644 --- a/vendor/github.com/go-sql-driver/mysql/auth.go +++ b/vendor/github.com/go-sql-driver/mysql/auth.go @@ -360,15 +360,13 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error { pubKey := mc.cfg.pubKey if pubKey == nil { // request public key from server - data, err := mc.buf.takeSmallBuffer(4 + 1) - if err != nil { - return err - } + data := mc.buf.takeSmallBuffer(4 + 1) data[4] = cachingSha2PasswordRequestPublicKey mc.writePacket(data) // parse public key - if data, err = mc.readPacket(); err != nil { + data, err := mc.readPacket() + if err != nil { return err } diff --git a/vendor/github.com/go-sql-driver/mysql/buffer.go b/vendor/github.com/go-sql-driver/mysql/buffer.go index 19486bd6f6..eb4748bf44 100644 --- a/vendor/github.com/go-sql-driver/mysql/buffer.go +++ b/vendor/github.com/go-sql-driver/mysql/buffer.go @@ -22,17 +22,17 @@ const defaultBufSize = 4096 // The buffer is similar to bufio.Reader / Writer but zero-copy-ish // Also highly optimized for this particular use case. type buffer struct { - buf []byte // buf is a byte buffer who's length and capacity are equal. + buf []byte nc net.Conn idx int length int timeout time.Duration } -// newBuffer allocates and returns a new buffer. func newBuffer(nc net.Conn) buffer { + var b [defaultBufSize]byte return buffer{ - buf: make([]byte, defaultBufSize), + buf: b[:], nc: nc, } } @@ -105,56 +105,43 @@ func (b *buffer) readNext(need int) ([]byte, error) { return b.buf[offset:b.idx], nil } -// takeBuffer returns a buffer with the requested size. +// returns a buffer with the requested size. // If possible, a slice from the existing buffer is returned. // Otherwise a bigger buffer is made. // Only one buffer (total) can be used at a time. -func (b *buffer) takeBuffer(length int) ([]byte, error) { +func (b *buffer) takeBuffer(length int) []byte { if b.length > 0 { - return nil, ErrBusyBuffer + return nil } // test (cheap) general case first - if length <= cap(b.buf) { - return b.buf[:length], nil + if length <= defaultBufSize || length <= cap(b.buf) { + return b.buf[:length] } if length < maxPacketSize { b.buf = make([]byte, length) - return b.buf, nil + return b.buf } - - // buffer is larger than we want to store. - return make([]byte, length), nil + return make([]byte, length) } -// takeSmallBuffer is shortcut which can be used if length is -// known to be smaller than defaultBufSize. +// shortcut which can be used if the requested buffer is guaranteed to be +// smaller than defaultBufSize // Only one buffer (total) can be used at a time. -func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { +func (b *buffer) takeSmallBuffer(length int) []byte { if b.length > 0 { - return nil, ErrBusyBuffer + return nil } - return b.buf[:length], nil + return b.buf[:length] } // takeCompleteBuffer returns the complete existing buffer. // This can be used if the necessary buffer size is unknown. -// cap and len of the returned buffer will be equal. // Only one buffer (total) can be used at a time. -func (b *buffer) takeCompleteBuffer() ([]byte, error) { +func (b *buffer) takeCompleteBuffer() []byte { if b.length > 0 { - return nil, ErrBusyBuffer + return nil } - return b.buf, nil -} - -// store stores buf, an updated buffer, if its suitable to do so. -func (b *buffer) store(buf []byte) error { - if b.length > 0 { - return ErrBusyBuffer - } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) { - b.buf = buf[:cap(buf)] - } - return nil + return b.buf } diff --git a/vendor/github.com/go-sql-driver/mysql/connection.go b/vendor/github.com/go-sql-driver/mysql/connection.go index fc4ec7597d..e57061412b 100644 --- a/vendor/github.com/go-sql-driver/mysql/connection.go +++ b/vendor/github.com/go-sql-driver/mysql/connection.go @@ -9,8 +9,6 @@ package mysql import ( - "context" - "database/sql" "database/sql/driver" "io" "net" @@ -19,6 +17,16 @@ import ( "time" ) +// a copy of context.Context for Go 1.7 and earlier +type mysqlContext interface { + Done() <-chan struct{} + Err() error + + // defined in context.Context, but not used in this driver: + // Deadline() (deadline time.Time, ok bool) + // Value(key interface{}) interface{} +} + type mysqlConn struct { buf buffer netConn net.Conn @@ -35,7 +43,7 @@ type mysqlConn struct { // for context support (Go 1.8+) watching bool - watcher chan<- context.Context + watcher chan<- mysqlContext closech chan struct{} finished chan<- struct{} canceled atomicError // set non-nil if conn is canceled @@ -182,10 +190,10 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin return "", driver.ErrSkip } - buf, err := mc.buf.takeCompleteBuffer() - if err != nil { + buf := mc.buf.takeCompleteBuffer() + if buf == nil { // can not take the buffer. Something must be wrong with the connection - errLog.Print(err) + errLog.Print(ErrBusyBuffer) return "", ErrInvalidConn } buf = buf[:0] @@ -451,193 +459,3 @@ func (mc *mysqlConn) finish() { case <-mc.closech: } } - -// Ping implements driver.Pinger interface -func (mc *mysqlConn) Ping(ctx context.Context) (err error) { - if mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return driver.ErrBadConn - } - - if err = mc.watchCancel(ctx); err != nil { - return - } - defer mc.finish() - - if err = mc.writeCommandPacket(comPing); err != nil { - return mc.markBadConn(err) - } - - return mc.readResultOK() -} - -// BeginTx implements driver.ConnBeginTx interface -func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - defer mc.finish() - - if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { - level, err := mapIsolationLevel(opts.Isolation) - if err != nil { - return nil, err - } - err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) - if err != nil { - return nil, err - } - } - - return mc.begin(opts.ReadOnly) -} - -func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - - rows, err := mc.query(query, dargs) - if err != nil { - mc.finish() - return nil, err - } - rows.finish = mc.finish - return rows, err -} - -func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - defer mc.finish() - - return mc.Exec(query, dargs) -} - -func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - - stmt, err := mc.Prepare(query) - mc.finish() - if err != nil { - return nil, err - } - - select { - default: - case <-ctx.Done(): - stmt.Close() - return nil, ctx.Err() - } - return stmt, nil -} - -func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := stmt.mc.watchCancel(ctx); err != nil { - return nil, err - } - - rows, err := stmt.query(dargs) - if err != nil { - stmt.mc.finish() - return nil, err - } - rows.finish = stmt.mc.finish - return rows, err -} - -func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := stmt.mc.watchCancel(ctx); err != nil { - return nil, err - } - defer stmt.mc.finish() - - return stmt.Exec(dargs) -} - -func (mc *mysqlConn) watchCancel(ctx context.Context) error { - if mc.watching { - // Reach here if canceled, - // so the connection is already invalid - mc.cleanup() - return nil - } - // When ctx is already cancelled, don't watch it. - if err := ctx.Err(); err != nil { - return err - } - // When ctx is not cancellable, don't watch it. - if ctx.Done() == nil { - return nil - } - // When watcher is not alive, can't watch it. - if mc.watcher == nil { - return nil - } - - mc.watching = true - mc.watcher <- ctx - return nil -} - -func (mc *mysqlConn) startWatcher() { - watcher := make(chan context.Context, 1) - mc.watcher = watcher - finished := make(chan struct{}) - mc.finished = finished - go func() { - for { - var ctx context.Context - select { - case ctx = <-watcher: - case <-mc.closech: - return - } - - select { - case <-ctx.Done(): - mc.cancel(ctx.Err()) - case <-finished: - case <-mc.closech: - return - } - } - }() -} - -func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { - nv.Value, err = converter{}.ConvertValue(nv.Value) - return -} - -// ResetSession implements driver.SessionResetter. -// (From Go 1.10) -func (mc *mysqlConn) ResetSession(ctx context.Context) error { - if mc.closed.IsSet() { - return driver.ErrBadConn - } - return nil -} diff --git a/vendor/github.com/go-sql-driver/mysql/connection_go18.go b/vendor/github.com/go-sql-driver/mysql/connection_go18.go new file mode 100644 index 0000000000..ce52c7d167 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/connection_go18.go @@ -0,0 +1,207 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// 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/. + +// +build go1.8 + +package mysql + +import ( + "context" + "database/sql" + "database/sql/driver" +) + +// Ping implements driver.Pinger interface +func (mc *mysqlConn) Ping(ctx context.Context) (err error) { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return driver.ErrBadConn + } + + if err = mc.watchCancel(ctx); err != nil { + return + } + defer mc.finish() + + if err = mc.writeCommandPacket(comPing); err != nil { + return + } + + return mc.readResultOK() +} + +// BeginTx implements driver.ConnBeginTx interface +func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { + level, err := mapIsolationLevel(opts.Isolation) + if err != nil { + return nil, err + } + err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) + if err != nil { + return nil, err + } + } + + return mc.begin(opts.ReadOnly) +} + +func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := mc.query(query, dargs) + if err != nil { + mc.finish() + return nil, err + } + rows.finish = mc.finish + return rows, err +} + +func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + return mc.Exec(query, dargs) +} + +func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + stmt, err := mc.Prepare(query) + mc.finish() + if err != nil { + return nil, err + } + + select { + default: + case <-ctx.Done(): + stmt.Close() + return nil, ctx.Err() + } + return stmt, nil +} + +func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := stmt.query(dargs) + if err != nil { + stmt.mc.finish() + return nil, err + } + rows.finish = stmt.mc.finish + return rows, err +} + +func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + defer stmt.mc.finish() + + return stmt.Exec(dargs) +} + +func (mc *mysqlConn) watchCancel(ctx context.Context) error { + if mc.watching { + // Reach here if canceled, + // so the connection is already invalid + mc.cleanup() + return nil + } + // When ctx is already cancelled, don't watch it. + if err := ctx.Err(); err != nil { + return err + } + // When ctx is not cancellable, don't watch it. + if ctx.Done() == nil { + return nil + } + // When watcher is not alive, can't watch it. + if mc.watcher == nil { + return nil + } + + mc.watching = true + mc.watcher <- ctx + return nil +} + +func (mc *mysqlConn) startWatcher() { + watcher := make(chan mysqlContext, 1) + mc.watcher = watcher + finished := make(chan struct{}) + mc.finished = finished + go func() { + for { + var ctx mysqlContext + select { + case ctx = <-watcher: + case <-mc.closech: + return + } + + select { + case <-ctx.Done(): + mc.cancel(ctx.Err()) + case <-finished: + case <-mc.closech: + return + } + } + }() +} + +func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { + nv.Value, err = converter{}.ConvertValue(nv.Value) + return +} + +// ResetSession implements driver.SessionResetter. +// (From Go 1.10) +func (mc *mysqlConn) ResetSession(ctx context.Context) error { + if mc.closed.IsSet() { + return driver.ErrBadConn + } + return nil +} diff --git a/vendor/github.com/go-sql-driver/mysql/driver.go b/vendor/github.com/go-sql-driver/mysql/driver.go index 9f4967087f..e9ede2c8da 100644 --- a/vendor/github.com/go-sql-driver/mysql/driver.go +++ b/vendor/github.com/go-sql-driver/mysql/driver.go @@ -23,6 +23,11 @@ import ( "sync" ) +// watcher interface is used for context support (From Go 1.8) +type watcher interface { + startWatcher() +} + // MySQLDriver is exported to make the driver directly accessible. // In general the driver is used via the database/sql package. type MySQLDriver struct{} @@ -50,7 +55,7 @@ func RegisterDial(net string, dial DialFunc) { // Open new Connection. // See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how -// the DSN string is formatted +// the DSN string is formated func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { var err error @@ -77,10 +82,6 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr) } if err != nil { - if nerr, ok := err.(net.Error); ok && nerr.Temporary() { - errLog.Print("net.Error from Dial()': ", nerr.Error()) - return nil, driver.ErrBadConn - } return nil, err } @@ -95,7 +96,9 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { } // Call startWatcher for context support (From Go 1.8) - mc.startWatcher() + if s, ok := interface{}(mc).(watcher); ok { + s.startWatcher() + } mc.buf = newBuffer(mc.netConn) diff --git a/vendor/github.com/go-sql-driver/mysql/dsn.go b/vendor/github.com/go-sql-driver/mysql/dsn.go index b9134722eb..be014babe3 100644 --- a/vendor/github.com/go-sql-driver/mysql/dsn.go +++ b/vendor/github.com/go-sql-driver/mysql/dsn.go @@ -560,7 +560,7 @@ func parseDSNParams(cfg *Config, params string) (err error) { } else { cfg.TLSConfig = "false" } - } else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" { + } else if vl := strings.ToLower(value); vl == "skip-verify" { cfg.TLSConfig = vl cfg.tls = &tls.Config{InsecureSkipVerify: true} } else { diff --git a/vendor/github.com/go-sql-driver/mysql/packets.go b/vendor/github.com/go-sql-driver/mysql/packets.go index 5e0853767d..9ed6408509 100644 --- a/vendor/github.com/go-sql-driver/mysql/packets.go +++ b/vendor/github.com/go-sql-driver/mysql/packets.go @@ -51,7 +51,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { mc.sequence++ // packets with length 0 terminate a previous packet which is a - // multiple of (2^24)-1 bytes long + // multiple of (2^24)−1 bytes long if pktLen == 0 { // there was no previous packet if prevData == nil { @@ -194,11 +194,7 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro return nil, "", ErrOldProtocol } if mc.flags&clientSSL == 0 && mc.cfg.tls != nil { - if mc.cfg.TLSConfig == "preferred" { - mc.cfg.tls = nil - } else { - return nil, "", ErrNoTLS - } + return nil, "", ErrNoTLS } pos += 2 @@ -290,10 +286,10 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string } // Calculate packet length and get buffer with that size - data, err := mc.buf.takeSmallBuffer(pktLen + 4) - if err != nil { + data := mc.buf.takeSmallBuffer(pktLen + 4) + if data == nil { // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) + errLog.Print(ErrBusyBuffer) return errBadConnNoWrite } @@ -371,10 +367,10 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { pktLen := 4 + len(authData) - data, err := mc.buf.takeSmallBuffer(pktLen) - if err != nil { + data := mc.buf.takeSmallBuffer(pktLen) + if data == nil { // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) + errLog.Print(ErrBusyBuffer) return errBadConnNoWrite } @@ -391,10 +387,10 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error { // Reset Packet Sequence mc.sequence = 0 - data, err := mc.buf.takeSmallBuffer(4 + 1) - if err != nil { + data := mc.buf.takeSmallBuffer(4 + 1) + if data == nil { // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) + errLog.Print(ErrBusyBuffer) return errBadConnNoWrite } @@ -410,10 +406,10 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { mc.sequence = 0 pktLen := 1 + len(arg) - data, err := mc.buf.takeBuffer(pktLen + 4) - if err != nil { + data := mc.buf.takeBuffer(pktLen + 4) + if data == nil { // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) + errLog.Print(ErrBusyBuffer) return errBadConnNoWrite } @@ -431,10 +427,10 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { // Reset Packet Sequence mc.sequence = 0 - data, err := mc.buf.takeSmallBuffer(4 + 1 + 4) - if err != nil { + data := mc.buf.takeSmallBuffer(4 + 1 + 4) + if data == nil { // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) + errLog.Print(ErrBusyBuffer) return errBadConnNoWrite } @@ -887,7 +883,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { const minPktLen = 4 + 1 + 4 + 1 + 4 mc := stmt.mc - // Determine threshold dynamically to avoid packet size shortage. + // Determine threshould dynamically to avoid packet size shortage. longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) if longDataSize < 64 { longDataSize = 64 @@ -897,17 +893,15 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { mc.sequence = 0 var data []byte - var err error if len(args) == 0 { - data, err = mc.buf.takeBuffer(minPktLen) + data = mc.buf.takeBuffer(minPktLen) } else { - data, err = mc.buf.takeCompleteBuffer() - // In this case the len(data) == cap(data) which is used to optimise the flow below. + data = mc.buf.takeCompleteBuffer() } - if err != nil { + if data == nil { // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) + errLog.Print(ErrBusyBuffer) return errBadConnNoWrite } @@ -933,7 +927,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { pos := minPktLen var nullMask []byte - if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= cap(data) { + if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= len(data) { // buffer has to be extended but we don't know by how much so // we depend on append after all data with known sizes fit. // We stop at that because we deal with a lot of columns here @@ -942,11 +936,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { copy(tmp[:pos], data[:pos]) data = tmp nullMask = data[pos : pos+maskLen] - // No need to clean nullMask as make ensures that. pos += maskLen } else { nullMask = data[pos : pos+maskLen] - for i := range nullMask { + for i := 0; i < maskLen; i++ { nullMask[i] = 0 } pos += maskLen @@ -1083,10 +1076,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // In that case we must build the data packet with the new values buffer if valuesCap != cap(paramValues) { data = append(data[:pos], paramValues...) - if err = mc.buf.store(data); err != nil { - errLog.Print(err) - return errBadConnNoWrite - } + mc.buf.buf = data } pos += len(paramValues) diff --git a/vendor/github.com/go-sql-driver/mysql/utils.go b/vendor/github.com/go-sql-driver/mysql/utils.go index cb3650bb9b..ca5d47d825 100644 --- a/vendor/github.com/go-sql-driver/mysql/utils.go +++ b/vendor/github.com/go-sql-driver/mysql/utils.go @@ -10,10 +10,8 @@ package mysql import ( "crypto/tls" - "database/sql" "database/sql/driver" "encoding/binary" - "errors" "fmt" "io" "strconv" @@ -82,7 +80,7 @@ func DeregisterTLSConfig(key string) { func getTLSConfigClone(key string) (config *tls.Config) { tlsConfigLock.RLock() if v, ok := tlsConfigRegistry[key]; ok { - config = v.Clone() + config = cloneTLSConfig(v) } tlsConfigLock.RUnlock() return @@ -726,30 +724,3 @@ func (ae *atomicError) Value() error { } return nil } - -func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { - dargs := make([]driver.Value, len(named)) - for n, param := range named { - if len(param.Name) > 0 { - // TODO: support the use of Named Parameters #561 - return nil, errors.New("mysql: driver does not support the use of Named Parameters") - } - dargs[n] = param.Value - } - return dargs, nil -} - -func mapIsolationLevel(level driver.IsolationLevel) (string, error) { - switch sql.IsolationLevel(level) { - case sql.LevelRepeatableRead: - return "REPEATABLE READ", nil - case sql.LevelReadCommitted: - return "READ COMMITTED", nil - case sql.LevelReadUncommitted: - return "READ UNCOMMITTED", nil - case sql.LevelSerializable: - return "SERIALIZABLE", nil - default: - return "", fmt.Errorf("mysql: unsupported isolation level: %v", level) - } -} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go17.go b/vendor/github.com/go-sql-driver/mysql/utils_go17.go new file mode 100644 index 0000000000..f595634567 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go17.go @@ -0,0 +1,40 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// 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/. + +// +build go1.7 +// +build !go1.8 + +package mysql + +import "crypto/tls" + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return &tls.Config{ + Rand: c.Rand, + Time: c.Time, + Certificates: c.Certificates, + NameToCertificate: c.NameToCertificate, + GetCertificate: c.GetCertificate, + RootCAs: c.RootCAs, + NextProtos: c.NextProtos, + ServerName: c.ServerName, + ClientAuth: c.ClientAuth, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + CipherSuites: c.CipherSuites, + PreferServerCipherSuites: c.PreferServerCipherSuites, + SessionTicketsDisabled: c.SessionTicketsDisabled, + SessionTicketKey: c.SessionTicketKey, + ClientSessionCache: c.ClientSessionCache, + MinVersion: c.MinVersion, + MaxVersion: c.MaxVersion, + CurvePreferences: c.CurvePreferences, + DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, + Renegotiation: c.Renegotiation, + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go18.go b/vendor/github.com/go-sql-driver/mysql/utils_go18.go new file mode 100644 index 0000000000..c35c2a6aab --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go18.go @@ -0,0 +1,50 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// 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/. + +// +build go1.8 + +package mysql + +import ( + "crypto/tls" + "database/sql" + "database/sql/driver" + "errors" + "fmt" +) + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return c.Clone() +} + +func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { + dargs := make([]driver.Value, len(named)) + for n, param := range named { + if len(param.Name) > 0 { + // TODO: support the use of Named Parameters #561 + return nil, errors.New("mysql: driver does not support the use of Named Parameters") + } + dargs[n] = param.Value + } + return dargs, nil +} + +func mapIsolationLevel(level driver.IsolationLevel) (string, error) { + switch sql.IsolationLevel(level) { + case sql.LevelRepeatableRead: + return "REPEATABLE READ", nil + case sql.LevelReadCommitted: + return "READ COMMITTED", nil + case sql.LevelReadUncommitted: + return "READ UNCOMMITTED", nil + case sql.LevelSerializable: + return "SERIALIZABLE", nil + default: + return "", fmt.Errorf("mysql: unsupported isolation level: %v", level) + } +} diff --git a/vendor/github.com/go-xorm/builder/go.mod b/vendor/github.com/go-xorm/builder/go.mod deleted file mode 100644 index ef1a659ad1..0000000000 --- a/vendor/github.com/go-xorm/builder/go.mod +++ /dev/null @@ -1 +0,0 @@ -module "github.com/go-xorm/builder" diff --git a/vendor/github.com/go-xorm/core/circle.yml b/vendor/github.com/go-xorm/core/circle.yml deleted file mode 100644 index e6a05be272..0000000000 --- a/vendor/github.com/go-xorm/core/circle.yml +++ /dev/null @@ -1,15 +0,0 @@ -dependencies: - override: - # './...' is a relative pattern which means all subdirectories - - go get -t -d -v ./... - - go build -v - -database: - override: - - mysql -u root -e "CREATE DATABASE core_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - -test: - override: - # './...' is a relative pattern which means all subdirectories - - go test -v -race - - go test -v -race --dbtype=sqlite3 diff --git a/vendor/github.com/go-xorm/core/db.go b/vendor/github.com/go-xorm/core/db.go deleted file mode 100644 index 9969fa4313..0000000000 --- a/vendor/github.com/go-xorm/core/db.go +++ /dev/null @@ -1,401 +0,0 @@ -package core - -import ( - "database/sql" - "database/sql/driver" - "errors" - "fmt" - "reflect" - "regexp" - "sync" -) - -var ( - DefaultCacheSize = 200 -) - -func MapToSlice(query string, mp interface{}) (string, []interface{}, error) { - vv := reflect.ValueOf(mp) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { - return "", []interface{}{}, ErrNoMapPointer - } - - args := make([]interface{}, 0, len(vv.Elem().MapKeys())) - var err error - query = re.ReplaceAllStringFunc(query, func(src string) string { - v := vv.Elem().MapIndex(reflect.ValueOf(src[1:])) - if !v.IsValid() { - err = fmt.Errorf("map key %s is missing", src[1:]) - } else { - args = append(args, v.Interface()) - } - return "?" - }) - - return query, args, err -} - -func StructToSlice(query string, st interface{}) (string, []interface{}, error) { - vv := reflect.ValueOf(st) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { - return "", []interface{}{}, ErrNoStructPointer - } - - args := make([]interface{}, 0) - var err error - query = re.ReplaceAllStringFunc(query, func(src string) string { - fv := vv.Elem().FieldByName(src[1:]).Interface() - if v, ok := fv.(driver.Valuer); ok { - var value driver.Value - value, err = v.Value() - if err != nil { - return "?" - } - args = append(args, value) - } else { - args = append(args, fv) - } - return "?" - }) - if err != nil { - return "", []interface{}{}, err - } - return query, args, nil -} - -type cacheStruct struct { - value reflect.Value - idx int -} - -type DB struct { - *sql.DB - Mapper IMapper - reflectCache map[reflect.Type]*cacheStruct - reflectCacheMutex sync.RWMutex -} - -func Open(driverName, dataSourceName string) (*DB, error) { - db, err := sql.Open(driverName, dataSourceName) - if err != nil { - return nil, err - } - return &DB{ - DB: db, - Mapper: NewCacheMapper(&SnakeMapper{}), - reflectCache: make(map[reflect.Type]*cacheStruct), - }, nil -} - -func FromDB(db *sql.DB) *DB { - return &DB{ - DB: db, - Mapper: NewCacheMapper(&SnakeMapper{}), - reflectCache: make(map[reflect.Type]*cacheStruct), - } -} - -func (db *DB) reflectNew(typ reflect.Type) reflect.Value { - db.reflectCacheMutex.Lock() - defer db.reflectCacheMutex.Unlock() - cs, ok := db.reflectCache[typ] - if !ok || cs.idx+1 > DefaultCacheSize-1 { - cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0} - db.reflectCache[typ] = cs - } else { - cs.idx = cs.idx + 1 - } - return cs.value.Index(cs.idx).Addr() -} - -func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { - rows, err := db.DB.Query(query, args...) - if err != nil { - if rows != nil { - rows.Close() - } - return nil, err - } - return &Rows{rows, db}, nil -} - -func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) { - query, args, err := MapToSlice(query, mp) - if err != nil { - return nil, err - } - return db.Query(query, args...) -} - -func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) { - query, args, err := StructToSlice(query, st) - if err != nil { - return nil, err - } - return db.Query(query, args...) -} - -func (db *DB) QueryRow(query string, args ...interface{}) *Row { - rows, err := db.Query(query, args...) - if err != nil { - return &Row{nil, err} - } - return &Row{rows, nil} -} - -func (db *DB) QueryRowMap(query string, mp interface{}) *Row { - query, args, err := MapToSlice(query, mp) - if err != nil { - return &Row{nil, err} - } - return db.QueryRow(query, args...) -} - -func (db *DB) QueryRowStruct(query string, st interface{}) *Row { - query, args, err := StructToSlice(query, st) - if err != nil { - return &Row{nil, err} - } - return db.QueryRow(query, args...) -} - -type Stmt struct { - *sql.Stmt - db *DB - names map[string]int -} - -func (db *DB) Prepare(query string) (*Stmt, error) { - names := make(map[string]int) - var i int - query = re.ReplaceAllStringFunc(query, func(src string) string { - names[src[1:]] = i - i += 1 - return "?" - }) - - stmt, err := db.DB.Prepare(query) - if err != nil { - return nil, err - } - return &Stmt{stmt, db, names}, nil -} - -func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) { - vv := reflect.ValueOf(mp) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() - } - return s.Stmt.Exec(args...) -} - -func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) { - vv := reflect.ValueOf(st) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().FieldByName(k).Interface() - } - return s.Stmt.Exec(args...) -} - -func (s *Stmt) Query(args ...interface{}) (*Rows, error) { - rows, err := s.Stmt.Query(args...) - if err != nil { - return nil, err - } - return &Rows{rows, s.db}, nil -} - -func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) { - vv := reflect.ValueOf(mp) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() - } - - return s.Query(args...) -} - -func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) { - vv := reflect.ValueOf(st) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().FieldByName(k).Interface() - } - - return s.Query(args...) -} - -func (s *Stmt) QueryRow(args ...interface{}) *Row { - rows, err := s.Query(args...) - return &Row{rows, err} -} - -func (s *Stmt) QueryRowMap(mp interface{}) *Row { - vv := reflect.ValueOf(mp) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { - return &Row{nil, errors.New("mp should be a map's pointer")} - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() - } - - return s.QueryRow(args...) -} - -func (s *Stmt) QueryRowStruct(st interface{}) *Row { - vv := reflect.ValueOf(st) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { - return &Row{nil, errors.New("st should be a struct's pointer")} - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().FieldByName(k).Interface() - } - - return s.QueryRow(args...) -} - -var ( - re = regexp.MustCompile(`[?](\w+)`) -) - -// insert into (name) values (?) -// insert into (name) values (?name) -func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) { - query, args, err := MapToSlice(query, mp) - if err != nil { - return nil, err - } - return db.DB.Exec(query, args...) -} - -func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) { - query, args, err := StructToSlice(query, st) - if err != nil { - return nil, err - } - return db.DB.Exec(query, args...) -} - -type EmptyScanner struct { -} - -func (EmptyScanner) Scan(src interface{}) error { - return nil -} - -type Tx struct { - *sql.Tx - db *DB -} - -func (db *DB) Begin() (*Tx, error) { - tx, err := db.DB.Begin() - if err != nil { - return nil, err - } - return &Tx{tx, db}, nil -} - -func (tx *Tx) Prepare(query string) (*Stmt, error) { - names := make(map[string]int) - var i int - query = re.ReplaceAllStringFunc(query, func(src string) string { - names[src[1:]] = i - i += 1 - return "?" - }) - - stmt, err := tx.Tx.Prepare(query) - if err != nil { - return nil, err - } - return &Stmt{stmt, tx.db, names}, nil -} - -func (tx *Tx) Stmt(stmt *Stmt) *Stmt { - // TODO: - return stmt -} - -func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) { - query, args, err := MapToSlice(query, mp) - if err != nil { - return nil, err - } - return tx.Tx.Exec(query, args...) -} - -func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) { - query, args, err := StructToSlice(query, st) - if err != nil { - return nil, err - } - return tx.Tx.Exec(query, args...) -} - -func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { - rows, err := tx.Tx.Query(query, args...) - if err != nil { - return nil, err - } - return &Rows{rows, tx.db}, nil -} - -func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) { - query, args, err := MapToSlice(query, mp) - if err != nil { - return nil, err - } - return tx.Query(query, args...) -} - -func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) { - query, args, err := StructToSlice(query, st) - if err != nil { - return nil, err - } - return tx.Query(query, args...) -} - -func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { - rows, err := tx.Query(query, args...) - return &Row{rows, err} -} - -func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row { - query, args, err := MapToSlice(query, mp) - if err != nil { - return &Row{nil, err} - } - return tx.QueryRow(query, args...) -} - -func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row { - query, args, err := StructToSlice(query, st) - if err != nil { - return &Row{nil, err} - } - return tx.QueryRow(query, args...) -} diff --git a/vendor/github.com/go-xorm/core/go.mod b/vendor/github.com/go-xorm/core/go.mod deleted file mode 100644 index 70c86bcbc8..0000000000 --- a/vendor/github.com/go-xorm/core/go.mod +++ /dev/null @@ -1 +0,0 @@ -module "github.com/go-xorm/core" diff --git a/vendor/github.com/go-xorm/xorm/.drone.yml b/vendor/github.com/go-xorm/xorm/.drone.yml index 0a79ed0216..df9d405bc2 100644 --- a/vendor/github.com/go-xorm/xorm/.drone.yml +++ b/vendor/github.com/go-xorm/xorm/.drone.yml @@ -59,8 +59,8 @@ pipeline: image: golang:${GO_VERSION} commands: - go get -t -d -v ./... - - go get -u github.com/go-xorm/core - - go get -u github.com/go-xorm/builder + - go get -u xorm.io/core + - go get -u xorm.io/builder - go build -v when: event: [ push, pull_request ] diff --git a/vendor/github.com/go-xorm/xorm/README.md b/vendor/github.com/go-xorm/xorm/README.md index 6a57606e7f..2b839d520f 100644 --- a/vendor/github.com/go-xorm/xorm/README.md +++ b/vendor/github.com/go-xorm/xorm/README.md @@ -28,7 +28,7 @@ Xorm is a simple and powerful ORM for Go. * Optimistic Locking support -* SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder) +* SQL Builder support via [xorm.io/builder](https://xorm.io/builder) * Automatical Read/Write seperatelly @@ -151,20 +151,20 @@ has, err := engine.Where("name = ?", name).Desc("id").Get(&user) // SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 var name string -has, err := engine.Where("id = ?", id).Cols("name").Get(&name) +has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name) // SELECT name FROM user WHERE id = ? var id int64 -has, err := engine.Where("name = ?", name).Cols("id").Get(&id) +has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id) has, err := engine.SQL("select id from user").Get(&id) // SELECT id FROM user WHERE name = ? var valuesMap = make(map[string]string) -has, err := engine.Where("id = ?", id).Get(&valuesMap) +has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap) // SELECT * FROM user WHERE id = ? var valuesSlice = make([]interface{}, len(cols)) -has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice) +has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice) // SELECT col1, col2, col3 FROM user WHERE id = ? ``` @@ -363,7 +363,7 @@ return session.Commit() * Or you can use `Transaction` to replace above codes. ```Go -res, err := engine.Transaction(func(sess *xorm.Session) (interface{}, error) { +res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) { user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} if _, err := session.Insert(&user1); err != nil { return nil, err @@ -493,4 +493,4 @@ Support this project by becoming a sponsor. Your logo will show up here with a l ## LICENSE -BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) \ No newline at end of file +BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) diff --git a/vendor/github.com/go-xorm/xorm/README_CN.md b/vendor/github.com/go-xorm/xorm/README_CN.md index e2ed95b62c..0cec6ed5c6 100644 --- a/vendor/github.com/go-xorm/xorm/README_CN.md +++ b/vendor/github.com/go-xorm/xorm/README_CN.md @@ -153,20 +153,20 @@ has, err := engine.Where("name = ?", name).Desc("id").Get(&user) // SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 var name string -has, err := engine.Where("id = ?", id).Cols("name").Get(&name) +has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name) // SELECT name FROM user WHERE id = ? var id int64 -has, err := engine.Where("name = ?", name).Cols("id").Get(&id) +has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id) has, err := engine.SQL("select id from user").Get(&id) // SELECT id FROM user WHERE name = ? var valuesMap = make(map[string]string) -has, err := engine.Where("id = ?", id).Get(&valuesMap) +has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap) // SELECT * FROM user WHERE id = ? var valuesSlice = make([]interface{}, len(cols)) -has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice) +has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice) // SELECT col1, col2, col3 FROM user WHERE id = ? ``` @@ -362,7 +362,7 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern return session.Commit() ``` -* 事物的简写方法 +* 事务的简写方法 ```Go res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) { diff --git a/vendor/github.com/go-xorm/xorm/cache_lru.go b/vendor/github.com/go-xorm/xorm/cache_lru.go index c9672cebe4..ab948bd28e 100644 --- a/vendor/github.com/go-xorm/xorm/cache_lru.go +++ b/vendor/github.com/go-xorm/xorm/cache_lru.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) // LRUCacher implments cache object facilities diff --git a/vendor/github.com/go-xorm/xorm/cache_memory_store.go b/vendor/github.com/go-xorm/xorm/cache_memory_store.go index 36853b19e3..0c483f4583 100644 --- a/vendor/github.com/go-xorm/xorm/cache_memory_store.go +++ b/vendor/github.com/go-xorm/xorm/cache_memory_store.go @@ -7,7 +7,7 @@ package xorm import ( "sync" - "github.com/go-xorm/core" + "xorm.io/core" ) var _ core.CacheStore = NewMemoryStore() diff --git a/vendor/github.com/go-xorm/xorm/circle.yml b/vendor/github.com/go-xorm/xorm/circle.yml deleted file mode 100644 index 8fde316921..0000000000 --- a/vendor/github.com/go-xorm/xorm/circle.yml +++ /dev/null @@ -1,41 +0,0 @@ -dependencies: - override: - # './...' is a relative pattern which means all subdirectories - - go get -t -d -v ./... - - go get -t -d -v github.com/go-xorm/tests - - go get -u github.com/go-xorm/core - - go get -u github.com/go-xorm/builder - - go build -v - -database: - override: - - mysql -u root -e "CREATE DATABASE xorm_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - mysql -u root -e "CREATE DATABASE xorm_test1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - mysql -u root -e "CREATE DATABASE xorm_test2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - mysql -u root -e "CREATE DATABASE xorm_test3 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - createdb -p 5432 -e -U postgres xorm_test - - createdb -p 5432 -e -U postgres xorm_test1 - - createdb -p 5432 -e -U postgres xorm_test2 - - createdb -p 5432 -e -U postgres xorm_test3 - - psql xorm_test postgres -c "create schema xorm" - -test: - override: - # './...' is a relative pattern which means all subdirectories - - go get -u github.com/wadey/gocovmerge - - go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic - - go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic - - go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic - - go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic - - go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic - - go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic - - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic - - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic - - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic - - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt - - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh - - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh - - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh - post: - - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/dialect_mssql.go b/vendor/github.com/go-xorm/xorm/dialect_mssql.go index fb1247094c..3330212c12 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_mssql.go +++ b/vendor/github.com/go-xorm/xorm/dialect_mssql.go @@ -7,10 +7,11 @@ package xorm import ( "errors" "fmt" + "net/url" "strconv" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) var ( @@ -544,14 +545,23 @@ type odbcDriver struct { } func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - kv := strings.Split(dataSourceName, ";") var dbName string - for _, c := range kv { - vv := strings.Split(strings.TrimSpace(c), "=") - if len(vv) == 2 { - switch strings.ToLower(vv[0]) { - case "database": - dbName = vv[1] + + if strings.HasPrefix(dataSourceName, "sqlserver://") { + u, err := url.Parse(dataSourceName) + if err != nil { + return nil, err + } + dbName = u.Query().Get("database") + } else { + kv := strings.Split(dataSourceName, ";") + for _, c := range kv { + vv := strings.Split(strings.TrimSpace(c), "=") + if len(vv) == 2 { + switch strings.ToLower(vv[0]) { + case "database": + dbName = vv[1] + } } } } diff --git a/vendor/github.com/go-xorm/xorm/dialect_mysql.go b/vendor/github.com/go-xorm/xorm/dialect_mysql.go index 9f5ae3b2e5..2628042ab3 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_mysql.go +++ b/vendor/github.com/go-xorm/xorm/dialect_mysql.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) var ( @@ -393,6 +393,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column if colType == "FLOAT UNSIGNED" { colType = "FLOAT" } + if colType == "DOUBLE UNSIGNED" { + colType = "DOUBLE" + } col.Length = len1 col.Length2 = len2 if _, ok := core.SqlTypes[colType]; ok { diff --git a/vendor/github.com/go-xorm/xorm/dialect_oracle.go b/vendor/github.com/go-xorm/xorm/dialect_oracle.go index ac0081b38f..b66145bcbe 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_oracle.go +++ b/vendor/github.com/go-xorm/xorm/dialect_oracle.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) var ( diff --git a/vendor/github.com/go-xorm/xorm/dialect_postgres.go b/vendor/github.com/go-xorm/xorm/dialect_postgres.go index 738c6a1581..662f6401c1 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_postgres.go +++ b/vendor/github.com/go-xorm/xorm/dialect_postgres.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) // from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html @@ -1093,6 +1093,19 @@ func (db *postgres) GetTables() ([]*core.Table, error) { return tables, nil } + +func getIndexColName(indexdef string) []string { + var colNames []string + + cs := strings.Split(indexdef, "(") + for _, v := range strings.Split(strings.Split(cs[1], ")")[0], ",") { + colNames = append(colNames, strings.Split(strings.TrimLeft(v, " "), " ")[0]) + } + + return colNames +} + + func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) { args := []interface{}{tableName} s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1") @@ -1126,8 +1139,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) } else { indexType = core.IndexType } - cs := strings.Split(indexdef, "(") - colNames = strings.Split(cs[1][0:len(cs[1])-1], ",") + colNames = getIndexColName(indexdef) var isRegular bool if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { newIdxName := indexName[5+len(tableName):] diff --git a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go index e129481466..e30a7751bf 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go +++ b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go @@ -11,7 +11,7 @@ import ( "regexp" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) var ( diff --git a/vendor/github.com/go-xorm/xorm/engine.go b/vendor/github.com/go-xorm/xorm/engine.go index c1bf06e15c..962df125bb 100644 --- a/vendor/github.com/go-xorm/xorm/engine.go +++ b/vendor/github.com/go-xorm/xorm/engine.go @@ -7,6 +7,7 @@ package xorm import ( "bufio" "bytes" + "context" "database/sql" "encoding/gob" "errors" @@ -19,8 +20,8 @@ import ( "sync" "time" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) // Engine is the major struct of xorm, it means a database manager. @@ -52,6 +53,8 @@ type Engine struct { cachers map[string]core.Cacher cacherLock sync.RWMutex + + defaultContext context.Context } func (engine *Engine) setCacher(tableName string, cacher core.Cacher) { @@ -122,6 +125,7 @@ func (engine *Engine) Logger() core.ILogger { // SetLogger set the new logger func (engine *Engine) SetLogger(logger core.ILogger) { engine.logger = logger + engine.showSQL = logger.IsShowSQL() engine.dialect.SetLogger(logger) } @@ -1351,31 +1355,31 @@ func (engine *Engine) DropIndexes(bean interface{}) error { } // Exec raw sql -func (engine *Engine) Exec(sqlorArgs ...interface{}) (sql.Result, error) { +func (engine *Engine) Exec(sqlOrArgs ...interface{}) (sql.Result, error) { session := engine.NewSession() defer session.Close() - return session.Exec(sqlorArgs...) + return session.Exec(sqlOrArgs...) } // Query a raw sql and return records as []map[string][]byte -func (engine *Engine) Query(sqlorArgs ...interface{}) (resultsSlice []map[string][]byte, err error) { +func (engine *Engine) Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error) { session := engine.NewSession() defer session.Close() - return session.Query(sqlorArgs...) + return session.Query(sqlOrArgs...) } // QueryString runs a raw sql and return records as []map[string]string -func (engine *Engine) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) { +func (engine *Engine) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) { session := engine.NewSession() defer session.Close() - return session.QueryString(sqlorArgs...) + return session.QueryString(sqlOrArgs...) } // QueryInterface runs a raw sql and return records as []map[string]interface{} -func (engine *Engine) QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error) { +func (engine *Engine) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) { session := engine.NewSession() defer session.Close() - return session.QueryInterface(sqlorArgs...) + return session.QueryInterface(sqlOrArgs...) } // Insert one or more records diff --git a/vendor/github.com/go-xorm/xorm/engine_cond.go b/vendor/github.com/go-xorm/xorm/engine_cond.go index 4dde8662e1..702ac80434 100644 --- a/vendor/github.com/go-xorm/xorm/engine_cond.go +++ b/vendor/github.com/go-xorm/xorm/engine_cond.go @@ -6,14 +6,13 @@ package xorm import ( "database/sql/driver" - "encoding/json" "fmt" "reflect" "strings" "time" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) func (engine *Engine) buildConds(table *core.Table, bean interface{}, @@ -147,7 +146,7 @@ func (engine *Engine) buildConds(table *core.Table, bean interface{}, } else { if col.SQLType.IsJson() { if col.SQLType.IsText() { - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { engine.logger.Error(err) continue @@ -156,7 +155,7 @@ func (engine *Engine) buildConds(table *core.Table, bean interface{}, } else if col.SQLType.IsBlob() { var bytes []byte var err error - bytes, err = json.Marshal(fieldValue.Interface()) + bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { engine.logger.Error(err) continue @@ -195,7 +194,7 @@ func (engine *Engine) buildConds(table *core.Table, bean interface{}, } if col.SQLType.IsText() { - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { engine.logger.Error(err) continue @@ -212,7 +211,7 @@ func (engine *Engine) buildConds(table *core.Table, bean interface{}, continue } } else { - bytes, err = json.Marshal(fieldValue.Interface()) + bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { engine.logger.Error(err) continue diff --git a/vendor/github.com/go-xorm/xorm/engine_context.go b/vendor/github.com/go-xorm/xorm/engine_context.go new file mode 100644 index 0000000000..c6cbb76c1d --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/engine_context.go @@ -0,0 +1,28 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.8 + +package xorm + +import "context" + +// Context creates a session with the context +func (engine *Engine) Context(ctx context.Context) *Session { + session := engine.NewSession() + session.isAutoClose = true + return session.Context(ctx) +} + +// SetDefaultContext set the default context +func (engine *Engine) SetDefaultContext(ctx context.Context) { + engine.defaultContext = ctx +} + +// PingContext tests if database is alive +func (engine *Engine) PingContext(ctx context.Context) error { + session := engine.NewSession() + defer session.Close() + return session.PingContext(ctx) +} diff --git a/vendor/github.com/go-xorm/xorm/engine_group.go b/vendor/github.com/go-xorm/xorm/engine_group.go index 5eee3e6183..42d49eca93 100644 --- a/vendor/github.com/go-xorm/xorm/engine_group.go +++ b/vendor/github.com/go-xorm/xorm/engine_group.go @@ -5,9 +5,10 @@ package xorm import ( + "context" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) // EngineGroup defines an engine group @@ -74,6 +75,20 @@ func (eg *EngineGroup) Close() error { return nil } +// Context returned a group session +func (eg *EngineGroup) Context(ctx context.Context) *Session { + sess := eg.NewSession() + sess.isAutoClose = true + return sess.Context(ctx) +} + +// NewSession returned a group session +func (eg *EngineGroup) NewSession() *Session { + sess := eg.Engine.NewSession() + sess.sessionType = groupSession + return sess +} + // Master returns the master engine func (eg *EngineGroup) Master() *Engine { return eg.Engine diff --git a/vendor/github.com/go-xorm/xorm/engine_table.go b/vendor/github.com/go-xorm/xorm/engine_table.go index 94871a4bce..eb5aa850af 100644 --- a/vendor/github.com/go-xorm/xorm/engine_table.go +++ b/vendor/github.com/go-xorm/xorm/engine_table.go @@ -9,10 +9,10 @@ import ( "reflect" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) -// TableNameWithSchema will automatically add schema prefix on table name +// tbNameWithSchema will automatically add schema prefix on table name func (engine *Engine) tbNameWithSchema(v string) string { // Add schema name as prefix of table name. // Only for postgres database. diff --git a/vendor/github.com/go-xorm/xorm/error.go b/vendor/github.com/go-xorm/xorm/error.go index a223fc4a86..a67527acda 100644 --- a/vendor/github.com/go-xorm/xorm/error.go +++ b/vendor/github.com/go-xorm/xorm/error.go @@ -26,6 +26,8 @@ var ( ErrNotImplemented = errors.New("Not implemented") // ErrConditionType condition type unsupported ErrConditionType = errors.New("Unsupported condition type") + // ErrUnSupportedSQLType parameter of SQL is not supported + ErrUnSupportedSQLType = errors.New("unsupported sql type") ) // ErrFieldIsNotExist columns does not exist diff --git a/vendor/github.com/go-xorm/xorm/go.mod b/vendor/github.com/go-xorm/xorm/go.mod index 1856169558..9a30b4b48a 100644 --- a/vendor/github.com/go-xorm/xorm/go.mod +++ b/vendor/github.com/go-xorm/xorm/go.mod @@ -1,24 +1,24 @@ module github.com/go-xorm/xorm require ( + cloud.google.com/go v0.34.0 // indirect github.com/cockroachdb/apd v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f - github.com/go-sql-driver/mysql v1.4.0 - github.com/go-xorm/builder v0.3.2 - github.com/go-xorm/core v0.6.0 - github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a // indirect + github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 + github.com/go-sql-driver/mysql v1.4.1 + github.com/google/go-cmp v0.2.0 // indirect github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect - github.com/jackc/pgx v3.2.0+incompatible + github.com/jackc/pgx v3.3.0+incompatible github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.0.0 - github.com/mattn/go-sqlite3 v1.9.0 - github.com/pkg/errors v0.8.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/mattn/go-sqlite3 v1.10.0 + github.com/pkg/errors v0.8.1 // indirect github.com/satori/go.uuid v1.2.0 // indirect github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect - github.com/stretchr/testify v1.2.2 + github.com/stretchr/testify v1.3.0 github.com/ziutek/mymysql v1.5.4 + golang.org/x/crypto v0.0.0-20190122013713-64072686203f // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/stretchr/testify.v1 v1.2.2 + xorm.io/builder v0.3.5 + xorm.io/core v0.6.3 ) diff --git a/vendor/github.com/go-xorm/xorm/go.sum b/vendor/github.com/go-xorm/xorm/go.sum index dbf757d1d3..307d46d9ad 100644 --- a/vendor/github.com/go-xorm/xorm/go.sum +++ b/vendor/github.com/go-xorm/xorm/go.sum @@ -1,21 +1,24 @@ +cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f h1:WH0w/R4Yoey+04HhFxqZ6VX6I0d7RMyw5aXQ9UTvQPs= -github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= -github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-xorm/builder v0.3.2 h1:pSsZQRRzJNapKEAEhigw3xLmiLPeAYv5GFlpYZ8+a5I= -github.com/go-xorm/builder v0.3.2/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk= -github.com/go-xorm/core v0.6.0 h1:tp6hX+ku4OD9khFZS8VGBDRY3kfVCtelPfmkgCyHxL0= -github.com/go-xorm/core v0.6.0/go.mod h1:d8FJ9Br8OGyQl12MCclmYBuBqqxsyeedpXciV5Myih8= +github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 h1:b5OnbZD49x9g+/FcYbs/vukEt8C/jUbGhCJ3uduQmu8= +github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY= -github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90= +github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -23,21 +26,32 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +golang.org/x/crypto v0.0.0-20190122013713-64072686203f h1:u1CmMhe3a44hy8VIgpInORnI01UVaUYheqR7x9BxT3c= +golang.org/x/crypto v0.0.0-20190122013713-64072686203f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M= -gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU= +xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A= +xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= +xorm.io/core v0.6.2 h1:EJLcSxf336POJr670wKB55Mah9f93xzvGYzNRgnT8/Y= +xorm.io/core v0.6.2/go.mod h1:bwPIfLdm/FzWgVUH8WPVlr+uJhscvNGFcaZKXsI3n2c= +xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M= +xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo= diff --git a/vendor/github.com/go-xorm/xorm/helpers.go b/vendor/github.com/go-xorm/xorm/helpers.go index f1705782e3..db8fc581f3 100644 --- a/vendor/github.com/go-xorm/xorm/helpers.go +++ b/vendor/github.com/go-xorm/xorm/helpers.go @@ -12,7 +12,7 @@ import ( "strconv" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) // str2PK convert string value to primary key value according to tp diff --git a/vendor/github.com/go-xorm/xorm/interface.go b/vendor/github.com/go-xorm/xorm/interface.go index 33d2078e44..0928f66a9a 100644 --- a/vendor/github.com/go-xorm/xorm/interface.go +++ b/vendor/github.com/go-xorm/xorm/interface.go @@ -5,11 +5,12 @@ package xorm import ( + "context" "database/sql" "reflect" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) // Interface defines the interface which Engine, EngineGroup and Session will implementate. @@ -27,7 +28,7 @@ type Interface interface { Delete(interface{}) (int64, error) Distinct(columns ...string) *Session DropIndexes(bean interface{}) error - Exec(sqlOrAgrs ...interface{}) (sql.Result, error) + Exec(sqlOrArgs ...interface{}) (sql.Result, error) Exist(bean ...interface{}) (bool, error) Find(interface{}, ...interface{}) error FindAndCount(interface{}, ...interface{}) (int64, error) @@ -49,9 +50,9 @@ type Interface interface { Omit(columns ...string) *Session OrderBy(order string) *Session Ping() error - Query(sqlOrAgrs ...interface{}) (resultsSlice []map[string][]byte, err error) - QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error) - QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) + Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error) + QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) + QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) Rows(bean interface{}) (*Rows, error) SetExpr(string, string) *Session SQL(interface{}, ...interface{}) *Session @@ -73,6 +74,7 @@ type EngineInterface interface { Before(func(interface{})) *Session Charset(charset string) *Session ClearCache(...interface{}) error + Context(context.Context) *Session CreateTables(...interface{}) error DBMetas() ([]*core.Table, error) Dialect() core.Dialect diff --git a/vendor/github.com/go-xorm/xorm/json.go b/vendor/github.com/go-xorm/xorm/json.go new file mode 100644 index 0000000000..fdb6ce5654 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/json.go @@ -0,0 +1,31 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import "encoding/json" + +// JSONInterface represents an interface to handle json data +type JSONInterface interface { + Marshal(v interface{}) ([]byte, error) + Unmarshal(data []byte, v interface{}) error +} + +var ( + // DefaultJSONHandler default json handler + DefaultJSONHandler JSONInterface = StdJSON{} +) + +// StdJSON implements JSONInterface via encoding/json +type StdJSON struct{} + +// Marshal implements JSONInterface +func (StdJSON) Marshal(v interface{}) ([]byte, error) { + return json.Marshal(v) +} + +// Unmarshal implements JSONInterface +func (StdJSON) Unmarshal(data []byte, v interface{}) error { + return json.Unmarshal(data, v) +} diff --git a/vendor/github.com/go-xorm/xorm/logger.go b/vendor/github.com/go-xorm/xorm/logger.go index 727d030a4c..7b26e77f3b 100644 --- a/vendor/github.com/go-xorm/xorm/logger.go +++ b/vendor/github.com/go-xorm/xorm/logger.go @@ -9,7 +9,7 @@ import ( "io" "log" - "github.com/go-xorm/core" + "xorm.io/core" ) // default log options diff --git a/vendor/github.com/go-xorm/xorm/rows.go b/vendor/github.com/go-xorm/xorm/rows.go index 54ec7f37a2..bdd44589f8 100644 --- a/vendor/github.com/go-xorm/xorm/rows.go +++ b/vendor/github.com/go-xorm/xorm/rows.go @@ -9,16 +9,13 @@ import ( "fmt" "reflect" - "github.com/go-xorm/core" + "xorm.io/core" ) // Rows rows wrapper a rows to type Rows struct { - NoTypeCheck bool - session *Session rows *core.Rows - fields []string beanType reflect.Type lastError error } @@ -57,13 +54,6 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { return nil, err } - rows.fields, err = rows.rows.Columns() - if err != nil { - rows.lastError = err - rows.Close() - return nil, err - } - return rows, nil } @@ -90,7 +80,7 @@ func (rows *Rows) Scan(bean interface{}) error { return rows.lastError } - if !rows.NoTypeCheck && reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType { + if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType { return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType) } @@ -98,13 +88,18 @@ func (rows *Rows) Scan(bean interface{}) error { return err } - scanResults, err := rows.session.row2Slice(rows.rows, rows.fields, bean) + fields, err := rows.rows.Columns() + if err != nil { + return err + } + + scanResults, err := rows.session.row2Slice(rows.rows, fields, bean) if err != nil { return err } dataStruct := rValue(bean) - _, err = rows.session.slice2Bean(scanResults, rows.fields, bean, &dataStruct, rows.session.statement.RefTable) + _, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable) if err != nil { return err } @@ -118,17 +113,9 @@ func (rows *Rows) Close() error { defer rows.session.Close() } - if rows.lastError == nil { - if rows.rows != nil { - rows.lastError = rows.rows.Close() - if rows.lastError != nil { - return rows.lastError - } - } - } else { - if rows.rows != nil { - defer rows.rows.Close() - } + if rows.rows != nil { + return rows.rows.Close() } + return rows.lastError } diff --git a/vendor/github.com/go-xorm/xorm/session.go b/vendor/github.com/go-xorm/xorm/session.go index e3437b9181..b33955fdce 100644 --- a/vendor/github.com/go-xorm/xorm/session.go +++ b/vendor/github.com/go-xorm/xorm/session.go @@ -5,8 +5,8 @@ package xorm import ( + "context" "database/sql" - "encoding/json" "errors" "fmt" "hash/crc32" @@ -14,7 +14,14 @@ import ( "strings" "time" - "github.com/go-xorm/core" + "xorm.io/core" +) + +type sessionType int + +const ( + engineSession sessionType = iota + groupSession ) // Session keep a pointer to sql.DB and provides all execution of all @@ -51,7 +58,8 @@ type Session struct { lastSQL string lastSQLArgs []interface{} - err error + ctx context.Context + sessionType sessionType } // Clone copy all the session's content and return a new session @@ -82,6 +90,8 @@ func (session *Session) Init() { session.lastSQL = "" session.lastSQLArgs = []interface{}{} + + session.ctx = session.engine.defaultContext } // Close release the connection from pool @@ -275,7 +285,7 @@ func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, var has bool stmt, has = session.stmtCache[crc] if !has { - stmt, err = db.Prepare(sqlStr) + stmt, err = db.PrepareContext(session.ctx, sqlStr) if err != nil { return nil, err } @@ -480,13 +490,13 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b continue } if fieldValue.CanAddr() { - err := json.Unmarshal(bs, fieldValue.Addr().Interface()) + err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface()) if err != nil { return nil, err } } else { x := reflect.New(fieldType) - err := json.Unmarshal(bs, x.Interface()) + err := DefaultJSONHandler.Unmarshal(bs, x.Interface()) if err != nil { return nil, err } @@ -510,13 +520,13 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b hasAssigned = true if len(bs) > 0 { if fieldValue.CanAddr() { - err := json.Unmarshal(bs, fieldValue.Addr().Interface()) + err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface()) if err != nil { return nil, err } } else { x := reflect.New(fieldType) - err := json.Unmarshal(bs, x.Interface()) + err := DefaultJSONHandler.Unmarshal(bs, x.Interface()) if err != nil { return nil, err } @@ -532,7 +542,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b hasAssigned = true if col.SQLType.IsText() { x := reflect.New(fieldType) - err := json.Unmarshal(vv.Bytes(), x.Interface()) + err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface()) if err != nil { return nil, err } @@ -647,7 +657,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b hasAssigned = true x := reflect.New(fieldType) if len([]byte(vv.String())) > 0 { - err := json.Unmarshal([]byte(vv.String()), x.Interface()) + err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), x.Interface()) if err != nil { return nil, err } @@ -657,7 +667,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b hasAssigned = true x := reflect.New(fieldType) if len(vv.Bytes()) > 0 { - err := json.Unmarshal(vv.Bytes(), x.Interface()) + err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface()) if err != nil { return nil, err } @@ -793,7 +803,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b case core.Complex64Type: var x complex64 if len([]byte(vv.String())) > 0 { - err := json.Unmarshal([]byte(vv.String()), &x) + err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x) if err != nil { return nil, err } @@ -803,7 +813,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b case core.Complex128Type: var x complex128 if len([]byte(vv.String())) > 0 { - err := json.Unmarshal([]byte(vv.String()), &x) + err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x) if err != nil { return nil, err } diff --git a/vendor/github.com/go-xorm/xorm/session_cols.go b/vendor/github.com/go-xorm/xorm/session_cols.go index 47d109c6cb..dc3befcf6b 100644 --- a/vendor/github.com/go-xorm/xorm/session_cols.go +++ b/vendor/github.com/go-xorm/xorm/session_cols.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) type incrParam struct { diff --git a/vendor/github.com/go-xorm/xorm/session_cond.go b/vendor/github.com/go-xorm/xorm/session_cond.go index e1d528f2db..b16bdea8e0 100644 --- a/vendor/github.com/go-xorm/xorm/session_cond.go +++ b/vendor/github.com/go-xorm/xorm/session_cond.go @@ -4,7 +4,7 @@ package xorm -import "github.com/go-xorm/builder" +import "xorm.io/builder" // Sql provides raw sql input parameter. When you have a complex SQL statement // and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. diff --git a/vendor/github.com/go-xorm/xorm/context.go b/vendor/github.com/go-xorm/xorm/session_context.go similarity index 60% rename from vendor/github.com/go-xorm/xorm/context.go rename to vendor/github.com/go-xorm/xorm/session_context.go index 074ba35a80..915f056858 100644 --- a/vendor/github.com/go-xorm/xorm/context.go +++ b/vendor/github.com/go-xorm/xorm/session_context.go @@ -1,18 +1,15 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. +// Copyright 2019 The Xorm Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.8 - package xorm import "context" -// PingContext tests if database is alive -func (engine *Engine) PingContext(ctx context.Context) error { - session := engine.NewSession() - defer session.Close() - return session.PingContext(ctx) +// Context sets the context on this session +func (session *Session) Context(ctx context.Context) *Session { + session.ctx = ctx + return session } // PingContext test if database is ok diff --git a/vendor/github.com/go-xorm/xorm/session_convert.go b/vendor/github.com/go-xorm/xorm/session_convert.go index 1f9d8aa1bd..c13b003d6b 100644 --- a/vendor/github.com/go-xorm/xorm/session_convert.go +++ b/vendor/github.com/go-xorm/xorm/session_convert.go @@ -7,7 +7,6 @@ package xorm import ( "database/sql" "database/sql/driver" - "encoding/json" "errors" "fmt" "reflect" @@ -15,7 +14,7 @@ import ( "strings" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) { @@ -103,7 +102,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, case reflect.Complex64, reflect.Complex128: x := reflect.New(fieldType) if len(data) > 0 { - err := json.Unmarshal(data, x.Interface()) + err := DefaultJSONHandler.Unmarshal(data, x.Interface()) if err != nil { session.engine.logger.Error(err) return err @@ -117,7 +116,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, if col.SQLType.IsText() { x := reflect.New(fieldType) if len(data) > 0 { - err := json.Unmarshal(data, x.Interface()) + err := DefaultJSONHandler.Unmarshal(data, x.Interface()) if err != nil { session.engine.logger.Error(err) return err @@ -130,7 +129,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, } else { x := reflect.New(fieldType) if len(data) > 0 { - err := json.Unmarshal(data, x.Interface()) + err := DefaultJSONHandler.Unmarshal(data, x.Interface()) if err != nil { session.engine.logger.Error(err) return err @@ -259,7 +258,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, case core.Complex64Type.Kind(): var x complex64 if len(data) > 0 { - err := json.Unmarshal(data, &x) + err := DefaultJSONHandler.Unmarshal(data, &x) if err != nil { session.engine.logger.Error(err) return err @@ -270,7 +269,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, case core.Complex128Type.Kind(): var x complex128 if len(data) > 0 { - err := json.Unmarshal(data, &x) + err := DefaultJSONHandler.Unmarshal(data, &x) if err != nil { session.engine.logger.Error(err) return err @@ -604,14 +603,14 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val } if col.SQLType.IsText() { - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { session.engine.logger.Error(err) return 0, err } return string(bytes), nil } else if col.SQLType.IsBlob() { - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { session.engine.logger.Error(err) return 0, err @@ -620,7 +619,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val } return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type()) case reflect.Complex64, reflect.Complex128: - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { session.engine.logger.Error(err) return 0, err @@ -632,7 +631,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val } if col.SQLType.IsText() { - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { session.engine.logger.Error(err) return 0, err @@ -645,7 +644,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val (fieldValue.Type().Elem().Kind() == reflect.Uint8) { bytes = fieldValue.Bytes() } else { - bytes, err = json.Marshal(fieldValue.Interface()) + bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { session.engine.logger.Error(err) return 0, err diff --git a/vendor/github.com/go-xorm/xorm/session_delete.go b/vendor/github.com/go-xorm/xorm/session_delete.go index dcce543a3a..675d4d8c7d 100644 --- a/vendor/github.com/go-xorm/xorm/session_delete.go +++ b/vendor/github.com/go-xorm/xorm/session_delete.go @@ -9,7 +9,7 @@ import ( "fmt" "strconv" - "github.com/go-xorm/core" + "xorm.io/core" ) func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error { @@ -79,6 +79,10 @@ func (session *Session) Delete(bean interface{}) (int64, error) { defer session.Close() } + if session.statement.lastError != nil { + return 0, session.statement.lastError + } + if err := session.statement.setRefBean(bean); err != nil { return 0, err } diff --git a/vendor/github.com/go-xorm/xorm/session_exist.go b/vendor/github.com/go-xorm/xorm/session_exist.go index 74a660e852..660cc47e42 100644 --- a/vendor/github.com/go-xorm/xorm/session_exist.go +++ b/vendor/github.com/go-xorm/xorm/session_exist.go @@ -9,8 +9,8 @@ import ( "fmt" "reflect" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) // Exist returns true if the record exist otherwise return false @@ -19,6 +19,10 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) { defer session.Close() } + if session.statement.lastError != nil { + return false, session.statement.lastError + } + var sqlStr string var args []interface{} var err error @@ -30,6 +34,8 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) { return false, ErrTableNotFound } + tableName = session.statement.Engine.Quote(tableName) + if session.statement.cond.IsValid() { condSQL, condArgs, err := builder.ToSQL(session.statement.cond) if err != nil { @@ -37,14 +43,18 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) { } if session.engine.dialect.DBType() == core.MSSQL { - sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s WHERE %s", tableName, condSQL) + sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s WHERE %s", tableName, condSQL) + } else if session.engine.dialect.DBType() == core.ORACLE { + sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE (%s) AND ROWNUM=1", tableName, condSQL) } else { sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL) } args = condArgs } else { if session.engine.dialect.DBType() == core.MSSQL { - sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s", tableName) + sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s", tableName) + } else if session.engine.dialect.DBType() == core.ORACLE { + sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE ROWNUM=1", tableName) } else { sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName) } diff --git a/vendor/github.com/go-xorm/xorm/session_find.go b/vendor/github.com/go-xorm/xorm/session_find.go index a5b4f79342..d3fc0d30dd 100644 --- a/vendor/github.com/go-xorm/xorm/session_find.go +++ b/vendor/github.com/go-xorm/xorm/session_find.go @@ -10,8 +10,8 @@ import ( "reflect" "strings" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) const ( @@ -63,6 +63,10 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte } func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error { + if session.statement.lastError != nil { + return session.statement.lastError + } + sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { return errors.New("needs a pointer to a slice or a map") diff --git a/vendor/github.com/go-xorm/xorm/session_get.go b/vendor/github.com/go-xorm/xorm/session_get.go index 1cea31c5f8..a38707c8c6 100644 --- a/vendor/github.com/go-xorm/xorm/session_get.go +++ b/vendor/github.com/go-xorm/xorm/session_get.go @@ -11,7 +11,7 @@ import ( "reflect" "strconv" - "github.com/go-xorm/core" + "xorm.io/core" ) // Get retrieve one record from database, bean's non-empty fields @@ -24,6 +24,10 @@ func (session *Session) Get(bean interface{}) (bool, error) { } func (session *Session) get(bean interface{}) (bool, error) { + if session.statement.lastError != nil { + return false, session.statement.lastError + } + beanValue := reflect.ValueOf(bean) if beanValue.Kind() != reflect.Ptr { return false, errors.New("needs a pointer to a value") diff --git a/vendor/github.com/go-xorm/xorm/session_insert.go b/vendor/github.com/go-xorm/xorm/session_insert.go index e673e87425..3cff48f613 100644 --- a/vendor/github.com/go-xorm/xorm/session_insert.go +++ b/vendor/github.com/go-xorm/xorm/session_insert.go @@ -8,10 +8,11 @@ import ( "errors" "fmt" "reflect" + "sort" "strconv" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) // Insert insert one or more beans @@ -24,32 +25,67 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) { } for _, bean := range beans { - sliceValue := reflect.Indirect(reflect.ValueOf(bean)) - if sliceValue.Kind() == reflect.Slice { - size := sliceValue.Len() - if size > 0 { - if session.engine.SupportInsertMany() { - cnt, err := session.innerInsertMulti(bean) - if err != nil { - return affected, err - } - affected += cnt - } else { - for i := 0; i < size; i++ { - cnt, err := session.innerInsert(sliceValue.Index(i).Interface()) - if err != nil { - return affected, err - } - affected += cnt - } - } - } - } else { - cnt, err := session.innerInsert(bean) + switch bean.(type) { + case map[string]interface{}: + cnt, err := session.insertMapInterface(bean.(map[string]interface{})) if err != nil { return affected, err } affected += cnt + case []map[string]interface{}: + s := bean.([]map[string]interface{}) + session.autoResetStatement = false + for i := 0; i < len(s); i++ { + cnt, err := session.insertMapInterface(s[i]) + if err != nil { + return affected, err + } + affected += cnt + } + case map[string]string: + cnt, err := session.insertMapString(bean.(map[string]string)) + if err != nil { + return affected, err + } + affected += cnt + case []map[string]string: + s := bean.([]map[string]string) + session.autoResetStatement = false + for i := 0; i < len(s); i++ { + cnt, err := session.insertMapString(s[i]) + if err != nil { + return affected, err + } + affected += cnt + } + default: + sliceValue := reflect.Indirect(reflect.ValueOf(bean)) + if sliceValue.Kind() == reflect.Slice { + size := sliceValue.Len() + if size > 0 { + if session.engine.SupportInsertMany() { + cnt, err := session.innerInsertMulti(bean) + if err != nil { + return affected, err + } + affected += cnt + } else { + for i := 0; i < size; i++ { + cnt, err := session.innerInsert(sliceValue.Index(i).Interface()) + if err != nil { + return affected, err + } + affected += cnt + } + } + } + } else { + cnt, err := session.innerInsert(bean) + if err != nil { + return affected, err + } + affected += cnt + } } } @@ -337,21 +373,30 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { var sqlStr string var tableName = session.statement.TableName() + var output string + if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 { + output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement) + } if len(colPlaces) > 0 { - sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", + sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v)%s VALUES (%v)", session.engine.Quote(tableName), session.engine.QuoteStr(), strings.Join(colNames, session.engine.Quote(", ")), session.engine.QuoteStr(), + output, colPlaces) } else { if session.engine.dialect.DBType() == core.MYSQL { sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName)) } else { - sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.engine.Quote(tableName)) + sqlStr = fmt.Sprintf("INSERT INTO %s%s DEFAULT VALUES", session.engine.Quote(tableName), output) } } + if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES { + sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement) + } + handleAfterInsertProcessorFunc := func(bean interface{}) { if session.isAutoCommit { for _, closure := range session.afterClosures { @@ -423,9 +468,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { aiValue.Set(int64ToIntValue(id, aiValue.Type())) return 1, nil - } else if session.engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 { - //assert table.AutoIncrement != "" - sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement) + } else if len(table.AutoIncrement) > 0 && (session.engine.dialect.DBType() == core.POSTGRES || session.engine.dialect.DBType() == core.MSSQL) { res, err := session.queryBytes(sqlStr, args...) if err != nil { @@ -445,7 +488,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } if len(res) < 1 { - return 0, errors.New("insert no error but not returned id") + return 0, errors.New("insert successfully but not returned id") } idByte := res[0][table.AutoIncrement] @@ -622,3 +665,83 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac } return colNames, args, nil } + +func (session *Session) insertMapInterface(m map[string]interface{}) (int64, error) { + if len(m) == 0 { + return 0, ErrParamsType + } + + var columns = make([]string, 0, len(m)) + for k := range m { + columns = append(columns, k) + } + sort.Strings(columns) + + qm := strings.Repeat("?,", len(columns)) + qm = "(" + qm[:len(qm)-1] + ")" + + tableName := session.statement.TableName() + if len(tableName) <= 0 { + return 0, ErrTableNotFound + } + + var sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES %s", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm) + var args = make([]interface{}, 0, len(m)) + for _, colName := range columns { + args = append(args, m[colName]) + } + + if err := session.cacheInsert(tableName); err != nil { + return 0, err + } + + res, err := session.exec(sql, args...) + if err != nil { + return 0, err + } + affected, err := res.RowsAffected() + if err != nil { + return 0, err + } + return affected, nil +} + +func (session *Session) insertMapString(m map[string]string) (int64, error) { + if len(m) == 0 { + return 0, ErrParamsType + } + + var columns = make([]string, 0, len(m)) + for k := range m { + columns = append(columns, k) + } + sort.Strings(columns) + + qm := strings.Repeat("?,", len(columns)) + qm = "(" + qm[:len(qm)-1] + ")" + + tableName := session.statement.TableName() + if len(tableName) <= 0 { + return 0, ErrTableNotFound + } + + var sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES %s", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm) + var args = make([]interface{}, 0, len(m)) + for _, colName := range columns { + args = append(args, m[colName]) + } + + if err := session.cacheInsert(tableName); err != nil { + return 0, err + } + + res, err := session.exec(sql, args...) + if err != nil { + return 0, err + } + affected, err := res.RowsAffected() + if err != nil { + return 0, err + } + return affected, nil +} diff --git a/vendor/github.com/go-xorm/xorm/session_iterate.go b/vendor/github.com/go-xorm/xorm/session_iterate.go index 071fce4992..ca996c2884 100644 --- a/vendor/github.com/go-xorm/xorm/session_iterate.go +++ b/vendor/github.com/go-xorm/xorm/session_iterate.go @@ -23,6 +23,10 @@ func (session *Session) Iterate(bean interface{}, fun IterFunc) error { defer session.Close() } + if session.statement.lastError != nil { + return session.statement.lastError + } + if session.statement.bufferSize > 0 { return session.bufferIterate(bean, fun) } diff --git a/vendor/github.com/go-xorm/xorm/session_query.go b/vendor/github.com/go-xorm/xorm/session_query.go index 6d597cc459..21c00b8d7f 100644 --- a/vendor/github.com/go-xorm/xorm/session_query.go +++ b/vendor/github.com/go-xorm/xorm/session_query.go @@ -11,13 +11,13 @@ import ( "strings" "time" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) -func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) { - if len(sqlorArgs) > 0 { - return convertSQLOrArgs(sqlorArgs...) +func (session *Session) genQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) { + if len(sqlOrArgs) > 0 { + return convertSQLOrArgs(sqlOrArgs...) } if session.statement.RawSQL != "" { @@ -78,12 +78,12 @@ func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interfa } // Query runs a raw sql and return records as []map[string][]byte -func (session *Session) Query(sqlorArgs ...interface{}) ([]map[string][]byte, error) { +func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) { if session.isAutoClose { defer session.Close() } - sqlStr, args, err := session.genQuerySQL(sqlorArgs...) + sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) if err != nil { return nil, err } @@ -227,12 +227,12 @@ func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) { } // QueryString runs a raw sql and return records as []map[string]string -func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) { +func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) { if session.isAutoClose { defer session.Close() } - sqlStr, args, err := session.genQuerySQL(sqlorArgs...) + sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) if err != nil { return nil, err } @@ -247,12 +247,12 @@ func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]stri } // QuerySliceString runs a raw sql and return records as [][]string -func (session *Session) QuerySliceString(sqlorArgs ...interface{}) ([][]string, error) { +func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) { if session.isAutoClose { defer session.Close() } - sqlStr, args, err := session.genQuerySQL(sqlorArgs...) + sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) if err != nil { return nil, err } @@ -300,12 +300,12 @@ func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, er } // QueryInterface runs a raw sql and return records as []map[string]interface{} -func (session *Session) QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error) { +func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) { if session.isAutoClose { defer session.Close() } - sqlStr, args, err := session.genQuerySQL(sqlorArgs...) + sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) if err != nil { return nil, err } diff --git a/vendor/github.com/go-xorm/xorm/session_raw.go b/vendor/github.com/go-xorm/xorm/session_raw.go index 47823d6706..67648ef130 100644 --- a/vendor/github.com/go-xorm/xorm/session_raw.go +++ b/vendor/github.com/go-xorm/xorm/session_raw.go @@ -9,8 +9,8 @@ import ( "reflect" "time" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) { @@ -49,7 +49,7 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row if session.isAutoCommit { var db *core.DB - if session.engine.engineGroup != nil { + if session.sessionType == groupSession { db = session.engine.engineGroup.Slave().DB() } else { db = session.DB() @@ -62,21 +62,21 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row return nil, err } - rows, err := stmt.Query(args...) + rows, err := stmt.QueryContext(session.ctx, args...) if err != nil { return nil, err } return rows, nil } - rows, err := db.Query(sqlStr, args...) + rows, err := db.QueryContext(session.ctx, sqlStr, args...) if err != nil { return nil, err } return rows, nil } - rows, err := session.tx.Query(sqlStr, args...) + rows, err := session.tx.QueryContext(session.ctx, sqlStr, args...) if err != nil { return nil, err } @@ -175,7 +175,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er } if !session.isAutoCommit { - return session.tx.Exec(sqlStr, args...) + return session.tx.ExecContext(session.ctx, sqlStr, args...) } if session.prepareStmt { @@ -184,24 +184,24 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er return nil, err } - res, err := stmt.Exec(args...) + res, err := stmt.ExecContext(session.ctx, args...) if err != nil { return nil, err } return res, nil } - return session.DB().Exec(sqlStr, args...) + return session.DB().ExecContext(session.ctx, sqlStr, args...) } -func convertSQLOrArgs(sqlorArgs ...interface{}) (string, []interface{}, error) { - switch sqlorArgs[0].(type) { +func convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) { + switch sqlOrArgs[0].(type) { case string: - return sqlorArgs[0].(string), sqlorArgs[1:], nil + return sqlOrArgs[0].(string), sqlOrArgs[1:], nil case *builder.Builder: - return sqlorArgs[0].(*builder.Builder).ToSQL() + return sqlOrArgs[0].(*builder.Builder).ToSQL() case builder.Builder: - bd := sqlorArgs[0].(builder.Builder) + bd := sqlOrArgs[0].(builder.Builder) return bd.ToSQL() } @@ -209,16 +209,16 @@ func convertSQLOrArgs(sqlorArgs ...interface{}) (string, []interface{}, error) { } // Exec raw sql -func (session *Session) Exec(sqlorArgs ...interface{}) (sql.Result, error) { +func (session *Session) Exec(sqlOrArgs ...interface{}) (sql.Result, error) { if session.isAutoClose { defer session.Close() } - if len(sqlorArgs) == 0 { + if len(sqlOrArgs) == 0 { return nil, ErrUnSupportedType } - sqlStr, args, err := convertSQLOrArgs(sqlorArgs...) + sqlStr, args, err := convertSQLOrArgs(sqlOrArgs...) if err != nil { return nil, err } diff --git a/vendor/github.com/go-xorm/xorm/session_schema.go b/vendor/github.com/go-xorm/xorm/session_schema.go index 369ec72a4d..da5c885599 100644 --- a/vendor/github.com/go-xorm/xorm/session_schema.go +++ b/vendor/github.com/go-xorm/xorm/session_schema.go @@ -9,7 +9,7 @@ import ( "fmt" "strings" - "github.com/go-xorm/core" + "xorm.io/core" ) // Ping test if database is ok @@ -19,7 +19,7 @@ func (session *Session) Ping() error { } session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName()) - return session.DB().Ping() + return session.DB().PingContext(session.ctx) } // CreateTable create a table according a bean diff --git a/vendor/github.com/go-xorm/xorm/session_tx.go b/vendor/github.com/go-xorm/xorm/session_tx.go index c8d759a31a..ee3d473f95 100644 --- a/vendor/github.com/go-xorm/xorm/session_tx.go +++ b/vendor/github.com/go-xorm/xorm/session_tx.go @@ -7,7 +7,7 @@ package xorm // Begin a transaction func (session *Session) Begin() error { if session.isAutoCommit { - tx, err := session.DB().Begin() + tx, err := session.DB().BeginTx(session.ctx, nil) if err != nil { return err } diff --git a/vendor/github.com/go-xorm/xorm/session_update.go b/vendor/github.com/go-xorm/xorm/session_update.go index 37b34ff3dd..216c4e87dd 100644 --- a/vendor/github.com/go-xorm/xorm/session_update.go +++ b/vendor/github.com/go-xorm/xorm/session_update.go @@ -11,8 +11,8 @@ import ( "strconv" "strings" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string, args ...interface{}) error { @@ -147,6 +147,10 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 defer session.Close() } + if session.statement.lastError != nil { + return 0, session.statement.lastError + } + v := rValue(bean) t := v.Type() @@ -240,23 +244,39 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 } var autoCond builder.Cond - if !session.statement.noAutoCondition && len(condiBean) > 0 { - if c, ok := condiBean[0].(map[string]interface{}); ok { - autoCond = builder.Eq(c) - } else { - ct := reflect.TypeOf(condiBean[0]) - k := ct.Kind() - if k == reflect.Ptr { - k = ct.Elem().Kind() - } - if k == reflect.Struct { - var err error - autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false) - if err != nil { - return 0, err - } + if !session.statement.noAutoCondition { + condBeanIsStruct := false + if len(condiBean) > 0 { + if c, ok := condiBean[0].(map[string]interface{}); ok { + autoCond = builder.Eq(c) } else { - return 0, ErrConditionType + ct := reflect.TypeOf(condiBean[0]) + k := ct.Kind() + if k == reflect.Ptr { + k = ct.Elem().Kind() + } + if k == reflect.Struct { + var err error + autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false) + if err != nil { + return 0, err + } + condBeanIsStruct = true + } else { + return 0, ErrConditionType + } + } + } + + if !condBeanIsStruct && table != nil { + if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled + autoCond1 := session.engine.CondDeleted(session.engine.Quote(col.Name)) + + if autoCond == nil { + autoCond = autoCond1 + } else { + autoCond = autoCond.And(autoCond1) + } } } } diff --git a/vendor/github.com/go-xorm/xorm/statement.go b/vendor/github.com/go-xorm/xorm/statement.go index a7f7010ad2..88b8423517 100644 --- a/vendor/github.com/go-xorm/xorm/statement.go +++ b/vendor/github.com/go-xorm/xorm/statement.go @@ -6,15 +6,14 @@ package xorm import ( "database/sql/driver" - "encoding/json" "errors" "fmt" "reflect" "strings" "time" - "github.com/go-xorm/builder" - "github.com/go-xorm/core" + "xorm.io/builder" + "xorm.io/core" ) // Statement save all the sql info for executing SQL @@ -60,6 +59,7 @@ type Statement struct { cond builder.Cond bufferSize int context ContextCache + lastError error } // Init reset all the statement's fields @@ -101,6 +101,7 @@ func (statement *Statement) Init() { statement.cond = builder.NewCond() statement.bufferSize = 0 statement.context = nil + statement.lastError = nil } // NoAutoCondition if you do not want convert bean's field as query condition, then use this function @@ -125,13 +126,13 @@ func (statement *Statement) SQL(query interface{}, args ...interface{}) *Stateme var err error statement.RawSQL, statement.RawParams, err = query.(*builder.Builder).ToSQL() if err != nil { - statement.Engine.logger.Error(err) + statement.lastError = err } case string: statement.RawSQL = query.(string) statement.RawParams = args default: - statement.Engine.logger.Error("unsupported sql type") + statement.lastError = ErrUnSupportedSQLType } return statement @@ -160,7 +161,7 @@ func (statement *Statement) And(query interface{}, args ...interface{}) *Stateme } } default: - // TODO: not support condition type + statement.lastError = ErrConditionType } return statement @@ -406,7 +407,7 @@ func (statement *Statement) buildUpdates(bean interface{}, } else { // Blank struct could not be as update data if requiredField || !isStructZero(fieldValue) { - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { panic(fmt.Sprintf("mashal %v failed", fieldValue.Interface())) } @@ -435,7 +436,7 @@ func (statement *Statement) buildUpdates(bean interface{}, } if col.SQLType.IsText() { - bytes, err := json.Marshal(fieldValue.Interface()) + bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { engine.logger.Error(err) continue @@ -455,7 +456,7 @@ func (statement *Statement) buildUpdates(bean interface{}, fieldType.Elem().Kind() == reflect.Uint8 { val = fieldValue.Slice(0, 0).Interface() } else { - bytes, err = json.Marshal(fieldValue.Interface()) + bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) if err != nil { engine.logger.Error(err) continue @@ -755,9 +756,32 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition fmt.Fprintf(&buf, "%v JOIN ", joinOP) } - tbName := statement.Engine.TableName(tablename, true) + switch tp := tablename.(type) { + case builder.Builder: + subSQL, subQueryArgs, err := tp.ToSQL() + if err != nil { + statement.lastError = err + return statement + } + tbs := strings.Split(tp.TableName(), ".") + var aliasName = strings.Trim(tbs[len(tbs)-1], statement.Engine.QuoteStr()) + fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition) + statement.joinArgs = append(statement.joinArgs, subQueryArgs...) + case *builder.Builder: + subSQL, subQueryArgs, err := tp.ToSQL() + if err != nil { + statement.lastError = err + return statement + } + tbs := strings.Split(tp.TableName(), ".") + var aliasName = strings.Trim(tbs[len(tbs)-1], statement.Engine.QuoteStr()) + fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition) + statement.joinArgs = append(statement.joinArgs, subQueryArgs...) + default: + tbName := statement.Engine.TableName(tablename, true) + fmt.Fprintf(&buf, "%s ON %v", tbName, condition) + } - fmt.Fprintf(&buf, "%s ON %v", tbName, condition) statement.JoinStr = buf.String() statement.joinArgs = append(statement.joinArgs, args...) return statement @@ -1064,7 +1088,7 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n if dialect.DBType() == core.MSSQL { if statement.LimitN > 0 { - top = fmt.Sprintf(" TOP %d ", statement.LimitN) + top = fmt.Sprintf("TOP %d ", statement.LimitN) } if statement.Start > 0 { var column string diff --git a/vendor/github.com/go-xorm/xorm/syslogger.go b/vendor/github.com/go-xorm/xorm/syslogger.go index 8840635d4c..11ba01e7bd 100644 --- a/vendor/github.com/go-xorm/xorm/syslogger.go +++ b/vendor/github.com/go-xorm/xorm/syslogger.go @@ -10,7 +10,7 @@ import ( "fmt" "log/syslog" - "github.com/go-xorm/core" + "xorm.io/core" ) var _ core.ILogger = &SyslogLogger{} diff --git a/vendor/github.com/go-xorm/xorm/tag.go b/vendor/github.com/go-xorm/xorm/tag.go index e1c821fb54..eb87be7829 100644 --- a/vendor/github.com/go-xorm/xorm/tag.go +++ b/vendor/github.com/go-xorm/xorm/tag.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) type tagContext struct { diff --git a/vendor/github.com/go-xorm/xorm/test_mssql.sh b/vendor/github.com/go-xorm/xorm/test_mssql.sh index 6f9cf7295f..7f060cff32 100644 --- a/vendor/github.com/go-xorm/xorm/test_mssql.sh +++ b/vendor/github.com/go-xorm/xorm/test_mssql.sh @@ -1 +1 @@ -go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test" \ No newline at end of file +go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/test_tidb.sh b/vendor/github.com/go-xorm/xorm/test_tidb.sh new file mode 100644 index 0000000000..03d2d6cd82 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/test_tidb.sh @@ -0,0 +1 @@ +go test -db=mysql -conn_str="root:@tcp(localhost:4000)/xorm_test" -ignore_select_update=true \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/types.go b/vendor/github.com/go-xorm/xorm/types.go index 99d761c278..c76a546065 100644 --- a/vendor/github.com/go-xorm/xorm/types.go +++ b/vendor/github.com/go-xorm/xorm/types.go @@ -1,9 +1,13 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package xorm import ( "reflect" - "github.com/go-xorm/core" + "xorm.io/core" ) var ( diff --git a/vendor/github.com/go-xorm/xorm/xorm.go b/vendor/github.com/go-xorm/xorm/xorm.go index 739de8d429..26d00d264d 100644 --- a/vendor/github.com/go-xorm/xorm/xorm.go +++ b/vendor/github.com/go-xorm/xorm/xorm.go @@ -7,6 +7,7 @@ package xorm import ( + "context" "fmt" "os" "reflect" @@ -14,7 +15,7 @@ import ( "sync" "time" - "github.com/go-xorm/core" + "xorm.io/core" ) const ( @@ -85,14 +86,15 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { } engine := &Engine{ - db: db, - dialect: dialect, - Tables: make(map[reflect.Type]*core.Table), - mutex: &sync.RWMutex{}, - TagIdentifier: "xorm", - TZLocation: time.Local, - tagHandlers: defaultTagHandlers, - cachers: make(map[string]core.Cacher), + db: db, + dialect: dialect, + Tables: make(map[reflect.Type]*core.Table), + mutex: &sync.RWMutex{}, + TagIdentifier: "xorm", + TZLocation: time.Local, + tagHandlers: defaultTagHandlers, + cachers: make(map[string]core.Cacher), + defaultContext: context.Background(), } if uri.DbType == core.SQLITE { diff --git a/vendor/google.golang.org/appengine/internal/api.go b/vendor/google.golang.org/appengine/internal/api.go index 16f87c5d37..bbc1cb9c34 100644 --- a/vendor/google.golang.org/appengine/internal/api.go +++ b/vendor/google.golang.org/appengine/internal/api.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. // +build !appengine -// +build go1.7 package internal @@ -130,7 +129,13 @@ func handleHTTP(w http.ResponseWriter, r *http.Request) { flushes++ } c.pendingLogs.Unlock() - go c.flushLog(false) + flushed := make(chan struct{}) + go func() { + defer close(flushed) + // Force a log flush, because with very short requests we + // may not ever flush logs. + c.flushLog(true) + }() w.Header().Set(logFlushHeader, strconv.Itoa(flushes)) // Avoid nil Write call if c.Write is never called. @@ -140,6 +145,9 @@ func handleHTTP(w http.ResponseWriter, r *http.Request) { if c.outBody != nil { w.Write(c.outBody) } + // Wait for the last flush to complete before returning, + // otherwise the security ticket will not be valid. + <-flushed } func executeRequestSafely(c *context, r *http.Request) { @@ -571,7 +579,10 @@ func logf(c *context, level int64, format string, args ...interface{}) { Level: &level, Message: &s, }) - log.Print(logLevelName[level] + ": " + s) + // Only duplicate log to stderr if not running on App Engine second generation + if !IsSecondGen() { + log.Print(logLevelName[level] + ": " + s) + } } // flushLog attempts to flush any pending logs to the appserver. diff --git a/vendor/google.golang.org/appengine/internal/api_pre17.go b/vendor/google.golang.org/appengine/internal/api_pre17.go deleted file mode 100644 index 028b4f056e..0000000000 --- a/vendor/google.golang.org/appengine/internal/api_pre17.go +++ /dev/null @@ -1,682 +0,0 @@ -// Copyright 2011 Google Inc. All rights reserved. -// Use of this source code is governed by the Apache 2.0 -// license that can be found in the LICENSE file. - -// +build !appengine -// +build !go1.7 - -package internal - -import ( - "bytes" - "errors" - "fmt" - "io/ioutil" - "log" - "net" - "net/http" - "net/url" - "os" - "runtime" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/golang/protobuf/proto" - netcontext "golang.org/x/net/context" - - basepb "google.golang.org/appengine/internal/base" - logpb "google.golang.org/appengine/internal/log" - remotepb "google.golang.org/appengine/internal/remote_api" -) - -const ( - apiPath = "/rpc_http" - defaultTicketSuffix = "/default.20150612t184001.0" -) - -var ( - // Incoming headers. - ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket") - dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo") - traceHeader = http.CanonicalHeaderKey("X-Cloud-Trace-Context") - curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace") - userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP") - remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr") - - // Outgoing headers. - apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint") - apiEndpointHeaderValue = []string{"app-engine-apis"} - apiMethodHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Method") - apiMethodHeaderValue = []string{"/VMRemoteAPI.CallRemoteAPI"} - apiDeadlineHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Deadline") - apiContentType = http.CanonicalHeaderKey("Content-Type") - apiContentTypeValue = []string{"application/octet-stream"} - logFlushHeader = http.CanonicalHeaderKey("X-AppEngine-Log-Flush-Count") - - apiHTTPClient = &http.Client{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - Dial: limitDial, - }, - } - - defaultTicketOnce sync.Once - defaultTicket string -) - -func apiURL() *url.URL { - host, port := "appengine.googleapis.internal", "10001" - if h := os.Getenv("API_HOST"); h != "" { - host = h - } - if p := os.Getenv("API_PORT"); p != "" { - port = p - } - return &url.URL{ - Scheme: "http", - Host: host + ":" + port, - Path: apiPath, - } -} - -func handleHTTP(w http.ResponseWriter, r *http.Request) { - c := &context{ - req: r, - outHeader: w.Header(), - apiURL: apiURL(), - } - stopFlushing := make(chan int) - - ctxs.Lock() - ctxs.m[r] = c - ctxs.Unlock() - defer func() { - ctxs.Lock() - delete(ctxs.m, r) - ctxs.Unlock() - }() - - // Patch up RemoteAddr so it looks reasonable. - if addr := r.Header.Get(userIPHeader); addr != "" { - r.RemoteAddr = addr - } else if addr = r.Header.Get(remoteAddrHeader); addr != "" { - r.RemoteAddr = addr - } else { - // Should not normally reach here, but pick a sensible default anyway. - r.RemoteAddr = "127.0.0.1" - } - // The address in the headers will most likely be of these forms: - // 123.123.123.123 - // 2001:db8::1 - // net/http.Request.RemoteAddr is specified to be in "IP:port" form. - if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil { - // Assume the remote address is only a host; add a default port. - r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80") - } - - // Start goroutine responsible for flushing app logs. - // This is done after adding c to ctx.m (and stopped before removing it) - // because flushing logs requires making an API call. - go c.logFlusher(stopFlushing) - - executeRequestSafely(c, r) - c.outHeader = nil // make sure header changes aren't respected any more - - stopFlushing <- 1 // any logging beyond this point will be dropped - - // Flush any pending logs asynchronously. - c.pendingLogs.Lock() - flushes := c.pendingLogs.flushes - if len(c.pendingLogs.lines) > 0 { - flushes++ - } - c.pendingLogs.Unlock() - go c.flushLog(false) - w.Header().Set(logFlushHeader, strconv.Itoa(flushes)) - - // Avoid nil Write call if c.Write is never called. - if c.outCode != 0 { - w.WriteHeader(c.outCode) - } - if c.outBody != nil { - w.Write(c.outBody) - } -} - -func executeRequestSafely(c *context, r *http.Request) { - defer func() { - if x := recover(); x != nil { - logf(c, 4, "%s", renderPanic(x)) // 4 == critical - c.outCode = 500 - } - }() - - http.DefaultServeMux.ServeHTTP(c, r) -} - -func renderPanic(x interface{}) string { - buf := make([]byte, 16<<10) // 16 KB should be plenty - buf = buf[:runtime.Stack(buf, false)] - - // Remove the first few stack frames: - // this func - // the recover closure in the caller - // That will root the stack trace at the site of the panic. - const ( - skipStart = "internal.renderPanic" - skipFrames = 2 - ) - start := bytes.Index(buf, []byte(skipStart)) - p := start - for i := 0; i < skipFrames*2 && p+1 < len(buf); i++ { - p = bytes.IndexByte(buf[p+1:], '\n') + p + 1 - if p < 0 { - break - } - } - if p >= 0 { - // buf[start:p+1] is the block to remove. - // Copy buf[p+1:] over buf[start:] and shrink buf. - copy(buf[start:], buf[p+1:]) - buf = buf[:len(buf)-(p+1-start)] - } - - // Add panic heading. - head := fmt.Sprintf("panic: %v\n\n", x) - if len(head) > len(buf) { - // Extremely unlikely to happen. - return head - } - copy(buf[len(head):], buf) - copy(buf, head) - - return string(buf) -} - -var ctxs = struct { - sync.Mutex - m map[*http.Request]*context - bg *context // background context, lazily initialized - // dec is used by tests to decorate the netcontext.Context returned - // for a given request. This allows tests to add overrides (such as - // WithAppIDOverride) to the context. The map is nil outside tests. - dec map[*http.Request]func(netcontext.Context) netcontext.Context -}{ - m: make(map[*http.Request]*context), -} - -// context represents the context of an in-flight HTTP request. -// It implements the appengine.Context and http.ResponseWriter interfaces. -type context struct { - req *http.Request - - outCode int - outHeader http.Header - outBody []byte - - pendingLogs struct { - sync.Mutex - lines []*logpb.UserAppLogLine - flushes int - } - - apiURL *url.URL -} - -var contextKey = "holds a *context" - -// fromContext returns the App Engine context or nil if ctx is not -// derived from an App Engine context. -func fromContext(ctx netcontext.Context) *context { - c, _ := ctx.Value(&contextKey).(*context) - return c -} - -func withContext(parent netcontext.Context, c *context) netcontext.Context { - ctx := netcontext.WithValue(parent, &contextKey, c) - if ns := c.req.Header.Get(curNamespaceHeader); ns != "" { - ctx = withNamespace(ctx, ns) - } - return ctx -} - -func toContext(c *context) netcontext.Context { - return withContext(netcontext.Background(), c) -} - -func IncomingHeaders(ctx netcontext.Context) http.Header { - if c := fromContext(ctx); c != nil { - return c.req.Header - } - return nil -} - -func ReqContext(req *http.Request) netcontext.Context { - return WithContext(netcontext.Background(), req) -} - -func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context { - ctxs.Lock() - c := ctxs.m[req] - d := ctxs.dec[req] - ctxs.Unlock() - - if d != nil { - parent = d(parent) - } - - if c == nil { - // Someone passed in an http.Request that is not in-flight. - // We panic here rather than panicking at a later point - // so that stack traces will be more sensible. - log.Panic("appengine: NewContext passed an unknown http.Request") - } - return withContext(parent, c) -} - -// DefaultTicket returns a ticket used for background context or dev_appserver. -func DefaultTicket() string { - defaultTicketOnce.Do(func() { - if IsDevAppServer() { - defaultTicket = "testapp" + defaultTicketSuffix - return - } - appID := partitionlessAppID() - escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1) - majVersion := VersionID(nil) - if i := strings.Index(majVersion, "."); i > 0 { - majVersion = majVersion[:i] - } - defaultTicket = fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(nil), majVersion, InstanceID()) - }) - return defaultTicket -} - -func BackgroundContext() netcontext.Context { - ctxs.Lock() - defer ctxs.Unlock() - - if ctxs.bg != nil { - return toContext(ctxs.bg) - } - - // Compute background security ticket. - ticket := DefaultTicket() - - ctxs.bg = &context{ - req: &http.Request{ - Header: http.Header{ - ticketHeader: []string{ticket}, - }, - }, - apiURL: apiURL(), - } - - // TODO(dsymonds): Wire up the shutdown handler to do a final flush. - go ctxs.bg.logFlusher(make(chan int)) - - return toContext(ctxs.bg) -} - -// RegisterTestRequest registers the HTTP request req for testing, such that -// any API calls are sent to the provided URL. It returns a closure to delete -// the registration. -// It should only be used by aetest package. -func RegisterTestRequest(req *http.Request, apiURL *url.URL, decorate func(netcontext.Context) netcontext.Context) (*http.Request, func()) { - c := &context{ - req: req, - apiURL: apiURL, - } - ctxs.Lock() - defer ctxs.Unlock() - if _, ok := ctxs.m[req]; ok { - log.Panic("req already associated with context") - } - if _, ok := ctxs.dec[req]; ok { - log.Panic("req already associated with context") - } - if ctxs.dec == nil { - ctxs.dec = make(map[*http.Request]func(netcontext.Context) netcontext.Context) - } - ctxs.m[req] = c - ctxs.dec[req] = decorate - - return req, func() { - ctxs.Lock() - delete(ctxs.m, req) - delete(ctxs.dec, req) - ctxs.Unlock() - } -} - -var errTimeout = &CallError{ - Detail: "Deadline exceeded", - Code: int32(remotepb.RpcError_CANCELLED), - Timeout: true, -} - -func (c *context) Header() http.Header { return c.outHeader } - -// Copied from $GOROOT/src/pkg/net/http/transfer.go. Some response status -// codes do not permit a response body (nor response entity headers such as -// Content-Length, Content-Type, etc). -func bodyAllowedForStatus(status int) bool { - switch { - case status >= 100 && status <= 199: - return false - case status == 204: - return false - case status == 304: - return false - } - return true -} - -func (c *context) Write(b []byte) (int, error) { - if c.outCode == 0 { - c.WriteHeader(http.StatusOK) - } - if len(b) > 0 && !bodyAllowedForStatus(c.outCode) { - return 0, http.ErrBodyNotAllowed - } - c.outBody = append(c.outBody, b...) - return len(b), nil -} - -func (c *context) WriteHeader(code int) { - if c.outCode != 0 { - logf(c, 3, "WriteHeader called multiple times on request.") // error level - return - } - c.outCode = code -} - -func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) { - hreq := &http.Request{ - Method: "POST", - URL: c.apiURL, - Header: http.Header{ - apiEndpointHeader: apiEndpointHeaderValue, - apiMethodHeader: apiMethodHeaderValue, - apiContentType: apiContentTypeValue, - apiDeadlineHeader: []string{strconv.FormatFloat(timeout.Seconds(), 'f', -1, 64)}, - }, - Body: ioutil.NopCloser(bytes.NewReader(body)), - ContentLength: int64(len(body)), - Host: c.apiURL.Host, - } - if info := c.req.Header.Get(dapperHeader); info != "" { - hreq.Header.Set(dapperHeader, info) - } - if info := c.req.Header.Get(traceHeader); info != "" { - hreq.Header.Set(traceHeader, info) - } - - tr := apiHTTPClient.Transport.(*http.Transport) - - var timedOut int32 // atomic; set to 1 if timed out - t := time.AfterFunc(timeout, func() { - atomic.StoreInt32(&timedOut, 1) - tr.CancelRequest(hreq) - }) - defer t.Stop() - defer func() { - // Check if timeout was exceeded. - if atomic.LoadInt32(&timedOut) != 0 { - err = errTimeout - } - }() - - hresp, err := apiHTTPClient.Do(hreq) - if err != nil { - return nil, &CallError{ - Detail: fmt.Sprintf("service bridge HTTP failed: %v", err), - Code: int32(remotepb.RpcError_UNKNOWN), - } - } - defer hresp.Body.Close() - hrespBody, err := ioutil.ReadAll(hresp.Body) - if hresp.StatusCode != 200 { - return nil, &CallError{ - Detail: fmt.Sprintf("service bridge returned HTTP %d (%q)", hresp.StatusCode, hrespBody), - Code: int32(remotepb.RpcError_UNKNOWN), - } - } - if err != nil { - return nil, &CallError{ - Detail: fmt.Sprintf("service bridge response bad: %v", err), - Code: int32(remotepb.RpcError_UNKNOWN), - } - } - return hrespBody, nil -} - -func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error { - if ns := NamespaceFromContext(ctx); ns != "" { - if fn, ok := NamespaceMods[service]; ok { - fn(in, ns) - } - } - - if f, ctx, ok := callOverrideFromContext(ctx); ok { - return f(ctx, service, method, in, out) - } - - // Handle already-done contexts quickly. - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - - c := fromContext(ctx) - if c == nil { - // Give a good error message rather than a panic lower down. - return errNotAppEngineContext - } - - // Apply transaction modifications if we're in a transaction. - if t := transactionFromContext(ctx); t != nil { - if t.finished { - return errors.New("transaction context has expired") - } - applyTransaction(in, &t.transaction) - } - - // Default RPC timeout is 60s. - timeout := 60 * time.Second - if deadline, ok := ctx.Deadline(); ok { - timeout = deadline.Sub(time.Now()) - } - - data, err := proto.Marshal(in) - if err != nil { - return err - } - - ticket := c.req.Header.Get(ticketHeader) - // Use a test ticket under test environment. - if ticket == "" { - if appid := ctx.Value(&appIDOverrideKey); appid != nil { - ticket = appid.(string) + defaultTicketSuffix - } - } - // Fall back to use background ticket when the request ticket is not available in Flex or dev_appserver. - if ticket == "" { - ticket = DefaultTicket() - } - req := &remotepb.Request{ - ServiceName: &service, - Method: &method, - Request: data, - RequestId: &ticket, - } - hreqBody, err := proto.Marshal(req) - if err != nil { - return err - } - - hrespBody, err := c.post(hreqBody, timeout) - if err != nil { - return err - } - - res := &remotepb.Response{} - if err := proto.Unmarshal(hrespBody, res); err != nil { - return err - } - if res.RpcError != nil { - ce := &CallError{ - Detail: res.RpcError.GetDetail(), - Code: *res.RpcError.Code, - } - switch remotepb.RpcError_ErrorCode(ce.Code) { - case remotepb.RpcError_CANCELLED, remotepb.RpcError_DEADLINE_EXCEEDED: - ce.Timeout = true - } - return ce - } - if res.ApplicationError != nil { - return &APIError{ - Service: *req.ServiceName, - Detail: res.ApplicationError.GetDetail(), - Code: *res.ApplicationError.Code, - } - } - if res.Exception != nil || res.JavaException != nil { - // This shouldn't happen, but let's be defensive. - return &CallError{ - Detail: "service bridge returned exception", - Code: int32(remotepb.RpcError_UNKNOWN), - } - } - return proto.Unmarshal(res.Response, out) -} - -func (c *context) Request() *http.Request { - return c.req -} - -func (c *context) addLogLine(ll *logpb.UserAppLogLine) { - // Truncate long log lines. - // TODO(dsymonds): Check if this is still necessary. - const lim = 8 << 10 - if len(*ll.Message) > lim { - suffix := fmt.Sprintf("...(length %d)", len(*ll.Message)) - ll.Message = proto.String((*ll.Message)[:lim-len(suffix)] + suffix) - } - - c.pendingLogs.Lock() - c.pendingLogs.lines = append(c.pendingLogs.lines, ll) - c.pendingLogs.Unlock() -} - -var logLevelName = map[int64]string{ - 0: "DEBUG", - 1: "INFO", - 2: "WARNING", - 3: "ERROR", - 4: "CRITICAL", -} - -func logf(c *context, level int64, format string, args ...interface{}) { - if c == nil { - panic("not an App Engine context") - } - s := fmt.Sprintf(format, args...) - s = strings.TrimRight(s, "\n") // Remove any trailing newline characters. - c.addLogLine(&logpb.UserAppLogLine{ - TimestampUsec: proto.Int64(time.Now().UnixNano() / 1e3), - Level: &level, - Message: &s, - }) - log.Print(logLevelName[level] + ": " + s) -} - -// flushLog attempts to flush any pending logs to the appserver. -// It should not be called concurrently. -func (c *context) flushLog(force bool) (flushed bool) { - c.pendingLogs.Lock() - // Grab up to 30 MB. We can get away with up to 32 MB, but let's be cautious. - n, rem := 0, 30<<20 - for ; n < len(c.pendingLogs.lines); n++ { - ll := c.pendingLogs.lines[n] - // Each log line will require about 3 bytes of overhead. - nb := proto.Size(ll) + 3 - if nb > rem { - break - } - rem -= nb - } - lines := c.pendingLogs.lines[:n] - c.pendingLogs.lines = c.pendingLogs.lines[n:] - c.pendingLogs.Unlock() - - if len(lines) == 0 && !force { - // Nothing to flush. - return false - } - - rescueLogs := false - defer func() { - if rescueLogs { - c.pendingLogs.Lock() - c.pendingLogs.lines = append(lines, c.pendingLogs.lines...) - c.pendingLogs.Unlock() - } - }() - - buf, err := proto.Marshal(&logpb.UserAppLogGroup{ - LogLine: lines, - }) - if err != nil { - log.Printf("internal.flushLog: marshaling UserAppLogGroup: %v", err) - rescueLogs = true - return false - } - - req := &logpb.FlushRequest{ - Logs: buf, - } - res := &basepb.VoidProto{} - c.pendingLogs.Lock() - c.pendingLogs.flushes++ - c.pendingLogs.Unlock() - if err := Call(toContext(c), "logservice", "Flush", req, res); err != nil { - log.Printf("internal.flushLog: Flush RPC: %v", err) - rescueLogs = true - return false - } - return true -} - -const ( - // Log flushing parameters. - flushInterval = 1 * time.Second - forceFlushInterval = 60 * time.Second -) - -func (c *context) logFlusher(stop <-chan int) { - lastFlush := time.Now() - tick := time.NewTicker(flushInterval) - for { - select { - case <-stop: - // Request finished. - tick.Stop() - return - case <-tick.C: - force := time.Now().Sub(lastFlush) > forceFlushInterval - if c.flushLog(force) { - lastFlush = time.Now() - } - } - } -} - -func ContextForTesting(req *http.Request) netcontext.Context { - return toContext(&context{req: req}) -} diff --git a/vendor/google.golang.org/appengine/internal/identity.go b/vendor/google.golang.org/appengine/internal/identity.go index d538701ab3..9b4134e425 100644 --- a/vendor/google.golang.org/appengine/internal/identity.go +++ b/vendor/google.golang.org/appengine/internal/identity.go @@ -4,11 +4,52 @@ package internal -import netcontext "golang.org/x/net/context" +import ( + "os" -// These functions are implementations of the wrapper functions -// in ../appengine/identity.go. See that file for commentary. + netcontext "golang.org/x/net/context" +) +var ( + // This is set to true in identity_classic.go, which is behind the appengine build tag. + // The appengine build tag is set for the first generation runtimes (<= Go 1.9) but not + // the second generation runtimes (>= Go 1.11), so this indicates whether we're on a + // first-gen runtime. See IsStandard below for the second-gen check. + appengineStandard bool + + // This is set to true in identity_flex.go, which is behind the appenginevm build tag. + appengineFlex bool +) + +// AppID is the implementation of the wrapper function of the same name in +// ../identity.go. See that file for commentary. func AppID(c netcontext.Context) string { return appID(FullyQualifiedAppID(c)) } + +// IsStandard is the implementation of the wrapper function of the same name in +// ../appengine.go. See that file for commentary. +func IsStandard() bool { + // appengineStandard will be true for first-gen runtimes (<= Go 1.9) but not + // second-gen (>= Go 1.11). + return appengineStandard || IsSecondGen() +} + +// IsStandard is the implementation of the wrapper function of the same name in +// ../appengine.go. See that file for commentary. +func IsSecondGen() bool { + // Second-gen runtimes set $GAE_ENV so we use that to check if we're on a second-gen runtime. + return os.Getenv("GAE_ENV") == "standard" +} + +// IsFlex is the implementation of the wrapper function of the same name in +// ../appengine.go. See that file for commentary. +func IsFlex() bool { + return appengineFlex +} + +// IsAppEngine is the implementation of the wrapper function of the same name in +// ../appengine.go. See that file for commentary. +func IsAppEngine() bool { + return IsStandard() || IsFlex() +} diff --git a/vendor/google.golang.org/appengine/internal/identity_classic.go b/vendor/google.golang.org/appengine/internal/identity_classic.go index b59603f132..4e979f45e3 100644 --- a/vendor/google.golang.org/appengine/internal/identity_classic.go +++ b/vendor/google.golang.org/appengine/internal/identity_classic.go @@ -12,6 +12,10 @@ import ( netcontext "golang.org/x/net/context" ) +func init() { + appengineStandard = true +} + func DefaultVersionHostname(ctx netcontext.Context) string { c := fromContext(ctx) if c == nil { diff --git a/vendor/google.golang.org/appengine/internal/identity_flex.go b/vendor/google.golang.org/appengine/internal/identity_flex.go new file mode 100644 index 0000000000..d5e2e7b5e3 --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/identity_flex.go @@ -0,0 +1,11 @@ +// Copyright 2018 Google LLC. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +// +build appenginevm + +package internal + +func init() { + appengineFlex = true +} diff --git a/vendor/google.golang.org/appengine/internal/main.go b/vendor/google.golang.org/appengine/internal/main.go index 49036163c2..1e765312fd 100644 --- a/vendor/google.golang.org/appengine/internal/main.go +++ b/vendor/google.golang.org/appengine/internal/main.go @@ -11,5 +11,6 @@ import ( ) func Main() { + MainPath = "" appengine_internal.Main() } diff --git a/vendor/google.golang.org/appengine/internal/main_common.go b/vendor/google.golang.org/appengine/internal/main_common.go new file mode 100644 index 0000000000..357dce4dd0 --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/main_common.go @@ -0,0 +1,7 @@ +package internal + +// MainPath stores the file path of the main package. On App Engine Standard +// using Go version 1.9 and below, this will be unset. On App Engine Flex and +// App Engine Standard second-gen (Go 1.11 and above), this will be the +// filepath to package main. +var MainPath string diff --git a/vendor/google.golang.org/appengine/internal/main_vm.go b/vendor/google.golang.org/appengine/internal/main_vm.go index 822e784a45..ddb79a3338 100644 --- a/vendor/google.golang.org/appengine/internal/main_vm.go +++ b/vendor/google.golang.org/appengine/internal/main_vm.go @@ -12,9 +12,12 @@ import ( "net/http" "net/url" "os" + "path/filepath" + "runtime" ) func Main() { + MainPath = filepath.Dir(findMainPath()) installHealthChecker(http.DefaultServeMux) port := "8080" @@ -31,6 +34,24 @@ func Main() { } } +// Find the path to package main by looking at the root Caller. +func findMainPath() string { + pc := make([]uintptr, 100) + n := runtime.Callers(2, pc) + frames := runtime.CallersFrames(pc[:n]) + for { + frame, more := frames.Next() + // Tests won't have package main, instead they have testing.tRunner + if frame.Function == "main.main" || frame.Function == "testing.tRunner" { + return frame.File + } + if !more { + break + } + } + return "" +} + func installHealthChecker(mux *http.ServeMux) { // If no health check handler has been installed by this point, add a trivial one. const healthPath = "/_ah/health" diff --git a/vendor/modules.txt b/vendor/modules.txt index e7f91d5bc2..ef253f5194 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -85,7 +85,7 @@ github.com/couchbase/vellum/utf8 github.com/couchbaselabs/go-couchbase # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 +# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 github.com/denisenkom/go-mssqldb # github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac github.com/dgrijalva/jwt-go @@ -147,13 +147,9 @@ github.com/go-redis/redis/internal/hashtag github.com/go-redis/redis/internal/pool github.com/go-redis/redis/internal/proto github.com/go-redis/redis/internal/util -# github.com/go-sql-driver/mysql v1.4.0 => github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f +# github.com/go-sql-driver/mysql v1.4.1 github.com/go-sql-driver/mysql -# github.com/go-xorm/builder v0.3.3 -github.com/go-xorm/builder -# github.com/go-xorm/core v0.6.0 -github.com/go-xorm/core -# github.com/go-xorm/xorm v0.0.0-20190116032649-a6300f2a45e0 +# github.com/go-xorm/xorm v0.7.3-0.20190620151208-f1b4f8368459 github.com/go-xorm/xorm # github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/chardet @@ -396,7 +392,7 @@ golang.org/x/text/internal/language/compact golang.org/x/text/internal/utf8internal golang.org/x/text/runes golang.org/x/text/internal/tag -# google.golang.org/appengine v1.2.0 +# google.golang.org/appengine v1.4.0 google.golang.org/appengine/cloudsql google.golang.org/appengine/urlfetch google.golang.org/appengine/internal @@ -481,3 +477,7 @@ gopkg.in/yaml.v2 mvdan.cc/xurls/v2 # strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a strk.kbt.io/projects/go/libravatar +# xorm.io/builder v0.3.5 +xorm.io/builder +# xorm.io/core v0.6.3 +xorm.io/core diff --git a/vendor/github.com/go-xorm/builder/.drone.yml b/vendor/xorm.io/builder/.drone.yml similarity index 100% rename from vendor/github.com/go-xorm/builder/.drone.yml rename to vendor/xorm.io/builder/.drone.yml diff --git a/vendor/github.com/go-xorm/builder/LICENSE b/vendor/xorm.io/builder/LICENSE similarity index 100% rename from vendor/github.com/go-xorm/builder/LICENSE rename to vendor/xorm.io/builder/LICENSE diff --git a/vendor/github.com/go-xorm/builder/README.md b/vendor/xorm.io/builder/README.md similarity index 100% rename from vendor/github.com/go-xorm/builder/README.md rename to vendor/xorm.io/builder/README.md diff --git a/vendor/github.com/go-xorm/builder/builder.go b/vendor/xorm.io/builder/builder.go similarity index 100% rename from vendor/github.com/go-xorm/builder/builder.go rename to vendor/xorm.io/builder/builder.go diff --git a/vendor/github.com/go-xorm/builder/builder_delete.go b/vendor/xorm.io/builder/builder_delete.go similarity index 100% rename from vendor/github.com/go-xorm/builder/builder_delete.go rename to vendor/xorm.io/builder/builder_delete.go diff --git a/vendor/github.com/go-xorm/builder/builder_insert.go b/vendor/xorm.io/builder/builder_insert.go similarity index 100% rename from vendor/github.com/go-xorm/builder/builder_insert.go rename to vendor/xorm.io/builder/builder_insert.go diff --git a/vendor/github.com/go-xorm/builder/builder_limit.go b/vendor/xorm.io/builder/builder_limit.go similarity index 100% rename from vendor/github.com/go-xorm/builder/builder_limit.go rename to vendor/xorm.io/builder/builder_limit.go diff --git a/vendor/github.com/go-xorm/builder/builder_select.go b/vendor/xorm.io/builder/builder_select.go similarity index 100% rename from vendor/github.com/go-xorm/builder/builder_select.go rename to vendor/xorm.io/builder/builder_select.go diff --git a/vendor/github.com/go-xorm/builder/builder_union.go b/vendor/xorm.io/builder/builder_union.go similarity index 100% rename from vendor/github.com/go-xorm/builder/builder_union.go rename to vendor/xorm.io/builder/builder_union.go diff --git a/vendor/github.com/go-xorm/builder/builder_update.go b/vendor/xorm.io/builder/builder_update.go similarity index 100% rename from vendor/github.com/go-xorm/builder/builder_update.go rename to vendor/xorm.io/builder/builder_update.go diff --git a/vendor/github.com/go-xorm/builder/cond.go b/vendor/xorm.io/builder/cond.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond.go rename to vendor/xorm.io/builder/cond.go diff --git a/vendor/github.com/go-xorm/builder/cond_and.go b/vendor/xorm.io/builder/cond_and.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_and.go rename to vendor/xorm.io/builder/cond_and.go diff --git a/vendor/github.com/go-xorm/builder/cond_between.go b/vendor/xorm.io/builder/cond_between.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_between.go rename to vendor/xorm.io/builder/cond_between.go diff --git a/vendor/github.com/go-xorm/builder/cond_compare.go b/vendor/xorm.io/builder/cond_compare.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_compare.go rename to vendor/xorm.io/builder/cond_compare.go diff --git a/vendor/github.com/go-xorm/builder/cond_eq.go b/vendor/xorm.io/builder/cond_eq.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_eq.go rename to vendor/xorm.io/builder/cond_eq.go diff --git a/vendor/github.com/go-xorm/builder/cond_expr.go b/vendor/xorm.io/builder/cond_expr.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_expr.go rename to vendor/xorm.io/builder/cond_expr.go diff --git a/vendor/xorm.io/builder/cond_if.go b/vendor/xorm.io/builder/cond_if.go new file mode 100644 index 0000000000..af9eb321fd --- /dev/null +++ b/vendor/xorm.io/builder/cond_if.go @@ -0,0 +1,49 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package builder + +type condIf struct { + condition bool + condTrue Cond + condFalse Cond +} + +var _ Cond = condIf{} + +// If returns Cond via condition +func If(condition bool, condTrue Cond, condFalse ...Cond) Cond { + var c = condIf{ + condition: condition, + condTrue: condTrue, + } + if len(condFalse) > 0 { + c.condFalse = condFalse[0] + } + return c +} + +func (condIf condIf) WriteTo(w Writer) error { + if condIf.condition { + return condIf.condTrue.WriteTo(w) + } else if condIf.condFalse != nil { + return condIf.condFalse.WriteTo(w) + } + return nil +} + +func (condIf condIf) And(conds ...Cond) Cond { + return And(condIf, And(conds...)) +} + +func (condIf condIf) Or(conds ...Cond) Cond { + return Or(condIf, Or(conds...)) +} + +func (condIf condIf) IsValid() bool { + if condIf.condition { + return condIf.condTrue != nil + } + return condIf.condFalse != nil +} diff --git a/vendor/github.com/go-xorm/builder/cond_in.go b/vendor/xorm.io/builder/cond_in.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_in.go rename to vendor/xorm.io/builder/cond_in.go diff --git a/vendor/github.com/go-xorm/builder/cond_like.go b/vendor/xorm.io/builder/cond_like.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_like.go rename to vendor/xorm.io/builder/cond_like.go diff --git a/vendor/github.com/go-xorm/builder/cond_neq.go b/vendor/xorm.io/builder/cond_neq.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_neq.go rename to vendor/xorm.io/builder/cond_neq.go diff --git a/vendor/github.com/go-xorm/builder/cond_not.go b/vendor/xorm.io/builder/cond_not.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_not.go rename to vendor/xorm.io/builder/cond_not.go diff --git a/vendor/github.com/go-xorm/builder/cond_notin.go b/vendor/xorm.io/builder/cond_notin.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_notin.go rename to vendor/xorm.io/builder/cond_notin.go diff --git a/vendor/github.com/go-xorm/builder/cond_null.go b/vendor/xorm.io/builder/cond_null.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_null.go rename to vendor/xorm.io/builder/cond_null.go diff --git a/vendor/github.com/go-xorm/builder/cond_or.go b/vendor/xorm.io/builder/cond_or.go similarity index 100% rename from vendor/github.com/go-xorm/builder/cond_or.go rename to vendor/xorm.io/builder/cond_or.go diff --git a/vendor/github.com/go-xorm/builder/doc.go b/vendor/xorm.io/builder/doc.go similarity index 100% rename from vendor/github.com/go-xorm/builder/doc.go rename to vendor/xorm.io/builder/doc.go diff --git a/vendor/github.com/go-xorm/builder/error.go b/vendor/xorm.io/builder/error.go similarity index 100% rename from vendor/github.com/go-xorm/builder/error.go rename to vendor/xorm.io/builder/error.go diff --git a/vendor/xorm.io/builder/go.mod b/vendor/xorm.io/builder/go.mod new file mode 100644 index 0000000000..35e43b329f --- /dev/null +++ b/vendor/xorm.io/builder/go.mod @@ -0,0 +1,6 @@ +module xorm.io/builder + +require ( + github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a + github.com/stretchr/testify v1.3.0 +) diff --git a/vendor/xorm.io/builder/go.sum b/vendor/xorm.io/builder/go.sum new file mode 100644 index 0000000000..468ba4a2d5 --- /dev/null +++ b/vendor/xorm.io/builder/go.sum @@ -0,0 +1,9 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/go-xorm/builder/sql.go b/vendor/xorm.io/builder/sql.go similarity index 100% rename from vendor/github.com/go-xorm/builder/sql.go rename to vendor/xorm.io/builder/sql.go diff --git a/vendor/github.com/go-xorm/builder/string_builder.go b/vendor/xorm.io/builder/string_builder.go similarity index 100% rename from vendor/github.com/go-xorm/builder/string_builder.go rename to vendor/xorm.io/builder/string_builder.go diff --git a/vendor/github.com/go-xorm/core/.gitignore b/vendor/xorm.io/core/.gitignore similarity index 100% rename from vendor/github.com/go-xorm/core/.gitignore rename to vendor/xorm.io/core/.gitignore diff --git a/vendor/github.com/go-xorm/core/LICENSE b/vendor/xorm.io/core/LICENSE similarity index 100% rename from vendor/github.com/go-xorm/core/LICENSE rename to vendor/xorm.io/core/LICENSE diff --git a/vendor/github.com/go-xorm/core/README.md b/vendor/xorm.io/core/README.md similarity index 100% rename from vendor/github.com/go-xorm/core/README.md rename to vendor/xorm.io/core/README.md diff --git a/vendor/github.com/go-xorm/core/benchmark.sh b/vendor/xorm.io/core/benchmark.sh similarity index 100% rename from vendor/github.com/go-xorm/core/benchmark.sh rename to vendor/xorm.io/core/benchmark.sh diff --git a/vendor/github.com/go-xorm/core/cache.go b/vendor/xorm.io/core/cache.go similarity index 92% rename from vendor/github.com/go-xorm/core/cache.go rename to vendor/xorm.io/core/cache.go index 8f9531da94..dc4992dfb1 100644 --- a/vendor/github.com/go-xorm/core/cache.go +++ b/vendor/xorm.io/core/cache.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/vendor/github.com/go-xorm/core/column.go b/vendor/xorm.io/core/column.go similarity index 88% rename from vendor/github.com/go-xorm/core/column.go rename to vendor/xorm.io/core/column.go index 20912b713c..40d8f9268d 100644 --- a/vendor/github.com/go-xorm/core/column.go +++ b/vendor/xorm.io/core/column.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( @@ -41,6 +45,7 @@ type Column struct { Comment string } +// NewColumn creates a new column func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column { return &Column{ Name: name, @@ -66,7 +71,7 @@ func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable } } -// generate column description string according dialect +// String generate column description string according dialect func (col *Column) String(d Dialect) string { sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " @@ -94,6 +99,7 @@ func (col *Column) String(d Dialect) string { return sql } +// StringNoPk generate column description string according dialect without primary keys func (col *Column) StringNoPk(d Dialect) string { sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " @@ -114,12 +120,13 @@ func (col *Column) StringNoPk(d Dialect) string { return sql } -// return col's filed of struct's value +// ValueOf returns column's filed of struct's value func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) { dataStruct := reflect.Indirect(reflect.ValueOf(bean)) return col.ValueOfV(&dataStruct) } +// ValueOfV returns column's filed of struct's value accept reflevt value func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) { var fieldValue reflect.Value fieldPath := strings.Split(col.FieldName, ".") diff --git a/vendor/github.com/go-xorm/core/converstion.go b/vendor/xorm.io/core/converstion.go similarity index 59% rename from vendor/github.com/go-xorm/core/converstion.go rename to vendor/xorm.io/core/converstion.go index 18522fbeeb..9703c36e08 100644 --- a/vendor/github.com/go-xorm/core/converstion.go +++ b/vendor/xorm.io/core/converstion.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core // Conversion is an interface. A type implements Conversion will according diff --git a/vendor/xorm.io/core/db.go b/vendor/xorm.io/core/db.go new file mode 100644 index 0000000000..3e50a14795 --- /dev/null +++ b/vendor/xorm.io/core/db.go @@ -0,0 +1,223 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package core + +import ( + "context" + "database/sql" + "database/sql/driver" + "fmt" + "reflect" + "regexp" + "sync" +) + +var ( + DefaultCacheSize = 200 +) + +func MapToSlice(query string, mp interface{}) (string, []interface{}, error) { + vv := reflect.ValueOf(mp) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { + return "", []interface{}{}, ErrNoMapPointer + } + + args := make([]interface{}, 0, len(vv.Elem().MapKeys())) + var err error + query = re.ReplaceAllStringFunc(query, func(src string) string { + v := vv.Elem().MapIndex(reflect.ValueOf(src[1:])) + if !v.IsValid() { + err = fmt.Errorf("map key %s is missing", src[1:]) + } else { + args = append(args, v.Interface()) + } + return "?" + }) + + return query, args, err +} + +func StructToSlice(query string, st interface{}) (string, []interface{}, error) { + vv := reflect.ValueOf(st) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { + return "", []interface{}{}, ErrNoStructPointer + } + + args := make([]interface{}, 0) + var err error + query = re.ReplaceAllStringFunc(query, func(src string) string { + fv := vv.Elem().FieldByName(src[1:]).Interface() + if v, ok := fv.(driver.Valuer); ok { + var value driver.Value + value, err = v.Value() + if err != nil { + return "?" + } + args = append(args, value) + } else { + args = append(args, fv) + } + return "?" + }) + if err != nil { + return "", []interface{}{}, err + } + return query, args, nil +} + +type cacheStruct struct { + value reflect.Value + idx int +} + +// DB is a wrap of sql.DB with extra contents +type DB struct { + *sql.DB + Mapper IMapper + reflectCache map[reflect.Type]*cacheStruct + reflectCacheMutex sync.RWMutex +} + +// Open opens a database +func Open(driverName, dataSourceName string) (*DB, error) { + db, err := sql.Open(driverName, dataSourceName) + if err != nil { + return nil, err + } + return &DB{ + DB: db, + Mapper: NewCacheMapper(&SnakeMapper{}), + reflectCache: make(map[reflect.Type]*cacheStruct), + }, nil +} + +// FromDB creates a DB from a sql.DB +func FromDB(db *sql.DB) *DB { + return &DB{ + DB: db, + Mapper: NewCacheMapper(&SnakeMapper{}), + reflectCache: make(map[reflect.Type]*cacheStruct), + } +} + +func (db *DB) reflectNew(typ reflect.Type) reflect.Value { + db.reflectCacheMutex.Lock() + defer db.reflectCacheMutex.Unlock() + cs, ok := db.reflectCache[typ] + if !ok || cs.idx+1 > DefaultCacheSize-1 { + cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0} + db.reflectCache[typ] = cs + } else { + cs.idx = cs.idx + 1 + } + return cs.value.Index(cs.idx).Addr() +} + +// QueryContext overwrites sql.DB.QueryContext +func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { + rows, err := db.DB.QueryContext(ctx, query, args...) + if err != nil { + if rows != nil { + rows.Close() + } + return nil, err + } + return &Rows{rows, db}, nil +} + +// Query overwrites sql.DB.Query +func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { + return db.QueryContext(context.Background(), query, args...) +} + +func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) { + query, args, err := MapToSlice(query, mp) + if err != nil { + return nil, err + } + return db.QueryContext(ctx, query, args...) +} + +func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) { + return db.QueryMapContext(context.Background(), query, mp) +} + +func (db *DB) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) { + query, args, err := StructToSlice(query, st) + if err != nil { + return nil, err + } + return db.QueryContext(ctx, query, args...) +} + +func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) { + return db.QueryStructContext(context.Background(), query, st) +} + +func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row { + rows, err := db.QueryContext(ctx, query, args...) + if err != nil { + return &Row{nil, err} + } + return &Row{rows, nil} +} + +func (db *DB) QueryRow(query string, args ...interface{}) *Row { + return db.QueryRowContext(context.Background(), query, args...) +} + +func (db *DB) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row { + query, args, err := MapToSlice(query, mp) + if err != nil { + return &Row{nil, err} + } + return db.QueryRowContext(ctx, query, args...) +} + +func (db *DB) QueryRowMap(query string, mp interface{}) *Row { + return db.QueryRowMapContext(context.Background(), query, mp) +} + +func (db *DB) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row { + query, args, err := StructToSlice(query, st) + if err != nil { + return &Row{nil, err} + } + return db.QueryRowContext(ctx, query, args...) +} + +func (db *DB) QueryRowStruct(query string, st interface{}) *Row { + return db.QueryRowStructContext(context.Background(), query, st) +} + +var ( + re = regexp.MustCompile(`[?](\w+)`) +) + +// insert into (name) values (?) +// insert into (name) values (?name) +func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) { + query, args, err := MapToSlice(query, mp) + if err != nil { + return nil, err + } + return db.DB.ExecContext(ctx, query, args...) +} + +func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) { + return db.ExecMapContext(context.Background(), query, mp) +} + +func (db *DB) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) { + query, args, err := StructToSlice(query, st) + if err != nil { + return nil, err + } + return db.DB.ExecContext(ctx, query, args...) +} + +func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) { + return db.ExecStructContext(context.Background(), query, st) +} diff --git a/vendor/github.com/go-xorm/core/dialect.go b/vendor/xorm.io/core/dialect.go similarity index 97% rename from vendor/github.com/go-xorm/core/dialect.go rename to vendor/xorm.io/core/dialect.go index c288a08478..5d35a4f11d 100644 --- a/vendor/github.com/go-xorm/core/dialect.go +++ b/vendor/xorm.io/core/dialect.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/vendor/github.com/go-xorm/core/driver.go b/vendor/xorm.io/core/driver.go similarity index 75% rename from vendor/github.com/go-xorm/core/driver.go rename to vendor/xorm.io/core/driver.go index 0f1020b403..ceef4ba618 100644 --- a/vendor/github.com/go-xorm/core/driver.go +++ b/vendor/xorm.io/core/driver.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core type Driver interface { diff --git a/vendor/github.com/go-xorm/core/error.go b/vendor/xorm.io/core/error.go similarity index 51% rename from vendor/github.com/go-xorm/core/error.go rename to vendor/xorm.io/core/error.go index 640e6036e6..63ea53e466 100644 --- a/vendor/github.com/go-xorm/core/error.go +++ b/vendor/xorm.io/core/error.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import "errors" diff --git a/vendor/github.com/go-xorm/core/filter.go b/vendor/xorm.io/core/filter.go similarity index 90% rename from vendor/github.com/go-xorm/core/filter.go rename to vendor/xorm.io/core/filter.go index 35b0ece676..6aeed4244c 100644 --- a/vendor/github.com/go-xorm/core/filter.go +++ b/vendor/xorm.io/core/filter.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/vendor/xorm.io/core/go.mod b/vendor/xorm.io/core/go.mod new file mode 100644 index 0000000000..2703545e69 --- /dev/null +++ b/vendor/xorm.io/core/go.mod @@ -0,0 +1,7 @@ +module xorm.io/core + +require ( + github.com/go-sql-driver/mysql v1.4.1 + github.com/mattn/go-sqlite3 v1.10.0 + google.golang.org/appengine v1.4.0 // indirect +) diff --git a/vendor/xorm.io/core/go.sum b/vendor/xorm.io/core/go.sum new file mode 100644 index 0000000000..8f20f8bc90 --- /dev/null +++ b/vendor/xorm.io/core/go.sum @@ -0,0 +1,9 @@ +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/vendor/github.com/go-xorm/core/ilogger.go b/vendor/xorm.io/core/ilogger.go similarity index 78% rename from vendor/github.com/go-xorm/core/ilogger.go rename to vendor/xorm.io/core/ilogger.go index c8d7849605..348ab88f4f 100644 --- a/vendor/github.com/go-xorm/core/ilogger.go +++ b/vendor/xorm.io/core/ilogger.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core type LogLevel int diff --git a/vendor/github.com/go-xorm/core/index.go b/vendor/xorm.io/core/index.go similarity index 78% rename from vendor/github.com/go-xorm/core/index.go rename to vendor/xorm.io/core/index.go index 9aa1b7ac99..ac97b68505 100644 --- a/vendor/github.com/go-xorm/core/index.go +++ b/vendor/xorm.io/core/index.go @@ -1,8 +1,11 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( "fmt" - "sort" "strings" ) @@ -46,11 +49,16 @@ func (index *Index) Equal(dst *Index) bool { if len(index.Cols) != len(dst.Cols) { return false } - sort.StringSlice(index.Cols).Sort() - sort.StringSlice(dst.Cols).Sort() for i := 0; i < len(index.Cols); i++ { - if index.Cols[i] != dst.Cols[i] { + var found bool + for j := 0; j < len(dst.Cols); j++ { + if index.Cols[i] == dst.Cols[j] { + found = true + break + } + } + if !found { return false } } diff --git a/vendor/github.com/go-xorm/core/mapper.go b/vendor/xorm.io/core/mapper.go similarity index 96% rename from vendor/github.com/go-xorm/core/mapper.go rename to vendor/xorm.io/core/mapper.go index bb72a15662..ec44ea0db9 100644 --- a/vendor/github.com/go-xorm/core/mapper.go +++ b/vendor/xorm.io/core/mapper.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/vendor/github.com/go-xorm/core/pk.go b/vendor/xorm.io/core/pk.go similarity index 72% rename from vendor/github.com/go-xorm/core/pk.go rename to vendor/xorm.io/core/pk.go index 1810dd944b..05a7672d86 100644 --- a/vendor/github.com/go-xorm/core/pk.go +++ b/vendor/xorm.io/core/pk.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/vendor/github.com/go-xorm/core/rows.go b/vendor/xorm.io/core/rows.go similarity index 97% rename from vendor/github.com/go-xorm/core/rows.go rename to vendor/xorm.io/core/rows.go index 580de4f9c6..2b046d84cc 100644 --- a/vendor/github.com/go-xorm/core/rows.go +++ b/vendor/xorm.io/core/rows.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/vendor/github.com/go-xorm/core/scan.go b/vendor/xorm.io/core/scan.go similarity index 79% rename from vendor/github.com/go-xorm/core/scan.go rename to vendor/xorm.io/core/scan.go index b7c159b274..897b534159 100644 --- a/vendor/github.com/go-xorm/core/scan.go +++ b/vendor/xorm.io/core/scan.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( @@ -53,3 +57,10 @@ func convertTime(dest *NullTime, src interface{}) error { } return nil } + +type EmptyScanner struct { +} + +func (EmptyScanner) Scan(src interface{}) error { + return nil +} diff --git a/vendor/xorm.io/core/stmt.go b/vendor/xorm.io/core/stmt.go new file mode 100644 index 0000000000..20ee202b9b --- /dev/null +++ b/vendor/xorm.io/core/stmt.go @@ -0,0 +1,165 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package core + +import ( + "context" + "database/sql" + "errors" + "reflect" +) + +type Stmt struct { + *sql.Stmt + db *DB + names map[string]int +} + +func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) { + names := make(map[string]int) + var i int + query = re.ReplaceAllStringFunc(query, func(src string) string { + names[src[1:]] = i + i += 1 + return "?" + }) + + stmt, err := db.DB.PrepareContext(ctx, query) + if err != nil { + return nil, err + } + return &Stmt{stmt, db, names}, nil +} + +func (db *DB) Prepare(query string) (*Stmt, error) { + return db.PrepareContext(context.Background(), query) +} + +func (s *Stmt) ExecMapContext(ctx context.Context, mp interface{}) (sql.Result, error) { + vv := reflect.ValueOf(mp) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() + } + return s.Stmt.ExecContext(ctx, args...) +} + +func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) { + return s.ExecMapContext(context.Background(), mp) +} + +func (s *Stmt) ExecStructContext(ctx context.Context, st interface{}) (sql.Result, error) { + vv := reflect.ValueOf(st) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().FieldByName(k).Interface() + } + return s.Stmt.ExecContext(ctx, args...) +} + +func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) { + return s.ExecStructContext(context.Background(), st) +} + +func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) { + rows, err := s.Stmt.QueryContext(ctx, args...) + if err != nil { + return nil, err + } + return &Rows{rows, s.db}, nil +} + +func (s *Stmt) Query(args ...interface{}) (*Rows, error) { + return s.QueryContext(context.Background(), args...) +} + +func (s *Stmt) QueryMapContext(ctx context.Context, mp interface{}) (*Rows, error) { + vv := reflect.ValueOf(mp) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() + } + + return s.QueryContext(ctx, args...) +} + +func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) { + return s.QueryMapContext(context.Background(), mp) +} + +func (s *Stmt) QueryStructContext(ctx context.Context, st interface{}) (*Rows, error) { + vv := reflect.ValueOf(st) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().FieldByName(k).Interface() + } + + return s.Query(args...) +} + +func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) { + return s.QueryStructContext(context.Background(), st) +} + +func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row { + rows, err := s.QueryContext(ctx, args...) + return &Row{rows, err} +} + +func (s *Stmt) QueryRow(args ...interface{}) *Row { + return s.QueryRowContext(context.Background(), args...) +} + +func (s *Stmt) QueryRowMapContext(ctx context.Context, mp interface{}) *Row { + vv := reflect.ValueOf(mp) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { + return &Row{nil, errors.New("mp should be a map's pointer")} + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() + } + + return s.QueryRowContext(ctx, args...) +} + +func (s *Stmt) QueryRowMap(mp interface{}) *Row { + return s.QueryRowMapContext(context.Background(), mp) +} + +func (s *Stmt) QueryRowStructContext(ctx context.Context, st interface{}) *Row { + vv := reflect.ValueOf(st) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { + return &Row{nil, errors.New("st should be a struct's pointer")} + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().FieldByName(k).Interface() + } + + return s.QueryRowContext(ctx, args...) +} + +func (s *Stmt) QueryRowStruct(st interface{}) *Row { + return s.QueryRowStructContext(context.Background(), st) +} diff --git a/vendor/github.com/go-xorm/core/table.go b/vendor/xorm.io/core/table.go similarity index 95% rename from vendor/github.com/go-xorm/core/table.go rename to vendor/xorm.io/core/table.go index b5d079404c..d129e60f8b 100644 --- a/vendor/github.com/go-xorm/core/table.go +++ b/vendor/xorm.io/core/table.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/vendor/xorm.io/core/tx.go b/vendor/xorm.io/core/tx.go new file mode 100644 index 0000000000..a56b70063e --- /dev/null +++ b/vendor/xorm.io/core/tx.go @@ -0,0 +1,153 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package core + +import ( + "context" + "database/sql" +) + +type Tx struct { + *sql.Tx + db *DB +} + +func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { + tx, err := db.DB.BeginTx(ctx, opts) + if err != nil { + return nil, err + } + return &Tx{tx, db}, nil +} + +func (db *DB) Begin() (*Tx, error) { + tx, err := db.DB.Begin() + if err != nil { + return nil, err + } + return &Tx{tx, db}, nil +} + +func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) { + names := make(map[string]int) + var i int + query = re.ReplaceAllStringFunc(query, func(src string) string { + names[src[1:]] = i + i += 1 + return "?" + }) + + stmt, err := tx.Tx.PrepareContext(ctx, query) + if err != nil { + return nil, err + } + return &Stmt{stmt, tx.db, names}, nil +} + +func (tx *Tx) Prepare(query string) (*Stmt, error) { + return tx.PrepareContext(context.Background(), query) +} + +func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt { + stmt.Stmt = tx.Tx.StmtContext(ctx, stmt.Stmt) + return stmt +} + +func (tx *Tx) Stmt(stmt *Stmt) *Stmt { + return tx.StmtContext(context.Background(), stmt) +} + +func (tx *Tx) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) { + query, args, err := MapToSlice(query, mp) + if err != nil { + return nil, err + } + return tx.Tx.ExecContext(ctx, query, args...) +} + +func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) { + return tx.ExecMapContext(context.Background(), query, mp) +} + +func (tx *Tx) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) { + query, args, err := StructToSlice(query, st) + if err != nil { + return nil, err + } + return tx.Tx.ExecContext(ctx, query, args...) +} + +func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) { + return tx.ExecStructContext(context.Background(), query, st) +} + +func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { + rows, err := tx.Tx.QueryContext(ctx, query, args...) + if err != nil { + return nil, err + } + return &Rows{rows, tx.db}, nil +} + +func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { + return tx.QueryContext(context.Background(), query, args...) +} + +func (tx *Tx) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) { + query, args, err := MapToSlice(query, mp) + if err != nil { + return nil, err + } + return tx.QueryContext(ctx, query, args...) +} + +func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) { + return tx.QueryMapContext(context.Background(), query, mp) +} + +func (tx *Tx) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) { + query, args, err := StructToSlice(query, st) + if err != nil { + return nil, err + } + return tx.QueryContext(ctx, query, args...) +} + +func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) { + return tx.QueryStructContext(context.Background(), query, st) +} + +func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row { + rows, err := tx.QueryContext(ctx, query, args...) + return &Row{rows, err} +} + +func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { + return tx.QueryRowContext(context.Background(), query, args...) +} + +func (tx *Tx) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row { + query, args, err := MapToSlice(query, mp) + if err != nil { + return &Row{nil, err} + } + return tx.QueryRowContext(ctx, query, args...) +} + +func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row { + return tx.QueryRowMapContext(context.Background(), query, mp) +} + +func (tx *Tx) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row { + query, args, err := StructToSlice(query, st) + if err != nil { + return &Row{nil, err} + } + return tx.QueryRowContext(ctx, query, args...) +} + +func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row { + return tx.QueryRowStructContext(context.Background(), query, st) +} diff --git a/vendor/github.com/go-xorm/core/type.go b/vendor/xorm.io/core/type.go similarity index 92% rename from vendor/github.com/go-xorm/core/type.go rename to vendor/xorm.io/core/type.go index 5cbf930573..8164953602 100644 --- a/vendor/github.com/go-xorm/core/type.go +++ b/vendor/xorm.io/core/type.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( @@ -71,6 +75,7 @@ var ( Char = "CHAR" Varchar = "VARCHAR" + NChar = "NCHAR" NVarchar = "NVARCHAR" TinyText = "TINYTEXT" Text = "TEXT" @@ -84,12 +89,15 @@ var ( Date = "DATE" DateTime = "DATETIME" + SmallDateTime = "SMALLDATETIME" Time = "TIME" TimeStamp = "TIMESTAMP" TimeStampz = "TIMESTAMPZ" Decimal = "DECIMAL" Numeric = "NUMERIC" + Money = "MONEY" + SmallMoney = "SMALLMONEY" Real = "REAL" Float = "FLOAT" @@ -127,6 +135,7 @@ var ( Jsonb: TEXT_TYPE, Char: TEXT_TYPE, + NChar: TEXT_TYPE, Varchar: TEXT_TYPE, NVarchar: TEXT_TYPE, TinyText: TEXT_TYPE, @@ -143,12 +152,15 @@ var ( Time: TIME_TYPE, TimeStamp: TIME_TYPE, TimeStampz: TIME_TYPE, + SmallDateTime: TIME_TYPE, Decimal: NUMERIC_TYPE, Numeric: NUMERIC_TYPE, Real: NUMERIC_TYPE, Float: NUMERIC_TYPE, Double: NUMERIC_TYPE, + Money: NUMERIC_TYPE, + SmallMoney: NUMERIC_TYPE, Binary: BLOB_TYPE, VarBinary: BLOB_TYPE, @@ -295,15 +307,15 @@ func SQLType2Type(st SQLType) reflect.Type { return reflect.TypeOf(float32(1)) case Double: return reflect.TypeOf(float64(1)) - case Char, Varchar, NVarchar, TinyText, Text, NText, MediumText, LongText, Enum, Set, Uuid, Clob, SysName: + case Char, NChar, Varchar, NVarchar, TinyText, Text, NText, MediumText, LongText, Enum, Set, Uuid, Clob, SysName: return reflect.TypeOf("") case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary, UniqueIdentifier: return reflect.TypeOf([]byte{}) case Bool: return reflect.TypeOf(true) - case DateTime, Date, Time, TimeStamp, TimeStampz: + case DateTime, Date, Time, TimeStamp, TimeStampz, SmallDateTime: return reflect.TypeOf(c_TIME_DEFAULT) - case Decimal, Numeric: + case Decimal, Numeric, Money, SmallMoney: return reflect.TypeOf("") default: return reflect.TypeOf("") From e07ff2f89064db8fa5c78a2a27a69d93183d10a4 Mon Sep 17 00:00:00 2001 From: Marat Radchenko Date: Mon, 24 Jun 2019 08:33:57 +0300 Subject: [PATCH 141/220] [docker] Add LFS_START_SERVER option to control git-lfs support (#7281) --- docker/root/etc/s6/gitea/setup | 1 + docker/root/etc/templates/app.ini | 1 + docs/content/doc/installation/with-docker.en-us.md | 1 + 3 files changed, 3 insertions(+) diff --git a/docker/root/etc/s6/gitea/setup b/docker/root/etc/s6/gitea/setup index dec0ee2b55..c4fbf5d65e 100755 --- a/docker/root/etc/s6/gitea/setup +++ b/docker/root/etc/s6/gitea/setup @@ -31,6 +31,7 @@ if [ ! -f ${GITEA_CUSTOM}/conf/app.ini ]; then ROOT_URL=${ROOT_URL:-""} \ DISABLE_SSH=${DISABLE_SSH:-"false"} \ SSH_PORT=${SSH_PORT:-"22"} \ + LFS_START_SERVER=${LFS_START_SERVER:-"false"} \ DB_TYPE=${DB_TYPE:-"sqlite3"} \ DB_HOST=${DB_HOST:-"localhost:3306"} \ DB_NAME=${DB_NAME:-"gitea"} \ diff --git a/docker/root/etc/templates/app.ini b/docker/root/etc/templates/app.ini index 20cbb9053c..212cd854d3 100644 --- a/docker/root/etc/templates/app.ini +++ b/docker/root/etc/templates/app.ini @@ -17,6 +17,7 @@ HTTP_PORT = $HTTP_PORT ROOT_URL = $ROOT_URL DISABLE_SSH = $DISABLE_SSH SSH_PORT = $SSH_PORT +LFS_START_SERVER = $LFS_START_SERVER LFS_CONTENT_PATH = /data/git/lfs [database] diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md index d8adc4b3a0..a403d18778 100644 --- a/docs/content/doc/installation/with-docker.en-us.md +++ b/docs/content/doc/installation/with-docker.en-us.md @@ -248,6 +248,7 @@ You can configure some of Gitea's settings via environment variables: * `DISABLE_SSH`: **false**: Disable SSH feature when it's not available. * `HTTP_PORT`: **3000**: HTTP listen port. * `ROOT_URL`: **""**: Overwrite the automatically generated public URL. This is useful if the internal and the external URL don't match (e.g. in Docker). +* `LFS_START_SERVER`: **false**: Enables git-lfs support. * `DB_TYPE`: **sqlite3**: The database type in use \[mysql, postgres, mssql, sqlite3\]. * `DB_HOST`: **localhost:3306**: Database host address and port. * `DB_NAME`: **gitea**: Database name. From 5908bb103003912bd0ba3cefa66f2ff815ee8d8e Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 24 Jun 2019 21:23:52 +0100 Subject: [PATCH 142/220] Make diff line-marker non-selectable (#7279) * Make diff line-marker non-selectable * Move to use data-* as per @mrsdizzie * fix missing line nums * Add a minimum-width to force right-align of the line num * Move line-type-marker into separate column --- models/git_diff.go | 29 +++++++++++++----------- models/git_diff_test.go | 4 ++-- public/css/index.css | 13 +++++++---- public/less/_repository.less | 27 +++++++++++++++++++--- templates/repo/diff/box.tmpl | 17 ++++++++++---- templates/repo/diff/section_unified.tmpl | 12 ++++++---- 6 files changed, 70 insertions(+), 32 deletions(-) diff --git a/models/git_diff.go b/models/git_diff.go index a6ea7306d4..29c424c11c 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -80,6 +80,14 @@ func (d *DiffLine) GetCommentSide() string { return d.Comments[0].DiffSide() } +// GetLineTypeMarker returns the line type marker +func (d *DiffLine) GetLineTypeMarker() string { + if strings.IndexByte(" +-", d.Content[0]) > -1 { + return d.Content[0:1] + } + return "" +} + // DiffSection represents a section of a DiffFile. type DiffSection struct { Name string @@ -87,22 +95,14 @@ type DiffSection struct { } var ( - addedCodePrefix = []byte("") - removedCodePrefix = []byte("") - codeTagSuffix = []byte("") + addedCodePrefix = []byte(``) + removedCodePrefix = []byte(``) + codeTagSuffix = []byte(``) ) func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { buf := bytes.NewBuffer(nil) - // Reproduce signs which are cut for inline diff before. - switch lineType { - case DiffLineAdd: - buf.WriteByte('+') - case DiffLineDel: - buf.WriteByte('-') - } - for i := range diffs { switch { case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: @@ -186,18 +186,21 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem case DiffLineAdd: compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx) if compareDiffLine == nil { - return template.HTML(html.EscapeString(diffLine.Content)) + return template.HTML(html.EscapeString(diffLine.Content[1:])) } diff1 = compareDiffLine.Content diff2 = diffLine.Content case DiffLineDel: compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx) if compareDiffLine == nil { - return template.HTML(html.EscapeString(diffLine.Content)) + return template.HTML(html.EscapeString(diffLine.Content[1:])) } diff1 = diffLine.Content diff2 = compareDiffLine.Content default: + if strings.IndexByte(" +-", diffLine.Content[0]) > -1 { + return template.HTML(html.EscapeString(diffLine.Content[1:])) + } return template.HTML(html.EscapeString(diffLine.Content)) } diff --git a/models/git_diff_test.go b/models/git_diff_test.go index deca7c8d4a..bf52095acf 100644 --- a/models/git_diff_test.go +++ b/models/git_diff_test.go @@ -18,14 +18,14 @@ func assertEqual(t *testing.T, s1 string, s2 template.HTML) { } func TestDiffToHTML(t *testing.T) { - assertEqual(t, "+foo bar biz", diffToHTML([]dmp.Diff{ + assertEqual(t, "foo bar biz", diffToHTML([]dmp.Diff{ {Type: dmp.DiffEqual, Text: "foo "}, {Type: dmp.DiffInsert, Text: "bar"}, {Type: dmp.DiffDelete, Text: " baz"}, {Type: dmp.DiffEqual, Text: " biz"}, }, DiffLineAdd)) - assertEqual(t, "-foo bar biz", diffToHTML([]dmp.Diff{ + assertEqual(t, "foo bar biz", diffToHTML([]dmp.Diff{ {Type: dmp.DiffEqual, Text: "foo "}, {Type: dmp.DiffDelete, Text: "bar"}, {Type: dmp.DiffInsert, Text: " baz"}, diff --git a/public/css/index.css b/public/css/index.css index 24a5d7865c..475a54f75f 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -633,7 +633,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .diff-box .header .file{flex:1;color:#888;word-break:break-all} .repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto} .repository .diff-file-box .header{background-color:#f7f7f7} -.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#a6a6a6;background:#fafafa;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top} +.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#a6a6a6;background:#fafafa;width:1%;min-width:50px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top} .repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center} .repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #ddd} .repository .diff-file-box .code-diff{font-size:12px} @@ -644,13 +644,16 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} .repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99} .repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9} +.repository .diff-file-box .code-diff tbody tr .lines-num[data-line-num]::before{content:attr(data-line-num);text-align:right} +.repository .diff-file-box .code-diff tbody tr .lines-type-marker{width:10px;min-width:10px} +.repository .diff-file-box .code-diff tbody tr .line-type-marker[data-type-marker]::before{content:attr(data-type-marker);text-align:right;display:inline-block} .repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important} .repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important} .repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%} -.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#fafafa} -.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#ffe0e0!important;border-color:#f1c0c0!important} -.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#d6fcd6!important;border-color:#c1e9c1!important} -.repository .diff-file-box .code-diff-split tbody tr td:nth-child(3){border-left-width:1px;border-left-style:solid} +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#fafafa} +.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#ffe0e0!important;border-color:#f1c0c0!important} +.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#d6fcd6!important;border-color:#c1e9c1!important} +.repository .diff-file-box .code-diff-split tbody tr td:nth-child(4){border-left-width:1px;border-left-style:solid} .repository .diff-file-box.file-content{clear:right} .repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px} .repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden} diff --git a/public/less/_repository.less b/public/less/_repository.less index acf8d7b870..8d38faf50c 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -1339,6 +1339,7 @@ color: #a6a6a6; background: #fafafa; width: 1%; + min-width: 50px; user-select: none; vertical-align: top; @@ -1403,6 +1404,22 @@ .added-code { background-color: #99ff99; } + + .lines-num[data-line-num]::before { + content: attr(data-line-num); + text-align: right; + } + + .lines-type-marker { + width: 10px; + min-width: 10px; + } + + .line-type-marker[data-type-marker]::before { + content: attr(data-type-marker); + text-align: right; + display: inline-block; + } } } } @@ -1432,25 +1449,29 @@ &.add-code td:nth-child(1), &.add-code td:nth-child(2), &.del-code td:nth-child(3), - &.del-code td:nth-child(4) { + &.del-code td:nth-child(4), + &.del-code td:nth-child(5), + &.del-code td:nth-child(6) { background-color: #fafafa; } &.del-code td:nth-child(1), &.del-code td:nth-child(2), + &.del-code td:nth-child(3), td.del-code { background-color: #ffe0e0 !important; border-color: #f1c0c0 !important; } - &.add-code td:nth-child(3), &.add-code td:nth-child(4), + &.add-code td:nth-child(5), + &.add-code td:nth-child(6), td.add-code { background-color: #d6fcd6 !important; border-color: #c1e9c1 !important; } - td:nth-child(3) { + td:nth-child(4) { border-left-width: 1px; border-left-style: solid; } diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 2bdf9e5881..94ac094fa4 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -120,8 +120,11 @@ {{range $j, $section := $file.Sections}} {{range $k, $line := $section.Lines}}
    - + - + - + + {{else}} - - {{end}} + + ' - + (isSplit ? '' - : '') + + (isSplit ? '' + : '') + ''); tr.after(ntr); } diff --git a/public/less/_base.less b/public/less/_base.less index 13ae1ad665..213ae2d2e6 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -160,7 +160,8 @@ a { } pre, -code { +code, +.mono { font: 12px @monospaced-fonts, monospace; &.raw { diff --git a/public/less/_repository.less b/public/less/_repository.less index 8d38faf50c..681296b74d 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -1362,10 +1362,6 @@ border-top: 0; } - pre { - margin: 0; - } - .lines-num { border-color: #d4d4d5; border-right-width: 1px; @@ -1405,7 +1401,7 @@ background-color: #99ff99; } - .lines-num[data-line-num]::before { + [data-line-num]::before { content: attr(data-line-num); text-align: right; } @@ -1413,9 +1409,10 @@ .lines-type-marker { width: 10px; min-width: 10px; + user-select: none; } - .line-type-marker[data-type-marker]::before { + [data-type-marker]::before { content: attr(data-type-marker); text-align: right; display: inline-block; @@ -1448,7 +1445,7 @@ // light gray for empty lines before / after commit &.add-code td:nth-child(1), &.add-code td:nth-child(2), - &.del-code td:nth-child(3), + &.add-code td:nth-child(3), &.del-code td:nth-child(4), &.del-code td:nth-child(5), &.del-code td:nth-child(6) { diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index d2fe2982d7..463a979434 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -1115,12 +1115,15 @@ a.ui.labels .label:hover { .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), -.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4) { +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4), +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5), +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) { background-color: #2a2e3a; } -.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4), +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5), +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6), .repository .diff-file-box .code-diff-split tbody tr td.add-code { background-color: #283e2d !important; border-color: #314a37 !important; @@ -1128,6 +1131,7 @@ a.ui.labels .label:hover { .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2), +.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr td.del-code { background-color: #3c2626 !important; border-color: #634343 !important; diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 94ac094fa4..056b8aea20 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -120,30 +120,12 @@ {{range $j, $section := $file.Sections}} {{range $k, $line := $section.Lines}} - - - - - - + + + + + + {{if gt (len $line.Comments) 0}} @@ -230,17 +212,22 @@ document.addEventListener('DOMContentLoaded', function() { $('tr.add-code').each(function() { var prev = $(this).prev(); - if(prev.is('.del-code') && prev.children().eq(3).text().trim() === '') { - while(prev.prev().is('.del-code') && prev.prev().children().eq(3).text().trim() === '') { + if(prev.is('.del-code') && prev.children().eq(5).text().trim() === '') { + while(prev.prev().is('.del-code') && prev.prev().children().eq(5).text().trim() === '') { prev = prev.prev(); } - prev.children().eq(2).html($(this).children().eq(2).html()); + prev.children().eq(3).attr("data-line-num", $(this).children().eq(3).attr("data-line-num")); prev.children().eq(3).html($(this).children().eq(3).html()); + prev.children().eq(4).html($(this).children().eq(4).html()); + prev.children().eq(5).html($(this).children().eq(5).html()); prev.children().eq(0).addClass('del-code'); prev.children().eq(1).addClass('del-code'); - prev.children().eq(2).addClass('add-code'); + prev.children().eq(2).addClass('del-code'); prev.children().eq(3).addClass('add-code'); + prev.children().eq(4).addClass('add-code'); + prev.children().eq(5).addClass('add-code'); + $(this).remove(); } }); diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index 5706e4cdee..f33381a1a2 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -8,22 +8,11 @@ {{/* {{if gt $j 0}}{{end}} */}} {{else}} - - + + {{end}} - - + + {{if gt (len $line.Comments) 0}} From c37ec66ee25b95525b9c8dfddd5a6f9a798150fe Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 27 Jun 2019 08:36:37 +0200 Subject: [PATCH 147/220] replace lesshint with stylelint (#7305) New CSS linter which is much more powerfull than the previous one. Configuration is default but I had to remove a few rules that were throwing too many or weird errors. More importantly, the linter will exit with code 1 on errors so now our build will fail if the CSS linter fails which should eliminate linter errors being introduced without notice. --- .lesshintrc.json | 12 - .stylelintrc | 11 + Makefile | 2 +- package-lock.json | 1468 +++++++++++++++++++++++++++-- package.json | 3 +- public/css/index.css | 11 +- public/css/theme-arc-green.css | 28 +- public/less/_form.less | 2 - public/less/_markdown.less | 5 +- public/less/_repository.less | 2 +- public/less/_user.less | 37 +- public/less/themes/arc-green.less | 91 +- 12 files changed, 1441 insertions(+), 231 deletions(-) delete mode 100644 .lesshintrc.json create mode 100644 .stylelintrc diff --git a/.lesshintrc.json b/.lesshintrc.json deleted file mode 100644 index 55ea979673..0000000000 --- a/.lesshintrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "idSelector": false, - "importPath": false, - "importantRule": false, - "maxCharPerLine": false, - "propertyOrdering": false, - "qualifyingElement": false, - "spaceAroundComma": false, - "stringQuotes": "double", - "universalSelector": false, - "zeroUnit": "no_unit" -} diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 0000000000..a3eb6c3fb5 --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,11 @@ +extends: stylelint-config-standard + +rules: + block-closing-brace-empty-line-before: null + color-hex-length: null + comment-empty-line-before: null + declaration-empty-line-before: null + indentation: 4 + no-descending-specificity: null + rule-empty-line-before: null + selector-pseudo-element-colon-notation: null diff --git a/Makefile b/Makefile index 0ab014226b..be66cb3ef3 100644 --- a/Makefile +++ b/Makefile @@ -392,7 +392,7 @@ js: npm .PHONY: css css: npm - npx lesshint public/less/ + npx stylelint public/less npx lessc --clean-css="--s0 -b" public/less/index.less public/css/index.css $(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css="--s0 -b" public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;) npx postcss --use autoprefixer --no-map --replace public/css/* diff --git a/package-lock.json b/package-lock.json index 8fb0edcfb4..4b3e047693 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,97 @@ "@babel/highlight": "^7.0.0" } }, + "@babel/core": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", + "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helpers": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.5", + "@babel/types": "^7.4.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helpers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", + "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", + "dev": true, + "requires": { + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, "@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", @@ -22,6 +113,51 @@ "js-tokens": "^4.0.0" } }, + "@babel/parser": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", + "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", + "dev": true + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", + "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/types": "^7.4.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -67,6 +203,33 @@ "integrity": "sha512-b8bbUOTwzIY3V5vDTY1fIJ+ePKDUBqt2hC2woVGotdQQhG/2Sh62HOKHrT7ab+VerXAcPyAiTEipPu/FsreUtg==", "dev": true }, + "@types/unist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", + "dev": true + }, + "@types/vfile": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/vfile/-/vfile-3.0.2.tgz", + "integrity": "sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/unist": "*", + "@types/vfile-message": "*" + } + }, + "@types/vfile-message": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-1.0.1.tgz", + "integrity": "sha512-mlGER3Aqmq7bqR1tTTIVHq8KSAFFRyGbrxuM8C/H82g6k7r2fS+IMEkIu3D7JHzG10NvPdR8DNx0jr0pwpp4dA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/unist": "*" + } + }, "acorn": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", @@ -190,6 +353,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -301,6 +470,12 @@ "dev": true, "optional": true }, + "bail": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.4.tgz", + "integrity": "sha512-S8vuDB4w6YpRhICUDET3guPlQpaJl7od94tpZ0Fvnyp+MKW/HyDTcRDck+29C9g+d/qQHnddRH3+94kZdrW0Ww==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -534,6 +709,25 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + }, "caniuse-lite": { "version": "1.0.30000975", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000975.tgz", @@ -547,6 +741,12 @@ "dev": true, "optional": true }, + "ccount": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.4.tgz", + "integrity": "sha512-fpZ81yYfzentuieinmGnphk0pLkOTMm6MZdVqwd77ROvhko6iujLNGrHH5E7utq3ygWklwfmwuG+A7P+NpqT6w==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -558,6 +758,30 @@ "supports-color": "^5.3.0" } }, + "character-entities": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.3.tgz", + "integrity": "sha512-yB4oYSAa9yLcGyTbB4ItFwHw43QHdH129IJ5R+WvxOkWlyFnR5FAaBNnUq4mcxsTVZGh28bHoeTHMKXH1wZf3w==", + "dev": true + }, + "character-entities-html4": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.3.tgz", + "integrity": "sha512-SwnyZ7jQBCRHELk9zf2CN5AnGEc2nA+uKMZLHvcqhpPprjkYhiLn0DywMHgN5ttFZuITMATbh68M6VIVKwJbcg==", + "dev": true + }, + "character-entities-legacy": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.3.tgz", + "integrity": "sha512-YAxUpPoPwxYFsslbdKkhrGnXAtXoHNgYjlBM3WMXkWGTl5RsY3QmOyhwAgL8Nxm9l5LBThXGawxKPn68y6/fww==", + "dev": true + }, + "character-reference-invalid": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.3.tgz", + "integrity": "sha512-VOq6PRzQBam/8Jm6XBGk2fNEnHXAdGd6go0rtd4weAGECBamHDwwCQSOT12TACIYUZegUXnV6xBXqUssijtxIg==", + "dev": true + }, "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -666,12 +890,27 @@ "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", "dev": true }, + "clone-regexp": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", + "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==", + "dev": true, + "requires": { + "is-regexp": "^2.0.0" + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "collapse-white-space": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.5.tgz", + "integrity": "sha512-703bOOmytCYAX9cXYqoikYIx6twmFCXsnzRQheBcTG3nzKYBR4P/+wkYeH+Mvj7qUz8zZDtdyzbxfnEi/kYzRQ==", + "dev": true + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -750,6 +989,15 @@ "proto-list": "~1.2.1" } }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", @@ -819,11 +1067,14 @@ "which": "^1.2.9" } }, - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } }, "cyclist": { "version": "0.2.2", @@ -856,6 +1107,24 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -928,16 +1197,6 @@ "integrity": "sha512-DCvzSq2UiMsuLnj/9AL484ummEgLtZIcRS7YvtO38QnpX3vqh9nJ8P+zhu8Ja+SmLrBHO2iDbva20jq38qvBkQ==", "dev": true }, - "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - } - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -947,6 +1206,50 @@ "esutils": "^2.0.2" } }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -1000,6 +1303,12 @@ "once": "^1.4.0" } }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, "err-code": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", @@ -1174,6 +1483,15 @@ "strip-eof": "^1.0.0" } }, + "execall": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", + "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", + "dev": true, + "requires": { + "clone-regexp": "^2.1.0" + } + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -1228,8 +1546,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "optional": true + "dev": true }, "extend-shallow": { "version": "3.0.2", @@ -1440,12 +1757,6 @@ "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", "dev": true }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", - "dev": true - }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", @@ -2161,31 +2472,51 @@ "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", "dev": true }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, - "globby": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=", + "dev": true + }, + "gonzales-pe": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.4.tgz", + "integrity": "sha512-v0Ts/8IsSbh9n1OJRnSfa7Nlxi4AkXIsWB6vPept8FDbL4bXn3FNuxjYtO/nmBGu7GDkL9MFeGebeSu6l55EPQ==", "dev": true, "requires": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "minimist": "1.1.x" }, "dependencies": { - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "minimist": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", + "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=", "dev": true } } @@ -2264,6 +2595,39 @@ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, + "html-tags": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.0.0.tgz", + "integrity": "sha512-xiXEBjihaNI+VZ2mKEoI5ZPxqUsevTKM+aeeJ/W4KAg2deGE35minmCJMn51BvwJZmiHaeAxrb2LAS0yZJxuuA==", + "dev": true + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", @@ -2403,12 +2767,24 @@ } } }, + "import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", @@ -2507,6 +2883,28 @@ } } }, + "is-alphabetical": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.3.tgz", + "integrity": "sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA==", + "dev": true + }, + "is-alphanumeric": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", + "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.3.tgz", + "integrity": "sha512-A1IGAPO5AW9vSh7omxIlOGwIqEvpW/TA+DksVOPM5ODuxKlZS09+TEM1E3275lJqO2oJ38vDpeAL3DCIiHE6eA==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -2548,6 +2946,12 @@ } } }, + "is-decimal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.3.tgz", + "integrity": "sha512-bvLSwoDg2q6Gf+E2LEPiklHZxxiSi3XAh4Mav65mKqTfCO1HM3uBs24TjEH8iJX3bbDdLXKJXBTmGzuTUuAEjQ==", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -2600,6 +3004,12 @@ "is-extglob": "^2.1.1" } }, + "is-hexadecimal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.3.tgz", + "integrity": "sha512-zxQ9//Q3D/34poZf8fiy3m3XVpbQc7ren15iKqrTtLPwkPD/t3Scy9Imp63FujULGxuK0ZlCwoo5xNpktFgbOA==", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -2620,6 +3030,18 @@ } } }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -2635,6 +3057,12 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-regexp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz", + "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==", + "dev": true + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -2648,12 +3076,24 @@ "dev": true, "optional": true }, + "is-whitespace-character": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.3.tgz", + "integrity": "sha512-SNPgMLz9JzPccD3nPctcj8sZlX9DAMJSKH8bP7Z6bohCwuNgX8xbWr1eTAYXX9Vpi/aSn8Y1akL9WgM3t43YNQ==", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, + "is-word-character": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.3.tgz", + "integrity": "sha512-0wfcrFgOOOBdgRNT9H33xe6Zi6yhX/uoc4U8NBZGeQQB0ctU1dnlNTyL9JM2646bHDTpsDm1Brb3VPoCIMrd/A==", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2702,6 +3142,12 @@ "dev": true, "optional": true }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -2734,6 +3180,23 @@ "dev": true, "optional": true }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -2762,6 +3225,12 @@ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, + "known-css-properties": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.14.0.tgz", + "integrity": "sha512-P+0a/gBzLgVlCnK8I7VcD0yuYJscmWn66wH9tlKsQnmVdg689tLEmziwB9PuazZYLkcm07fvWOKCJJqI55sD5Q==", + "dev": true + }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", @@ -2797,23 +3266,11 @@ "clean-css": "^3.0.1" } }, - "lesshint": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/lesshint/-/lesshint-6.3.6.tgz", - "integrity": "sha512-yFUAwNAMkUzKRO0qa6d0N1xXW66RFuipFB3VVICwQB6aIyh9y11wUpcMp6e3adL46+0aGJIkDW6z12c+bWaLgA==", - "dev": true, - "requires": { - "commander": "^2.8.0", - "cosmiconfig": "^5.0.1", - "globby": "^8.0.0", - "lodash.merge": "^4.0.1", - "lodash.orderby": "^4.6.0", - "postcss": "^7.0.14", - "postcss-less": "^3.1.1", - "postcss-selector-parser": "^5.0.0", - "postcss-values-parser": "^2.0.0", - "strip-json-comments": "^2.0.0" - } + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true }, "levn": { "version": "0.3.0", @@ -2825,6 +3282,18 @@ "type-check": "~0.3.2" } }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -2841,18 +3310,6 @@ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, - "lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", - "dev": true - }, - "lodash.orderby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.orderby/-/lodash.orderby-4.6.0.tgz", - "integrity": "sha1-5pfwTOXXhSL1TZM4syuBozk+TrM=", - "dev": true - }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -2862,6 +3319,22 @@ "chalk": "^2.0.1" } }, + "longest-streak": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.3.tgz", + "integrity": "sha512-9lz5IVdpwsKLMzQi0MQ+oD9EA0mIGcWYP7jXMTZVXP8D42PwuAk+M/HBFYQoxt1G5OR8m7aSIgb1UymfWGBWEw==", + "dev": true + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -2914,6 +3387,12 @@ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -2923,6 +3402,33 @@ "object-visit": "^1.0.0" } }, + "markdown-escapes": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.3.tgz", + "integrity": "sha512-XUi5HJhhV5R74k8/0H2oCbCiYf/u4cO/rX8tnGkRvrqhsr5BRNU6Mg0yt/8UIx1iIS8220BNJsDb7XnILhLepw==", + "dev": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "mathml-tag-names": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.1.tgz", + "integrity": "sha512-pWB896KPGSGkp1XtyzRBftpTzwSOL0Gfk0wLvxt4f2mgzjY19o0LxJ3U25vNWTzsh7da+KTbuXQoQ3lOJZ8WHw==", + "dev": true + }, + "mdast-util-compact": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.3.tgz", + "integrity": "sha512-nRiU5GpNy62rZppDKbLwhhtw5DXoFMqw9UNZFmlPsNaQCZ//WLjGKUwWMdJrUH+Se7UvtO2gXtAMe0g/N+eI5w==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -2942,6 +3448,40 @@ } } }, + "meow": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, "merge2": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", @@ -3014,6 +3554,16 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -3146,6 +3696,18 @@ "semver": "^5.3.0" } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3158,6 +3720,12 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, + "normalize-selector": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz", + "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", + "dev": true + }, "npm-conf": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", @@ -3356,6 +3924,20 @@ "callsites": "^3.0.0" } }, + "parse-entities": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", + "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", + "dev": true, + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -3402,6 +3984,12 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", @@ -3418,6 +4006,12 @@ "dev": true, "optional": true }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "dev": true + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -3511,6 +4105,24 @@ } } }, + "postcss-html": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz", + "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==", + "dev": true, + "requires": { + "htmlparser2": "^3.10.0" + } + }, + "postcss-jsx": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/postcss-jsx/-/postcss-jsx-0.36.1.tgz", + "integrity": "sha512-xaZpy01YR7ijsFUtu5rViYCFHurFIPHir+faiOQp8g/NfTfWqZCKDhKrydQZ4d8WlSAmVdXGwLjpFbsNUI26Sw==", + "dev": true, + "requires": { + "@babel/core": ">=7.2.2" + } + }, "postcss-less": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz", @@ -3530,6 +4142,22 @@ "import-cwd": "^2.0.0" } }, + "postcss-markdown": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/postcss-markdown/-/postcss-markdown-0.36.0.tgz", + "integrity": "sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ==", + "dev": true, + "requires": { + "remark": "^10.0.1", + "unist-util-find-all-after": "^1.0.2" + } + }, + "postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=", + "dev": true + }, "postcss-reporter": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz", @@ -3542,34 +4170,52 @@ "postcss": "^7.0.7" } }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "postcss-resolve-nested-selector": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", + "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=", + "dev": true + }, + "postcss-safe-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", + "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", "dev": true, "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "postcss": "^7.0.0" } }, + "postcss-sass": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.3.5.tgz", + "integrity": "sha512-B5z2Kob4xBxFjcufFnhQ2HqJQ2y/Zs/ic5EZbCywCkxKd756Q40cIQ/veRDwSrw1BF6+4wUgmpm0sBASqVi65A==", + "dev": true, + "requires": { + "gonzales-pe": "^4.2.3", + "postcss": "^7.0.1" + } + }, + "postcss-scss": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.0.0.tgz", + "integrity": "sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-syntax": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", + "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==", + "dev": true + }, "postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, - "postcss-values-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", - "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", - "dev": true, - "requires": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -3692,6 +4338,12 @@ "dev": true, "optional": true }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -3729,6 +4381,72 @@ } } }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -3755,6 +4473,16 @@ "readable-stream": "^2.0.2" } }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -3781,6 +4509,62 @@ "safe-buffer": "^5.0.1" } }, + "remark": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-10.0.1.tgz", + "integrity": "sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ==", + "dev": true, + "requires": { + "remark-parse": "^6.0.0", + "remark-stringify": "^6.0.0", + "unified": "^7.0.0" + } + }, + "remark-parse": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-6.0.3.tgz", + "integrity": "sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg==", + "dev": true, + "requires": { + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^1.1.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^1.0.0", + "vfile-location": "^2.0.0", + "xtend": "^4.0.1" + } + }, + "remark-stringify": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-6.0.4.tgz", + "integrity": "sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg==", + "dev": true, + "requires": { + "ccount": "^1.0.0", + "is-alphanumeric": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "longest-streak": "^2.0.1", + "markdown-escapes": "^1.0.0", + "markdown-table": "^1.1.0", + "mdast-util-compact": "^1.0.0", + "parse-entities": "^1.0.2", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "stringify-entities": "^1.0.1", + "unherit": "^1.0.4", + "xtend": "^4.0.1" + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -3799,6 +4583,12 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -3840,6 +4630,15 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, + "resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3987,12 +4786,6 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -4194,6 +4987,44 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "dev": true + }, + "specificity": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz", + "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==", + "dev": true + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -4236,6 +5067,12 @@ "figgy-pudding": "^3.5.1" } }, + "state-toggle": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.2.tgz", + "integrity": "sha512-8LpelPGR0qQM4PnfLiplOQNJcIN1/r2Gy0xKB2zKnIW2YzPMt2sR4I/+gtPjhN7Svh9kw+zqEg2SFwpBO9iNiw==", + "dev": true + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -4292,6 +5129,18 @@ "safe-buffer": "~5.1.0" } }, + "stringify-entities": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz", + "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", + "dev": true, + "requires": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -4301,18 +5150,288 @@ "ansi-regex": "^3.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, + "style-search": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", + "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=", + "dev": true + }, + "stylelint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-10.1.0.tgz", + "integrity": "sha512-OmlUXrgzEMLQYj1JPTpyZPR9G4bl0StidfHnGJEMpdiQ0JyTq0MPg1xkHk1/xVJ2rTPESyJCDWjG8Kbpoo7Kuw==", + "dev": true, + "requires": { + "autoprefixer": "^9.5.1", + "balanced-match": "^1.0.0", + "chalk": "^2.4.2", + "cosmiconfig": "^5.2.0", + "debug": "^4.1.1", + "execall": "^2.0.0", + "file-entry-cache": "^5.0.1", + "get-stdin": "^7.0.0", + "global-modules": "^2.0.0", + "globby": "^9.2.0", + "globjoin": "^0.1.4", + "html-tags": "^3.0.0", + "ignore": "^5.0.6", + "import-lazy": "^4.0.0", + "imurmurhash": "^0.1.4", + "known-css-properties": "^0.14.0", + "leven": "^3.1.0", + "lodash": "^4.17.11", + "log-symbols": "^3.0.0", + "mathml-tag-names": "^2.1.0", + "meow": "^5.0.0", + "micromatch": "^4.0.0", + "normalize-selector": "^0.2.0", + "pify": "^4.0.1", + "postcss": "^7.0.14", + "postcss-html": "^0.36.0", + "postcss-jsx": "^0.36.1", + "postcss-less": "^3.1.4", + "postcss-markdown": "^0.36.0", + "postcss-media-query-parser": "^0.2.3", + "postcss-reporter": "^6.0.1", + "postcss-resolve-nested-selector": "^0.1.1", + "postcss-safe-parser": "^4.0.1", + "postcss-sass": "^0.3.5", + "postcss-scss": "^2.0.0", + "postcss-selector-parser": "^3.1.0", + "postcss-syntax": "^0.36.2", + "postcss-value-parser": "^3.3.1", + "resolve-from": "^5.0.0", + "signal-exit": "^3.0.2", + "slash": "^3.0.0", + "specificity": "^0.4.1", + "string-width": "^4.1.0", + "strip-ansi": "^5.2.0", + "style-search": "^0.1.0", + "sugarss": "^2.0.0", + "svg-tags": "^1.0.0", + "table": "^5.2.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "ignore": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.2.tgz", + "integrity": "sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "stylelint-config-recommended": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-2.2.0.tgz", + "integrity": "sha512-bZ+d4RiNEfmoR74KZtCKmsABdBJr4iXRiCso+6LtMJPw5rd/KnxUWTxht7TbafrTJK1YRjNgnN0iVZaJfc3xJA==", + "dev": true + }, + "stylelint-config-standard": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-18.3.0.tgz", + "integrity": "sha512-Tdc/TFeddjjy64LvjPau9SsfVRexmTFqUhnMBrzz07J4p2dVQtmpncRF/o8yZn8ugA3Ut43E6o1GtjX80TFytw==", + "dev": true, + "requires": { + "stylelint-config-recommended": "^2.2.0" + } + }, + "sugarss": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", + "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4322,6 +5441,12 @@ "has-flag": "^3.0.0" } }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, "table": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz", @@ -4393,6 +5518,12 @@ "os-tmpdir": "~1.0.2" } }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -4455,6 +5586,36 @@ } } }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", + "dev": true + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "trim-trailing-lines": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.2.tgz", + "integrity": "sha512-MUjYItdrqqj2zpcHFTkMa9WAv4JHTI6gnRQGPFLrt5L9a6tRMiDnIqYl8JBvu2d2Tc3lWJKQwlGCp0K8AvCM+Q==", + "dev": true + }, + "trough": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.4.tgz", + "integrity": "sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==", + "dev": true + }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", @@ -4493,6 +5654,32 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "unherit": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.2.tgz", + "integrity": "sha512-W3tMnpaMG7ZY6xe/moK04U9fBhi6wEiCYHUW5Mop/wQHf12+79EQGwxYejNdhEz2mkqkBlGwm7pxmgBKMVUj0w==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "xtend": "^4.0.1" + } + }, + "unified": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-7.1.0.tgz", + "integrity": "sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "@types/vfile": "^3.0.0", + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^1.1.0", + "trough": "^1.0.0", + "vfile": "^3.0.0", + "x-is-string": "^0.1.0" + } + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -4552,6 +5739,54 @@ "imurmurhash": "^0.1.4" } }, + "unist-util-find-all-after": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-1.0.4.tgz", + "integrity": "sha512-CaxvMjTd+yF93BKLJvZnEfqdM7fgEACsIpQqz8vIj9CJnUb9VpyymFS3tg6TCtgrF7vfCJBF5jbT2Ox9CBRYRQ==", + "dev": true, + "requires": { + "unist-util-is": "^3.0.0" + } + }, + "unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", + "dev": true + }, + "unist-util-remove-position": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.3.tgz", + "integrity": "sha512-CtszTlOjP2sBGYc2zcKA/CvNdTdEs3ozbiJ63IPBxh8iZg42SCCb8m04f8z2+V1aSk5a7BxbZKEdoDjadmBkWA==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "unist-util-stringify-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", + "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==", + "dev": true + }, + "unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "dev": true, + "requires": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "dev": true, + "requires": { + "unist-util-is": "^3.0.0" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -4742,6 +5977,16 @@ "dev": true, "optional": true }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -4754,6 +5999,41 @@ "extsprintf": "^1.2.0" } }, + "vfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-3.0.1.tgz", + "integrity": "sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==", + "dev": true, + "requires": { + "is-buffer": "^2.0.0", + "replace-ext": "1.0.0", + "unist-util-stringify-position": "^1.0.0", + "vfile-message": "^1.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + } + } + }, + "vfile-location": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.5.tgz", + "integrity": "sha512-Pa1ey0OzYBkLPxPZI3d9E+S4BmvfVwNAAXrrqGbwTVXWaX2p9kM1zZ+n35UtVM06shmWKH4RPRN8KI80qE3wNQ==", + "dev": true + }, + "vfile-message": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", + "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "dev": true, + "requires": { + "unist-util-stringify-position": "^1.1.1" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -4837,6 +6117,12 @@ "mkdirp": "^0.5.1" } }, + "x-is-string": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", + "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index 5d352c5ca2..b046430e41 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "eslint": "5.16.0", "less": "3.9.0", "less-plugin-clean-css": "1.5.1", - "lesshint": "6.3.6", "postcss-cli": "6.1.2", + "stylelint": "10.1.0", + "stylelint-config-standard": "18.3.0", "updates": "8.1.0" }, "browserslist": [ diff --git a/public/css/index.css b/public/css/index.css index 5e2c7908e9..2bf2f96181 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -235,7 +235,6 @@ footer .ui.left,footer .ui.right{line-height:40px} .markdown:not(code) h6{font-size:1em;color:#777} .markdown:not(code) h6 .anchor{line-height:1.1} .markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px} -.markdown:not(code) blockquote{margin-left:0} .markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0} .markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em} .markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none} @@ -245,7 +244,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .markdown:not(code) dl{padding:0} .markdown:not(code) dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700} .markdown:not(code) dl dd{padding:0 16px;margin-bottom:16px} -.markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd} +.markdown:not(code) blockquote{margin-left:0;padding:0 15px;color:#777;border-left:4px solid #ddd} .markdown:not(code) blockquote>:first-child{margin-top:0} .markdown:not(code) blockquote>:last-child{margin-bottom:0} .markdown:not(code) table{width:auto;overflow:auto;word-break:keep-all;display:block} @@ -888,14 +887,14 @@ tbody.commit-list{vertical-align:baseline} .user.followers .header.name{font-size:20px;line-height:24px;vertical-align:middle} .user.followers .follow .ui.button{padding:8px 15px} .user.notification .octicon{float:left;font-size:2em} -.user.notification .content{float:left;margin-left:7px} -.user.notification table form{display:inline-block} -.user.notification table button{padding:3px 3px 3px 5px} -.user.notification table tr{cursor:pointer} .user.notification .octicon.green{color:#21ba45} .user.notification .octicon.red{color:#d01919} .user.notification .octicon.purple{color:#a333c8} .user.notification .octicon.blue{color:#2185d0} +.user.notification .content{float:left;margin-left:7px} +.user.notification table form{display:inline-block} +.user.notification table button{padding:3px 3px 3px 5px} +.user.notification table tr{cursor:pointer} .user.link-account:not(.icon){padding-top:15px;padding-bottom:5px} .user.settings .iconFloat{float:left} .user-orgs{display:flex;flex-flow:row wrap;padding:0;margin:-3px!important} diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index f61fd2c96e..f165ea8c84 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -28,12 +28,11 @@ a:hover{color:#a0cc75} .repository .milestone.list>.item .operate>a:hover{color:#a0cc75} .ui.green.progress .bar{background-color:#684} .ui.progress.success .bar{background-color:#7b9e57!important} -.following.bar.light{background:#2e323e} +.following.bar.light{background:#2e323e;border-bottom:1px solid #313131} .ui.secondary.menu .active.item{color:#dbdbdb} .ui.secondary.menu .item{color:#9e9e9e} .following.bar .top.menu a.item:hover{color:#fff} .repository.view.issue .comment-list .comment .content>.bottom.segment a{border:solid 1px #353945;background-color:#353945} -.following.bar.light{border-bottom:1px solid #313131} .ui.attached.header{background:#404552;border:1px solid #404552;color:#dbdbdb} .ui.attached.table{border:1px solid #304251;background:#304251} .feeds .list ul li:not(:last-child){border-bottom:1px solid #333640} @@ -112,7 +111,7 @@ footer{background:#2e323e;border-top:1px solid #313131} .ui.attached.segment{border:1px solid #404552} .repository.view.issue .comment-list .comment .content>.bottom.segment{background:#353945} .repository.view.issue .comment-list .comment .content .header{color:#dbdbdb;background-color:#404552;border-bottom:1px solid #353944} -.ui .text.grey a{color:#b3b3b3!important} +.ui .text.grey a{color:#dbdbdb!important} .ui.comments .comment .actions a{color:#dbdbdb} .repository.view.issue .comment-list .comment .content .header:after{border-right-color:#404552} .repository.new.issue .comment.form .content:after{border-right-color:#353945} @@ -121,10 +120,9 @@ footer{background:#2e323e;border-top:1px solid #313131} .repository.view.issue .comment-list:before{background-color:#313c47} .repository .comment.form .content .form:after{border-right-color:#313c47} .repository .comment.form .content .form:before{border-right-color:#313c47} -.ui .text.grey a{color:#dbdbdb!important} .ui .text.grey a:hover{color:#dbdbdb!important} .ui.basic.green.active.button,.ui.basic.green.buttons .active.button{color:#13ae38!important} -.ui.form textarea,.ui.form textarea:focus{background:#1a2632;border:1px solid #313c47;color:#dbdbdb} +.ui.form textarea,.ui.form textarea:focus{color:#dbdbdb;background:#404552;border:2px solid #353945} .ui.form textarea:focus{border:1px solid #456580} .ui .info.segment.top{background-color:#404552!important} .repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#3c2626!important;border-color:#634343!important} @@ -134,7 +132,7 @@ footer{background:#2e323e;border-top:1px solid #313131} .repository .diff-file-box .file-body.file-code .lines-num{color:#9e9e9e;background:#2e323e} .repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #2d2d2d} .hljs-section,.hljs-selector-id,.hljs-title{color:#986c88} -.hljs-doctag,.hljs-string{color:#949494} +.hljs-doctag,.hljs-string{color:#8ab398} .repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#5f3737} .repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#292727!important} .ui.vertical.menu .active.item{background:#4b5162} @@ -154,7 +152,7 @@ footer{background:#2e323e;border-top:1px solid #313131} .ui .text.black{color:#9e9e9e} .ui .text.black:hover{color:#dbdbdb} .ui.secondary.segment{background:#353945} -.ui.secondary.pointing.menu .active.item{border-color:#87ab63;color:#dbdbdb;background:#404552} +.ui.secondary.pointing.menu .active.item{color:#dbdbdb;border:0;background:#383c4a} .ui.user.list .item:not(:first-child){border-top:1px solid #4c505c} .ui.secondary.pointing.menu .active.item:hover{border-color:#af8b4c;color:#dbdbdb;background:#4b5162} .ui.secondary.pointing.menu .dropdown.item:hover,.ui.secondary.pointing.menu .link.item:hover,.ui.secondary.pointing.menu a.item:hover{color:#dbdbdb} @@ -166,7 +164,6 @@ footer{background:#2e323e;border-top:1px solid #313131} @media only screen and (max-width:1200px){.ui.menu.new-menu:after{background-image:linear-gradient(to right,rgba(42,46,42,0),#2a2e2a 100%)} } input{background:#2e323e} -.ui.secondary.pointing.menu .active.item{border:0;background:#383c4a} .settings .key.list .item:not(:first-child){border-top:1px solid #404552} .ui.attached.info.message,.ui.info.message{box-shadow:0 0 0 1px #4b5e71 inset,0 0 0 0 transparent} .ui.bottom.attached.message{background-color:#2c662d;color:#87ab63} @@ -179,14 +176,12 @@ input{background:#2e323e} .ui.red.button:hover,.ui.red.buttons .button:hover{background-color:#984646} .ui.checkbox label:hover,.ui.checkbox+label:hover{color:#dbdbdb!important} .ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{color:#7f98ad} -.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{background:#304251} +.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{background:#304251;opacity:1;color:#7f98ad;border-color:#304251} .ui.checkbox .box:hover::before,.ui.checkbox label:hover::before{background:#304251} .ui.checkbox .box:before,.ui.checkbox label:before{background:#304251;border:1px solid #304251} .ui.checkbox .box:active::before,.ui.checkbox label:active::before{background:#304251;border-color:rgba(34,36,38,.35)} -.ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{border-color:#304251;background:#304251} .ui.checkbox input:focus~.box:before,.ui.checkbox input:focus~label:before{border-color:#304251;background:#304251} .ui.checkbox input:checked:focus~.box:before,.ui.checkbox input:checked:focus~label:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:before{border-color:#304251;background:#304251} -.ui.checkbox input:checked~.box:after,.ui.checkbox input:checked~label:after{opacity:1;color:#7f98ad} .ui.checkbox input:checked:focus~.box:after,.ui.checkbox input:checked:focus~label:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:after,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:after{color:#7f98ad} .ui.checkbox input:focus~.box:after,.ui.checkbox input:focus~label,.ui.checkbox input:focus~label:after{color:#9a9a9a} .ui.selection.dropdown:hover{border:1px solid #456580} @@ -195,9 +190,7 @@ input{background:#2e323e} .ui.negative.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent} .hljs-attribute,.hljs-name,.hljs-tag{color:#ef5e77} .user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #4c505c} -.ui.form textarea,.ui.form textarea:focus{background:#404552;border:2px solid #353945} .hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:#bd84bf} -.hljs-doctag,.hljs-string{color:#8ab398} .ui.form .dropzone{border:2px dashed #4c505c} .ui.basic.red.button,.ui.basic.red.buttons .button{box-shadow:0 0 0 1px #a04141 inset!important;color:#a04141!important} .ui.list .list>.item .header,.ui.list>.item .header{color:#dedede} @@ -205,21 +198,17 @@ input{background:#2e323e} .ui.user.list .item .description a{color:#668cb1} .repository.file.list #file-content .code-view .lines-num{background:#2e323e} .repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e} -.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#87ab63} +.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#a27558} .ui.basic.blue.button:hover,.ui.basic.blue.buttons .button:hover{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} .ui.basic.blue.button:focus,.ui.basic.blue.buttons .button:focus{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} .repository.file.list #file-content .code-view .lines-code .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb} .repository .label.list .item{border-bottom:1px dashed #4c505c} -.repository.file.list #file-content .code-view .lines-num{background:#2e323e} -.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule{color:#7c9b5e} -.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #a27558 inset!important;color:#a27558!important} +.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} .repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} -a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb} .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a} .repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important} .repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important} -.ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#a27558} .ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558} #git-graph-container li a{color:#c79575} #git-graph-container li .author{color:#c79575} @@ -228,7 +217,6 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb .ui.modal>.header{background:#404552;color:#dbdbdb} .ui.modal>.actions{background:#404552;border-top:1px solid #404552} .ui.modal>.content{background:#383c4a} -.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} .editor-toolbar{background-color:#404552} .editor-toolbar a{color:#87ab63!important} .CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:0} diff --git a/public/less/_form.less b/public/less/_form.less index 419b16ecb4..c1a4f80c10 100644 --- a/public/less/_form.less +++ b/public/less/_form.less @@ -211,9 +211,7 @@ margin-left: 25px; } } -} -.new.webhook { .events.fields { .column { padding-left: 40px; diff --git a/public/less/_markdown.less b/public/less/_markdown.less index af46d6a3b2..e971248f6f 100644 --- a/public/less/_markdown.less +++ b/public/less/_markdown.less @@ -173,10 +173,6 @@ margin-bottom: 16px; } - blockquote { - margin-left: 0; - } - hr { height: 4px; padding: 0; @@ -231,6 +227,7 @@ } blockquote { + margin-left: 0; padding: 0 15px; color: #777777; border-left: 4px solid #dddddd; diff --git a/public/less/_repository.less b/public/less/_repository.less index 681296b74d..a8b2e22569 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -1217,7 +1217,7 @@ .detail.icon { background: #fafafa; - margin: -6px -10px -4px 0px; + margin: -6px -10px -4px 0; padding: 5px 3px 5px 6px; border-left: 1px solid #bbbbbb; border-top-left-radius: 0; diff --git a/public/less/_user.less b/public/less/_user.less index 695f780fd6..52c59464d8 100644 --- a/public/less/_user.less +++ b/public/less/_user.less @@ -24,7 +24,8 @@ border-bottom: 1px solid #eaeaea; } - .octicon, .fa { + .octicon, + .fa { margin-left: 1px; margin-right: 5px; } @@ -82,6 +83,22 @@ .octicon { float: left; font-size: 2em; + + &.green { + color: #21ba45; + } + + &.red { + color: #d01919; + } + + &.purple { + color: #a333c8; + } + + &.blue { + color: #2185d0; + } } .content { @@ -102,24 +119,6 @@ cursor: pointer; } } - - .octicon { - &.green { - color: #21ba45; - } - - &.red { - color: #d01919; - } - - &.purple { - color: #a333c8; - } - - &.blue { - color: #2185d0; - } - } } &.link-account:not(.icon) { diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index 463a979434..e4f3095154 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -152,6 +152,7 @@ a:hover { .following.bar.light { background: #2e323e; + border-bottom: 1px solid #313131; } .ui.secondary.menu .active.item { @@ -171,10 +172,6 @@ a:hover { background-color: #353945; } -.following.bar.light { - border-bottom: 1px solid #313131; -} - .ui.attached.header { background: #404552; border: 1px solid #404552; @@ -519,9 +516,9 @@ a.ui.basic.green.label:hover { .repository.file.editor.edit, .repository.wiki.new .CodeMirror { - border-right: 1px solid rgba(187,187,187, 0.6); - border-left: 1px solid rgba(187,187,187, 0.6); - border-bottom: 1px solid rgba(187,187,187, 0.6); + border-right: 1px solid rgba(187, 187, 187, 0.6); + border-left: 1px solid rgba(187, 187, 187, 0.6); + border-bottom: 1px solid rgba(187, 187, 187, 0.6); .editor-preview, .editor-preview-side { @@ -594,7 +591,7 @@ a.ui.basic.green.label:hover { } .ui .text.grey a { - color: #b3b3b3 !important; + color: #dbdbdb !important; } .ui.comments .comment .actions a { @@ -629,10 +626,6 @@ a.ui.basic.green.label:hover { border-right-color: #313c47; } -.ui .text.grey a { - color: #dbdbdb !important; -} - .ui .text.grey a:hover { color: #dbdbdb !important; } @@ -644,9 +637,9 @@ a.ui.basic.green.label:hover { .ui.form textarea, .ui.form textarea:focus { - background: #1a2632; - border: 1px solid #313c47; color: #dbdbdb; + background: #404552; + border: 2px solid #353945; } .ui.form textarea:focus { @@ -692,7 +685,7 @@ a.ui.basic.green.label:hover { .hljs-string, .hljs-doctag { - color: #949494; + color: #8ab398; } .repository .diff-file-box .code-diff tbody tr .removed-code { @@ -784,9 +777,9 @@ a.ui.basic.green.label:hover { } .ui.secondary.pointing.menu .active.item { - border-color: #87ab63; color: #dbdbdb; - background: #404552; + border: 0; + background: #383c4a; } .ui.user.list .item:not(:first-child) { @@ -829,6 +822,7 @@ a.ui.basic.green.label:hover { .ui.menu.new-menu { background-color: #2a2e3a !important; + @media only screen and (max-width: 1200px) { &:after { background-image: linear-gradient(to right, rgba(42, 46, 42, 0), rgba(42, 46, 42, 1) 100%); @@ -840,11 +834,6 @@ input { background: #2e323e; } -.ui.secondary.pointing.menu .active.item { - border: 0; - background: #383c4a; -} - .settings .key.list .item:not(:first-child) { border-top: 1px solid #404552; } @@ -906,6 +895,9 @@ input { .ui.checkbox input:checked ~ .box:before, .ui.checkbox input:checked ~ label:before { background: #304251; + opacity: 1; + color: #7f98ad; + border-color: #304251; } .ui.checkbox .box:hover::before, @@ -925,12 +917,6 @@ input { border-color: rgba(34, 36, 38, 0.35); } -.ui.checkbox input:checked ~ .box:before, -.ui.checkbox input:checked ~ label:before { - border-color: #304251; - background: #304251; -} - .ui.checkbox input:focus ~ .box:before, .ui.checkbox input:focus ~ label:before { border-color: #304251; @@ -945,12 +931,6 @@ input { background: #304251; } -.ui.checkbox input:checked ~ .box:after, -.ui.checkbox input:checked ~ label:after { - opacity: 1; - color: #7f98ad; -} - .ui.checkbox input:checked:focus ~ .box:after, .ui.checkbox input:checked:focus ~ label:after, .ui.checkbox input:not([type="radio"]):indeterminate:focus ~ .box:after, @@ -992,12 +972,6 @@ input { border-bottom: 1px solid #4c505c; } -.ui.form textarea, -.ui.form textarea:focus { - background: #404552; - border: 2px solid #353945; -} - .hljs-number, .hljs-literal, .hljs-variable, @@ -1006,11 +980,6 @@ input { color: #bd84bf; } -.hljs-string, -.hljs-doctag { - color: #8ab398; -} - .ui.form .dropzone { border: 2px dashed #4c505c; } @@ -1046,7 +1015,7 @@ input { .ui.blue.button:focus, .ui.blue.buttons .button:focus { - background-color: #87ab63; + background-color: #a27558; } .ui.basic.blue.button:hover, @@ -1080,19 +1049,10 @@ a.ui.labels .label:hover { border-bottom: 1px dashed #4c505c; } -.repository.file.list #file-content .code-view .lines-num { - background: #2e323e; -} - -.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory, -.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule { - color: #7c9b5e; -} - .ui.basic.blue.button, .ui.basic.blue.buttons .button { - box-shadow: 0 0 0 1px #a27558 inset !important; - color: #a27558 !important; + box-shadow: 0 0 0 1px #87ab63 inset !important; + color: #87ab63 !important; } .repository.file.list #file-content .code-view { @@ -1106,12 +1066,6 @@ a.ui.labels .label:hover { } } -a.ui.label:hover, -a.ui.labels .label:hover { - background-color: #505667; - color: #dbdbdb; -} - .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), @@ -1137,11 +1091,6 @@ a.ui.labels .label:hover { border-color: #634343 !important; } -.ui.blue.button:focus, -.ui.blue.buttons .button:focus { - background-color: #a27558; -} - .ui.blue.button:active, .ui.blue.buttons .button:active { background-color: #a27558; @@ -1177,12 +1126,6 @@ a.ui.labels .label:hover { background: #383c4a; } -.ui.basic.blue.button, -.ui.basic.blue.buttons .button { - box-shadow: 0 0 0 1px #87ab63 inset !important; - color: #87ab63 !important; -} - .editor-toolbar { background-color: #404552; From 7c0f2b9843f67ec49ea0038692648a531138a055 Mon Sep 17 00:00:00 2001 From: Mario Lubenka Date: Thu, 27 Jun 2019 16:15:30 +0200 Subject: [PATCH 148/220] Show Pull Request button or status of latest PR in branch list (#6990) * Show Pull Request button or status of latest PR in branch list Signed-off-by: Mario Lubenka * Do not show pull request button on deleted branches Signed-off-by: Mario Lubenka * Do not show commit divergence on deleted branches Signed-off-by: Mario Lubenka * Use XORMs Get instead of limit * Links pull request ID and use smaller labels for displaying the pull request status Signed-off-by: Mario Lubenka * Handle error when getting latest pull request Signed-off-by: Mario Lubenka * Indent template Signed-off-by: Mario Lubenka * Check error when loading issue Signed-off-by: Mario Lubenka --- models/pull.go | 14 ++++++++++++ routers/repo/branch.go | 38 ++++++++++++++++++++++----------- templates/repo/branch/list.tmpl | 25 ++++++++++++++++++++-- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/models/pull.go b/models/pull.go index 2f5412651b..eac36235bb 100644 --- a/models/pull.go +++ b/models/pull.go @@ -776,6 +776,20 @@ func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequ Find(&prs) } +// GetLatestPullRequestByHeadInfo returns the latest pull request (regardless of its status) +// by given head information (repo and branch). +func GetLatestPullRequestByHeadInfo(repoID int64, branch string) (*PullRequest, error) { + pr := new(PullRequest) + has, err := x. + Where("head_repo_id = ? AND head_branch = ?", repoID, branch). + OrderBy("id DESC"). + Get(pr) + if !has { + return nil, err + } + return pr, err +} + // GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged // by given base information (repo and branch). func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) { diff --git a/routers/repo/branch.go b/routers/repo/branch.go index 05d64fb4c8..708b33be09 100644 --- a/routers/repo/branch.go +++ b/routers/repo/branch.go @@ -24,13 +24,14 @@ const ( // Branch contains the branch information type Branch struct { - Name string - Commit *git.Commit - IsProtected bool - IsDeleted bool - DeletedBranch *models.DeletedBranch - CommitsAhead int - CommitsBehind int + Name string + Commit *git.Commit + IsProtected bool + IsDeleted bool + DeletedBranch *models.DeletedBranch + CommitsAhead int + CommitsBehind int + LatestPullRequest *models.PullRequest } // Branches render repository branch page @@ -181,12 +182,25 @@ func loadBranches(ctx *context.Context) []*Branch { return nil } + pr, err := models.GetLatestPullRequestByHeadInfo(ctx.Repo.Repository.ID, branchName) + if err != nil { + ctx.ServerError("GetLatestPullRequestByHeadInfo", err) + return nil + } + if pr != nil { + if err := pr.LoadIssue(); err != nil { + ctx.ServerError("pr.LoadIssue", err) + return nil + } + } + branches[i] = &Branch{ - Name: branchName, - Commit: commit, - IsProtected: isProtected, - CommitsAhead: divergence.Ahead, - CommitsBehind: divergence.Behind, + Name: branchName, + Commit: commit, + IsProtected: isProtected, + CommitsAhead: divergence.Ahead, + CommitsBehind: divergence.Behind, + LatestPullRequest: pr, } } diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index 58e77f2c11..a2fb5c2069 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -26,7 +26,8 @@
    @@ -27,12 +27,13 @@ {{end}} - {{.LatestCommit.Summary}} + {{template "repo/commit_status" .LatestCommitStatus}} + {{.LatestCommit.Summary}} {{if IsMultilineCommitMessage .LatestCommit.Message}} {{end}} - {{template "repo/commit_status" .LatestCommitStatus}} + {{if .LatestCommit.Author}}{{TimeSince .LatestCommit.Author.When $.Lang}}{{end}}
    - {{$commit.Summary}} + {{$commit.Summary}} {{TimeSince $commit.Committer.When $.Lang}}
    - {{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}} + + + +
    {{if $line.LeftIdx}}{{end}}
    {{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}} @@ -129,10 +132,12 @@ {{end}}
    {{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}
    - {{if $line.RightIdx}}{{$line.RightIdx}}{{end}} + + + +
    {{if $line.RightIdx}}{{end}}
    {{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}} + @@ -143,6 +148,7 @@ {{if gt (len $line.Comments) 0}}
    {{if eq $line.GetCommentSide "previous"}}
    @@ -156,6 +162,7 @@ {{end}}
    {{if eq $line.GetCommentSide "proposed"}}
    diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index 53ccaedbc2..5706e4cdee 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -8,13 +8,16 @@ {{/* {{if gt $j 0}}{{end}} */}}
    - {{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}} + + - {{if $line.RightIdx}}{{$line.RightIdx}}{{end}} + + +
    +
    {{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles}} + @@ -25,6 +28,7 @@ {{if gt (len $line.Comments) 0}}
    From 42729b7562cfcdd7fe554a381c48360ca63c6932 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 26 Jun 2019 16:51:32 +0800 Subject: [PATCH 143/220] fix API link header (#7298) --- modules/context/api.go | 41 ++++++++++++++++++++++++----- modules/context/api_test.go | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 modules/context/api_test.go diff --git a/modules/context/api.go b/modules/context/api.go index 9be3fb512c..0b2f81fd64 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -7,6 +7,7 @@ package context import ( "fmt" + "net/url" "strings" "github.com/go-macaron/csrf" @@ -77,23 +78,49 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) { }) } -// SetLinkHeader sets pagination link header by given total number and page size. -func (ctx *APIContext) SetLinkHeader(total, pageSize int) { - page := NewPagination(total, pageSize, ctx.QueryInt("page"), 0) +func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string { + page := NewPagination(total, pageSize, curPage, 0) paginater := page.Paginater links := make([]string, 0, 4) + if paginater.HasNext() { - links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"next\"", setting.AppURL, ctx.Req.URL.Path[1:], paginater.Next())) + u := *curURL + queries := u.Query() + queries.Set("page", fmt.Sprintf("%d", paginater.Next())) + u.RawQuery = queries.Encode() + + links = append(links, fmt.Sprintf("<%s%s>; rel=\"next\"", setting.AppURL, u.RequestURI()[1:])) } if !paginater.IsLast() { - links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"last\"", setting.AppURL, ctx.Req.URL.Path[1:], paginater.TotalPages())) + u := *curURL + queries := u.Query() + queries.Set("page", fmt.Sprintf("%d", paginater.TotalPages())) + u.RawQuery = queries.Encode() + + links = append(links, fmt.Sprintf("<%s%s>; rel=\"last\"", setting.AppURL, u.RequestURI()[1:])) } if !paginater.IsFirst() { - links = append(links, fmt.Sprintf("<%s%s?page=1>; rel=\"first\"", setting.AppURL, ctx.Req.URL.Path[1:])) + u := *curURL + queries := u.Query() + queries.Set("page", "1") + u.RawQuery = queries.Encode() + + links = append(links, fmt.Sprintf("<%s%s>; rel=\"first\"", setting.AppURL, u.RequestURI()[1:])) } if paginater.HasPrevious() { - links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"prev\"", setting.AppURL, ctx.Req.URL.Path[1:], paginater.Previous())) + u := *curURL + queries := u.Query() + queries.Set("page", fmt.Sprintf("%d", paginater.Previous())) + u.RawQuery = queries.Encode() + + links = append(links, fmt.Sprintf("<%s%s>; rel=\"prev\"", setting.AppURL, u.RequestURI()[1:])) } + return links +} + +// SetLinkHeader sets pagination link header by given total number and page size. +func (ctx *APIContext) SetLinkHeader(total, pageSize int) { + links := genAPILinks(ctx.Req.URL, total, pageSize, ctx.QueryInt("page")) if len(links) > 0 { ctx.Header().Set("Link", strings.Join(links, ",")) diff --git a/modules/context/api_test.go b/modules/context/api_test.go new file mode 100644 index 0000000000..e7e3e230af --- /dev/null +++ b/modules/context/api_test.go @@ -0,0 +1,51 @@ +// Copyright 2019 The Gitea 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 context + +import ( + "net/url" + "strconv" + "testing" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestGenAPILinks(t *testing.T) { + setting.AppURL = "http://localhost:3000/" + var kases = map[string][]string{ + "api/v1/repos/jerrykan/example-repo/issues?state=all": { + `; rel="next"`, + `; rel="last"`, + }, + "api/v1/repos/jerrykan/example-repo/issues?state=all&page=1": { + `; rel="next"`, + `; rel="last"`, + }, + "api/v1/repos/jerrykan/example-repo/issues?state=all&page=2": { + `; rel="next"`, + `; rel="last"`, + `; rel="first"`, + `; rel="prev"`, + }, + "api/v1/repos/jerrykan/example-repo/issues?state=all&page=5": { + `; rel="first"`, + `; rel="prev"`, + }, + } + + for req, response := range kases { + u, err := url.Parse(setting.AppURL + req) + assert.NoError(t, err) + + p := u.Query().Get("page") + curPage, _ := strconv.Atoi(p) + + links := genAPILinks(u, 100, 20, curPage) + + assert.EqualValues(t, links, response) + } +} From 161e12e157a48f9bcd2de50c187c77444aa2a9a8 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 27 Jun 2019 00:12:38 +0800 Subject: [PATCH 144/220] Shadow the password on cache and session config on admin panel (#7300) * shadow the password on cache and session config on admin panel * add shadow password of mysql/postgres/couchbase * fix log import --- routers/admin/admin.go | 68 ++++++++++++++++++++++++++++++++++-- routers/admin/admin_test.go | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 routers/admin/admin_test.go diff --git a/routers/admin/admin.go b/routers/admin/admin.go index 2836b7ddc7..370f816525 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -1,4 +1,5 @@ // Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -6,6 +7,7 @@ package admin import ( "fmt" + "net/url" "os" "runtime" "strings" @@ -19,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/cron" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" ) @@ -202,6 +205,63 @@ func SendTestMail(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + "/admin/config") } +func shadownPasswordKV(cfgItem, splitter string) string { + fields := strings.Split(cfgItem, splitter) + for i := 0; i < len(fields); i++ { + if strings.HasPrefix(fields[i], "password=") { + fields[i] = "password=******" + break + } + } + return strings.Join(fields, splitter) +} + +func shadownURL(provider, cfgItem string) string { + u, err := url.Parse(cfgItem) + if err != nil { + log.Error("shodowPassword %v failed: %v", provider, err) + return cfgItem + } + if u.User != nil { + atIdx := strings.Index(cfgItem, "@") + if atIdx > 0 { + colonIdx := strings.LastIndex(cfgItem[:atIdx], ":") + if colonIdx > 0 { + return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:] + } + } + } + return cfgItem +} + +func shadowPassword(provider, cfgItem string) string { + switch provider { + case "redis": + return shadownPasswordKV(cfgItem, ",") + case "mysql": + //root:@tcp(localhost:3306)/macaron?charset=utf8 + atIdx := strings.Index(cfgItem, "@") + if atIdx > 0 { + colonIdx := strings.Index(cfgItem[:atIdx], ":") + if colonIdx > 0 { + return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:] + } + } + return cfgItem + case "postgres": + // user=jiahuachen dbname=macaron port=5432 sslmode=disable + if !strings.HasPrefix(cfgItem, "postgres://") { + return shadownPasswordKV(cfgItem, " ") + } + + // postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full + // Notice: use shadwonURL + } + + // "couchbase" + return shadownURL(provider, cfgItem) +} + // Config show admin config page func Config(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.config") @@ -239,10 +299,14 @@ func Config(ctx *context.Context) { ctx.Data["CacheAdapter"] = setting.CacheService.Adapter ctx.Data["CacheInterval"] = setting.CacheService.Interval - ctx.Data["CacheConn"] = setting.CacheService.Conn + + ctx.Data["CacheConn"] = shadowPassword(setting.CacheService.Adapter, setting.CacheService.Conn) ctx.Data["CacheItemTTL"] = setting.CacheService.TTL - ctx.Data["SessionConfig"] = setting.SessionConfig + sessionCfg := setting.SessionConfig + sessionCfg.ProviderConfig = shadowPassword(sessionCfg.Provider, sessionCfg.ProviderConfig) + + ctx.Data["SessionConfig"] = sessionCfg ctx.Data["DisableGravatar"] = setting.DisableGravatar ctx.Data["EnableFederatedAvatar"] = setting.EnableFederatedAvatar diff --git a/routers/admin/admin_test.go b/routers/admin/admin_test.go new file mode 100644 index 0000000000..da404e50d7 --- /dev/null +++ b/routers/admin/admin_test.go @@ -0,0 +1,69 @@ +// Copyright 2019 The Gitea 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 admin + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestShadowPassword(t *testing.T) { + var kases = []struct { + Provider string + CfgItem string + Result string + }{ + { + Provider: "redis", + CfgItem: "network=tcp,addr=:6379,password=gitea,db=0,pool_size=100,idle_timeout=180", + Result: "network=tcp,addr=:6379,password=******,db=0,pool_size=100,idle_timeout=180", + }, + { + Provider: "mysql", + CfgItem: "root:@tcp(localhost:3306)/gitea?charset=utf8", + Result: "root:******@tcp(localhost:3306)/gitea?charset=utf8", + }, + { + Provider: "mysql", + CfgItem: "/gitea?charset=utf8", + Result: "/gitea?charset=utf8", + }, + { + Provider: "mysql", + CfgItem: "user:mypassword@/dbname", + Result: "user:******@/dbname", + }, + { + Provider: "postgres", + CfgItem: "user=pqgotest dbname=pqgotest sslmode=verify-full", + Result: "user=pqgotest dbname=pqgotest sslmode=verify-full", + }, + { + Provider: "postgres", + CfgItem: "user=pqgotest password= dbname=pqgotest sslmode=verify-full", + Result: "user=pqgotest password=****** dbname=pqgotest sslmode=verify-full", + }, + { + Provider: "postgres", + CfgItem: "postgres://user:pass@hostname/dbname", + Result: "postgres://user:******@hostname/dbname", + }, + { + Provider: "couchbase", + CfgItem: "http://dev-couchbase.example.com:8091/", + Result: "http://dev-couchbase.example.com:8091/", + }, + { + Provider: "couchbase", + CfgItem: "http://user:the_password@dev-couchbase.example.com:8091/", + Result: "http://user:******@dev-couchbase.example.com:8091/", + }, + } + + for _, k := range kases { + assert.EqualValues(t, k.Result, shadowPassword(k.Provider, k.CfgItem)) + } +} From edc94c70413048107ea728ff330f32ca3de6df88 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 27 Jun 2019 02:15:26 +0800 Subject: [PATCH 145/220] Monitor all git commands; move blame to git package and replace git as a variable (#6864) * monitor all git commands; move blame to git package and replace git as a variable * use git command but not other commands * fix build * move exec.Command to git.NewCommand * fix fmt * remove unrelated changes * remove unrelated changes * refactor IsEmpty and add tests * fix tests * fix tests * fix tests * fix tests * remove gitLogger * fix fmt * fix isEmpty * fix lint * fix tests --- contrib/pr/checkout.go | 6 +- models/git_diff.go | 16 +- models/pull.go | 8 +- models/release.go | 2 +- models/repo.go | 34 ++-- models/repo_mirror.go | 4 +- models/update.go | 6 +- models/git_blame.go => modules/git/blame.go | 7 +- .../git/blame_test.go | 2 +- modules/git/command.go | 5 + modules/git/repo.go | 14 ++ modules/git/repo_test.go | 10 ++ modules/git/tests/repos/repo2_empty/HEAD | 1 + modules/git/tests/repos/repo2_empty/config | 6 + .../git/tests/repos/repo2_empty/description | 1 + .../repo2_empty/hooks/applypatch-msg.sample | 15 ++ .../repos/repo2_empty/hooks/commit-msg.sample | 24 +++ .../hooks/fsmonitor-watchman.sample | 114 ++++++++++++ .../repo2_empty/hooks/post-update.sample | 8 + .../repo2_empty/hooks/pre-applypatch.sample | 14 ++ .../repos/repo2_empty/hooks/pre-commit.sample | 49 +++++ .../repos/repo2_empty/hooks/pre-push.sample | 53 ++++++ .../repos/repo2_empty/hooks/pre-rebase.sample | 169 ++++++++++++++++++ .../repo2_empty/hooks/pre-receive.sample | 24 +++ .../hooks/prepare-commit-msg.sample | 42 +++++ .../repos/repo2_empty/hooks/update.sample | 128 +++++++++++++ .../git/tests/repos/repo2_empty/info/exclude | 6 + .../repos/repo2_empty/objects/info/.gitkeep | 0 .../repos/repo2_empty/objects/pack/.gitkeep | 0 .../repos/repo2_empty/refs/heads/.gitkeep | 0 .../repos/repo2_empty/refs/tags/.gitkeep | 0 modules/repofiles/temp_repo.go | 24 +-- routers/repo/blame.go | 6 +- routers/repo/http.go | 26 +-- 34 files changed, 750 insertions(+), 74 deletions(-) rename models/git_blame.go => modules/git/blame.go (93%) rename models/git_blame_test.go => modules/git/blame_test.go (99%) create mode 100644 modules/git/tests/repos/repo2_empty/HEAD create mode 100644 modules/git/tests/repos/repo2_empty/config create mode 100644 modules/git/tests/repos/repo2_empty/description create mode 100755 modules/git/tests/repos/repo2_empty/hooks/applypatch-msg.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/commit-msg.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/fsmonitor-watchman.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/post-update.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/pre-applypatch.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/pre-commit.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/pre-push.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/pre-rebase.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/pre-receive.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/prepare-commit-msg.sample create mode 100755 modules/git/tests/repos/repo2_empty/hooks/update.sample create mode 100644 modules/git/tests/repos/repo2_empty/info/exclude create mode 100644 modules/git/tests/repos/repo2_empty/objects/info/.gitkeep create mode 100644 modules/git/tests/repos/repo2_empty/objects/pack/.gitkeep create mode 100644 modules/git/tests/repos/repo2_empty/refs/heads/.gitkeep create mode 100644 modules/git/tests/repos/repo2_empty/refs/tags/.gitkeep diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index a837cb5812..4b39c8e9f2 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -20,10 +20,13 @@ import ( "strconv" "time" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/routes" + "github.com/Unknwon/com" "github.com/go-xorm/xorm" context2 "github.com/gorilla/context" @@ -31,9 +34,6 @@ import ( "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/testfixtures.v2" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/setting" ) var codeFilePath = "contrib/pr/checkout.go" diff --git a/models/git_diff.go b/models/git_diff.go index 29c424c11c..bc79a73a4e 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -675,7 +675,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID var cmd *exec.Cmd if len(beforeCommitID) == 0 && commit.ParentCount() == 0 { - cmd = exec.Command("git", "show", afterCommitID) + cmd = exec.Command(git.GitExecutable, "show", afterCommitID) } else { actualBeforeCommitID := beforeCommitID if len(actualBeforeCommitID) == 0 { @@ -688,7 +688,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID } diffArgs = append(diffArgs, actualBeforeCommitID) diffArgs = append(diffArgs, afterCommitID) - cmd = exec.Command("git", diffArgs...) + cmd = exec.Command(git.GitExecutable, diffArgs...) } cmd.Dir = repoPath cmd.Stderr = os.Stderr @@ -752,23 +752,23 @@ func GetRawDiffForFile(repoPath, startCommit, endCommit string, diffType RawDiff switch diffType { case RawDiffNormal: if len(startCommit) != 0 { - cmd = exec.Command("git", append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...) + cmd = exec.Command(git.GitExecutable, append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...) } else if commit.ParentCount() == 0 { - cmd = exec.Command("git", append([]string{"show", endCommit}, fileArgs...)...) + cmd = exec.Command(git.GitExecutable, append([]string{"show", endCommit}, fileArgs...)...) } else { c, _ := commit.Parent(0) - cmd = exec.Command("git", append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...) + cmd = exec.Command(git.GitExecutable, append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...) } case RawDiffPatch: if len(startCommit) != 0 { query := fmt.Sprintf("%s...%s", endCommit, startCommit) - cmd = exec.Command("git", append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...) + cmd = exec.Command(git.GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...) } else if commit.ParentCount() == 0 { - cmd = exec.Command("git", append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...) + cmd = exec.Command(git.GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...) } else { c, _ := commit.Parent(0) query := fmt.Sprintf("%s...%s", endCommit, c.ID.String()) - cmd = exec.Command("git", append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...) + cmd = exec.Command(git.GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...) } default: return fmt.Errorf("invalid diffType: %s", diffType) diff --git a/models/pull.go b/models/pull.go index 38976d37ec..2f5412651b 100644 --- a/models/pull.go +++ b/models/pull.go @@ -463,7 +463,7 @@ func (pr *PullRequest) getMergeCommit() (*git.Commit, error) { // Check if a pull request is merged into BaseBranch _, stderr, err := process.GetManager().ExecDirEnv(-1, "", fmt.Sprintf("isMerged (git merge-base --is-ancestor): %d", pr.BaseRepo.ID), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}, - "git", "merge-base", "--is-ancestor", headFile, pr.BaseBranch) + git.GitExecutable, "merge-base", "--is-ancestor", headFile, pr.BaseBranch) if err != nil { // Errors are signaled by a non-zero status that is not 1 @@ -486,7 +486,7 @@ func (pr *PullRequest) getMergeCommit() (*git.Commit, error) { // Get the commit from BaseBranch where the pull request got merged mergeCommit, stderr, err := process.GetManager().ExecDirEnv(-1, "", fmt.Sprintf("isMerged (git rev-list --ancestry-path --merges --reverse): %d", pr.BaseRepo.ID), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}, - "git", "rev-list", "--ancestry-path", "--merges", "--reverse", cmd) + git.GitExecutable, "rev-list", "--ancestry-path", "--merges", "--reverse", cmd) if err != nil { return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v %v", stderr, err) } else if len(mergeCommit) < 40 { @@ -548,7 +548,7 @@ func (pr *PullRequest) testPatch(e Engine) (err error) { var stderr string _, stderr, err = process.GetManager().ExecDirEnv(-1, "", fmt.Sprintf("testPatch (git read-tree): %d", pr.BaseRepo.ID), []string{"GIT_DIR=" + pr.BaseRepo.RepoPath(), "GIT_INDEX_FILE=" + indexTmpPath}, - "git", "read-tree", pr.BaseBranch) + git.GitExecutable, "read-tree", pr.BaseBranch) if err != nil { return fmt.Errorf("git read-tree --index-output=%s %s: %v - %s", indexTmpPath, pr.BaseBranch, err, stderr) } @@ -568,7 +568,7 @@ func (pr *PullRequest) testPatch(e Engine) (err error) { _, stderr, err = process.GetManager().ExecDirEnv(-1, "", fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}, - "git", args...) + git.GitExecutable, args...) if err != nil { for i := range patchConflicts { if strings.Contains(stderr, patchConflicts[i]) { diff --git a/models/release.go b/models/release.go index 036b5f78b9..f8e8c17e74 100644 --- a/models/release.go +++ b/models/release.go @@ -434,7 +434,7 @@ func DeleteReleaseByID(id int64, u *User, delTag bool) error { if delTag { _, stderr, err := process.GetManager().ExecDir(-1, repo.RepoPath(), fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID), - "git", "tag", "-d", rel.TagName) + git.GitExecutable, "tag", "-d", rel.TagName) if err != nil && !strings.Contains(stderr, "not found") { return fmt.Errorf("git tag -d: %v - %s", err, stderr) } diff --git a/models/repo.go b/models/repo.go index 2f732d0e26..1b4ff1f186 100644 --- a/models/repo.go +++ b/models/repo.go @@ -932,22 +932,18 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err } } - // Check if repository is empty. - _, stderr, err := com.ExecCmdDir(repoPath, "git", "log", "-1") + gitRepo, err := git.OpenRepository(repoPath) if err != nil { - if strings.Contains(stderr, "fatal: bad default revision 'HEAD'") { - repo.IsEmpty = true - } else { - return repo, fmt.Errorf("check empty: %v - %s", err, stderr) - } + return repo, fmt.Errorf("OpenRepository: %v", err) + } + + repo.IsEmpty, err = gitRepo.IsEmpty() + if err != nil { + return repo, fmt.Errorf("git.IsEmpty: %v", err) } if !repo.IsEmpty { // Try to get HEAD branch and set it as default branch. - gitRepo, err := git.OpenRepository(repoPath) - if err != nil { - return repo, fmt.Errorf("OpenRepository: %v", err) - } headBranch, err := gitRepo.GetHEADBranch() if err != nil { return repo, fmt.Errorf("GetHEADBranch: %v", err) @@ -1072,20 +1068,20 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { var stderr string if _, stderr, err = process.GetManager().ExecDir(-1, tmpPath, fmt.Sprintf("initRepoCommit (git add): %s", tmpPath), - "git", "add", "--all"); err != nil { + git.GitExecutable, "add", "--all"); err != nil { return fmt.Errorf("git add: %s", stderr) } if _, stderr, err = process.GetManager().ExecDir(-1, tmpPath, fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath), - "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), + git.GitExecutable, "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", "Initial commit"); err != nil { return fmt.Errorf("git commit: %s", stderr) } if _, stderr, err = process.GetManager().ExecDir(-1, tmpPath, fmt.Sprintf("initRepoCommit (git push): %s", tmpPath), - "git", "push", "origin", "master"); err != nil { + git.GitExecutable, "push", "origin", "master"); err != nil { return fmt.Errorf("git push: %s", stderr) } return nil @@ -1131,7 +1127,7 @@ func prepareRepoCommit(e Engine, repo *Repository, tmpDir, repoPath string, opts // Clone to temporary path and do the init commit. _, stderr, err := process.GetManager().Exec( fmt.Sprintf("initRepository(git clone): %s", repoPath), - "git", "clone", repoPath, tmpDir, + git.GitExecutable, "clone", repoPath, tmpDir, ) if err != nil { return fmt.Errorf("git clone: %v - %s", err, stderr) @@ -1390,7 +1386,7 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err _, stderr, err := process.GetManager().ExecDir(-1, repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath), - "git", "update-server-info") + git.GitExecutable, "update-server-info") if err != nil { return nil, errors.New("CreateRepository(git update-server-info): " + stderr) } @@ -2239,7 +2235,7 @@ func GitGcRepos() error { _, stderr, err := process.GetManager().ExecDir( time.Duration(setting.Git.Timeout.GC)*time.Second, RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection", - "git", args...) + git.GitExecutable, args...) if err != nil { return fmt.Errorf("%v: %v", err, stderr) } @@ -2429,14 +2425,14 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R repoPath := RepoPath(u.Name, repo.Name) _, stderr, err := process.GetManager().ExecTimeout(10*time.Minute, fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name), - "git", "clone", "--bare", oldRepo.repoPath(sess), repoPath) + git.GitExecutable, "clone", "--bare", oldRepo.repoPath(sess), repoPath) if err != nil { return nil, fmt.Errorf("git clone: %v", stderr) } _, stderr, err = process.GetManager().ExecDir(-1, repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath), - "git", "update-server-info") + git.GitExecutable, "update-server-info") if err != nil { return nil, fmt.Errorf("git update-server-info: %v", stderr) } diff --git a/models/repo_mirror.go b/models/repo_mirror.go index 7579231d8c..c62834f6fb 100644 --- a/models/repo_mirror.go +++ b/models/repo_mirror.go @@ -216,7 +216,7 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) { _, stderr, err := process.GetManager().ExecDir( timeout, repoPath, fmt.Sprintf("Mirror.runSync: %s", repoPath), - "git", gitArgs...) + git.GitExecutable, gitArgs...) if err != nil { // sanitize the output, since it may contain the remote address, which may // contain a password @@ -250,7 +250,7 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) { if m.Repo.HasWiki() { if _, stderr, err := process.GetManager().ExecDir( timeout, wikiPath, fmt.Sprintf("Mirror.runSync: %s", wikiPath), - "git", "remote", "update", "--prune"); err != nil { + git.GitExecutable, "remote", "update", "--prune"); err != nil { // sanitize the output, since it may contain the remote address, which may // contain a password message, err := sanitizeOutput(stderr, wikiPath) diff --git a/models/update.go b/models/update.go index 3eb0990d3d..411f7d5be1 100644 --- a/models/update.go +++ b/models/update.go @@ -7,7 +7,6 @@ package models import ( "container/list" "fmt" - "os/exec" "strings" "time" @@ -193,9 +192,8 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { repoPath := RepoPath(opts.RepoUserName, opts.RepoName) - gitUpdate := exec.Command("git", "update-server-info") - gitUpdate.Dir = repoPath - if err = gitUpdate.Run(); err != nil { + _, err = git.NewCommand("update-server-info").RunInDir(repoPath) + if err != nil { return nil, fmt.Errorf("Failed to call 'git update-server-info': %v", err) } diff --git a/models/git_blame.go b/modules/git/blame.go similarity index 93% rename from models/git_blame.go rename to modules/git/blame.go index 2b439a23b9..548236b657 100644 --- a/models/git_blame.go +++ b/modules/git/blame.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package git import ( "bufio" @@ -12,7 +12,6 @@ import ( "os/exec" "regexp" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/process" ) @@ -88,12 +87,12 @@ func (r *BlameReader) Close() error { // CreateBlameReader creates reader for given repository, commit and file func CreateBlameReader(repoPath, commitID, file string) (*BlameReader, error) { - _, err := git.OpenRepository(repoPath) + _, err := OpenRepository(repoPath) if err != nil { return nil, err } - return createBlameReader(repoPath, "git", "blame", commitID, "--porcelain", "--", file) + return createBlameReader(repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file) } func createBlameReader(dir string, command ...string) (*BlameReader, error) { diff --git a/models/git_blame_test.go b/modules/git/blame_test.go similarity index 99% rename from models/git_blame_test.go rename to modules/git/blame_test.go index eb0b35380b..1752312d81 100644 --- a/models/git_blame_test.go +++ b/modules/git/blame_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package git import ( "io/ioutil" diff --git a/modules/git/command.go b/modules/git/command.go index d6221ce268..347dcfe39f 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -12,6 +12,8 @@ import ( "os/exec" "strings" "time" + + "code.gitea.io/gitea/modules/process" ) var ( @@ -84,6 +86,9 @@ func (c *Command) RunInDirTimeoutEnvFullPipeline(env []string, timeout time.Dura return err } + pid := process.GetManager().Add(fmt.Sprintf("%s %s %s [repo_path: %s]", GitExecutable, c.name, strings.Join(c.args, " "), dir), cmd) + defer process.GetManager().Remove(pid) + if err := cmd.Wait(); err != nil { return err } diff --git a/modules/git/repo.go b/modules/git/repo.go index f5d7ee63bb..8a40fb1b91 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -107,6 +107,20 @@ func OpenRepository(repoPath string) (*Repository, error) { }, nil } +// IsEmpty Check if repository is empty. +func (repo *Repository) IsEmpty() (bool, error) { + var errbuf strings.Builder + if err := NewCommand("log", "-1").RunInDirPipeline(repo.Path, nil, &errbuf); err != nil { + if strings.Contains(errbuf.String(), "fatal: bad default revision 'HEAD'") || + strings.Contains(errbuf.String(), "fatal: your current branch 'master' does not have any commits yet") { + return true, nil + } + return true, fmt.Errorf("check empty: %v - %s", err, errbuf.String()) + } + + return false, nil +} + // CloneRepoOptions options when clone a repository type CloneRepoOptions struct { Timeout time.Duration diff --git a/modules/git/repo_test.go b/modules/git/repo_test.go index c5ce6f4447..15f5e3781c 100644 --- a/modules/git/repo_test.go +++ b/modules/git/repo_test.go @@ -5,6 +5,7 @@ package git import ( + "path/filepath" "testing" "time" @@ -24,3 +25,12 @@ func TestGetLatestCommitTime(t *testing.T) { assert.NoError(t, err) assert.True(t, lct.Unix() > refTime.Unix(), "%d not greater than %d", lct, refTime) } + +func TestRepoIsEmpty(t *testing.T) { + emptyRepo2Path := filepath.Join(testReposDir, "repo2_empty") + repo, err := OpenRepository(emptyRepo2Path) + assert.NoError(t, err) + isEmpty, err := repo.IsEmpty() + assert.NoError(t, err) + assert.True(t, isEmpty) +} diff --git a/modules/git/tests/repos/repo2_empty/HEAD b/modules/git/tests/repos/repo2_empty/HEAD new file mode 100644 index 0000000000..cb089cd89a --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/modules/git/tests/repos/repo2_empty/config b/modules/git/tests/repos/repo2_empty/config new file mode 100644 index 0000000000..e6da231579 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true diff --git a/modules/git/tests/repos/repo2_empty/description b/modules/git/tests/repos/repo2_empty/description new file mode 100644 index 0000000000..498b267a8c --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/modules/git/tests/repos/repo2_empty/hooks/applypatch-msg.sample b/modules/git/tests/repos/repo2_empty/hooks/applypatch-msg.sample new file mode 100755 index 0000000000..a5d7b84a67 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/modules/git/tests/repos/repo2_empty/hooks/commit-msg.sample b/modules/git/tests/repos/repo2_empty/hooks/commit-msg.sample new file mode 100755 index 0000000000..b58d1184a9 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/modules/git/tests/repos/repo2_empty/hooks/fsmonitor-watchman.sample b/modules/git/tests/repos/repo2_empty/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000000..e673bb3980 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/fsmonitor-watchman.sample @@ -0,0 +1,114 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 1) and a time in nanoseconds +# formatted as a string and outputs to stdout all files that have been +# modified since the given time. Paths must be relative to the root of +# the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $time) = @ARGV; + +# Check the hook interface version + +if ($version == 1) { + # convert nanoseconds to seconds + $time = int $time / 1000000000; +} else { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree; +if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $git_work_tree = Win32::GetCwd(); + $git_work_tree =~ tr/\\/\//; +} else { + require Cwd; + $git_work_tree = Cwd::cwd(); +} + +my $retry = 1; + +launch_watchman(); + +sub launch_watchman { + + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $time but were not transient (ie created after + # $time but no longer exist). + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + # + # The category of transient files that we want to ignore will have a + # creation clock (cclock) newer than $time_t value and will also not + # currently exist. + + my $query = <<" END"; + ["query", "$git_work_tree", { + "since": $time, + "fields": ["name"], + "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]] + }] + END + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + my $json_pkg; + eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; + } or do { + require JSON::PP; + $json_pkg = "JSON::PP"; + }; + + my $o = $json_pkg->new->utf8->decode($response); + + if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) { + print STDERR "Adding '$git_work_tree' to watchman's watch list.\n"; + $retry--; + qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + print "/\0"; + eval { launch_watchman() }; + exit 0; + } + + die "Watchman: $o->{error}.\n" . + "Falling back to scanning...\n" if $o->{error}; + + binmode STDOUT, ":utf8"; + local $, = "\0"; + print @{$o->{files}}; +} diff --git a/modules/git/tests/repos/repo2_empty/hooks/post-update.sample b/modules/git/tests/repos/repo2_empty/hooks/post-update.sample new file mode 100755 index 0000000000..ec17ec1939 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/modules/git/tests/repos/repo2_empty/hooks/pre-applypatch.sample b/modules/git/tests/repos/repo2_empty/hooks/pre-applypatch.sample new file mode 100755 index 0000000000..4142082bcb --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/modules/git/tests/repos/repo2_empty/hooks/pre-commit.sample b/modules/git/tests/repos/repo2_empty/hooks/pre-commit.sample new file mode 100755 index 0000000000..6a75641638 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/modules/git/tests/repos/repo2_empty/hooks/pre-push.sample b/modules/git/tests/repos/repo2_empty/hooks/pre-push.sample new file mode 100755 index 0000000000..6187dbf439 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/modules/git/tests/repos/repo2_empty/hooks/pre-rebase.sample b/modules/git/tests/repos/repo2_empty/hooks/pre-rebase.sample new file mode 100755 index 0000000000..6cbef5c370 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/modules/git/tests/repos/repo2_empty/hooks/pre-receive.sample b/modules/git/tests/repos/repo2_empty/hooks/pre-receive.sample new file mode 100755 index 0000000000..a1fd29ec14 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/modules/git/tests/repos/repo2_empty/hooks/prepare-commit-msg.sample b/modules/git/tests/repos/repo2_empty/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000000..10fa14c5ab --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/modules/git/tests/repos/repo2_empty/hooks/update.sample b/modules/git/tests/repos/repo2_empty/hooks/update.sample new file mode 100755 index 0000000000..80ba94135c --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/modules/git/tests/repos/repo2_empty/info/exclude b/modules/git/tests/repos/repo2_empty/info/exclude new file mode 100644 index 0000000000..a5196d1be8 --- /dev/null +++ b/modules/git/tests/repos/repo2_empty/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/modules/git/tests/repos/repo2_empty/objects/info/.gitkeep b/modules/git/tests/repos/repo2_empty/objects/info/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/git/tests/repos/repo2_empty/objects/pack/.gitkeep b/modules/git/tests/repos/repo2_empty/objects/pack/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/git/tests/repos/repo2_empty/refs/heads/.gitkeep b/modules/git/tests/repos/repo2_empty/refs/heads/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/git/tests/repos/repo2_empty/refs/tags/.gitkeep b/modules/git/tests/repos/repo2_empty/refs/tags/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/repofiles/temp_repo.go b/modules/repofiles/temp_repo.go index ec35628676..ef75709c23 100644 --- a/modules/repofiles/temp_repo.go +++ b/modules/repofiles/temp_repo.go @@ -50,7 +50,7 @@ func (t *TemporaryUploadRepository) Close() { func (t *TemporaryUploadRepository) Clone(branch string) error { if _, stderr, err := process.GetManager().ExecTimeout(5*time.Minute, fmt.Sprintf("Clone (git clone -s --bare): %s", t.basePath), - "git", "clone", "-s", "--bare", "-b", branch, t.repo.RepoPath(), t.basePath); err != nil { + git.GitExecutable, "clone", "-s", "--bare", "-b", branch, t.repo.RepoPath(), t.basePath); err != nil { if matched, _ := regexp.MatchString(".*Remote branch .* not found in upstream origin.*", stderr); matched { return git.ErrBranchNotExist{ Name: branch, @@ -79,7 +79,7 @@ func (t *TemporaryUploadRepository) SetDefaultIndex() error { if _, stderr, err := process.GetManager().ExecDir(5*time.Minute, t.basePath, fmt.Sprintf("SetDefaultIndex (git read-tree HEAD): %s", t.basePath), - "git", "read-tree", "HEAD"); err != nil { + git.GitExecutable, "read-tree", "HEAD"); err != nil { return fmt.Errorf("SetDefaultIndex: %v %s", err, stderr) } return nil @@ -101,7 +101,7 @@ func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, erro } } - cmd := exec.CommandContext(ctx, "git", cmdArgs...) + cmd := exec.CommandContext(ctx, git.GitExecutable, cmdArgs...) desc := fmt.Sprintf("lsFiles: (git ls-files) %v", cmdArgs) cmd.Dir = t.basePath cmd.Stdout = stdOut @@ -146,7 +146,7 @@ func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) er defer cancel() cmdArgs := []string{"update-index", "--remove", "-z", "--index-info"} - cmd := exec.CommandContext(ctx, "git", cmdArgs...) + cmd := exec.CommandContext(ctx, git.GitExecutable, cmdArgs...) desc := fmt.Sprintf("removeFilesFromIndex: (git update-index) %v", filenames) cmd.Dir = t.basePath cmd.Stdout = stdOut @@ -174,7 +174,7 @@ func (t *TemporaryUploadRepository) HashObject(content io.Reader) (string, error ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() - hashCmd := exec.CommandContext(ctx, "git", "hash-object", "-w", "--stdin") + hashCmd := exec.CommandContext(ctx, git.GitExecutable, "hash-object", "-w", "--stdin") hashCmd.Dir = t.basePath hashCmd.Stdin = content stdOutBuffer := new(bytes.Buffer) @@ -203,7 +203,7 @@ func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPat if _, stderr, err := process.GetManager().ExecDir(5*time.Minute, t.basePath, fmt.Sprintf("addObjectToIndex (git update-index): %s", t.basePath), - "git", "update-index", "--add", "--replace", "--cacheinfo", mode, objectHash, objectPath); err != nil { + git.GitExecutable, "update-index", "--add", "--replace", "--cacheinfo", mode, objectHash, objectPath); err != nil { if matched, _ := regexp.MatchString(".*Invalid path '.*", stderr); matched { return models.ErrFilePathInvalid{ Message: objectPath, @@ -220,7 +220,7 @@ func (t *TemporaryUploadRepository) WriteTree() (string, error) { treeHash, stderr, err := process.GetManager().ExecDir(5*time.Minute, t.basePath, fmt.Sprintf("WriteTree (git write-tree): %s", t.basePath), - "git", "write-tree") + git.GitExecutable, "write-tree") if err != nil { return "", fmt.Errorf("git write-tree: %s", stderr) } @@ -240,7 +240,7 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, erro treeHash, stderr, err := process.GetManager().ExecDir(5*time.Minute, t.basePath, fmt.Sprintf("GetLastCommit (git rev-parse %s): %s", ref, t.basePath), - "git", "rev-parse", ref) + git.GitExecutable, "rev-parse", ref) if err != nil { return "", fmt.Errorf("git rev-parse %s: %s", ref, stderr) } @@ -267,7 +267,7 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t t.basePath, fmt.Sprintf("commitTree (git commit-tree): %s", t.basePath), env, - "git", "commit-tree", treeHash, "-p", "HEAD", "-m", message) + git.GitExecutable, "commit-tree", treeHash, "-p", "HEAD", "-m", message) if err != nil { return "", fmt.Errorf("git commit-tree: %s", stderr) } @@ -283,7 +283,7 @@ func (t *TemporaryUploadRepository) Push(doer *models.User, commitHash string, b t.basePath, fmt.Sprintf("actuallyPush (git push): %s", t.basePath), env, - "git", "push", t.repo.RepoPath(), strings.TrimSpace(commitHash)+":refs/heads/"+strings.TrimSpace(branch)); err != nil { + git.GitExecutable, "push", t.repo.RepoPath(), strings.TrimSpace(commitHash)+":refs/heads/"+strings.TrimSpace(branch)); err != nil { return fmt.Errorf("git push: %s", stderr) } return nil @@ -297,7 +297,7 @@ func (t *TemporaryUploadRepository) DiffIndex() (diff *models.Diff, err error) { stdErr := new(bytes.Buffer) - cmd := exec.CommandContext(ctx, "git", "diff-index", "--cached", "-p", "HEAD") + cmd := exec.CommandContext(ctx, git.GitExecutable, "diff-index", "--cached", "-p", "HEAD") cmd.Dir = t.basePath cmd.Stderr = stdErr @@ -341,7 +341,7 @@ func (t *TemporaryUploadRepository) CheckAttribute(attribute string, args ...str } } - cmd := exec.CommandContext(ctx, "git", cmdArgs...) + cmd := exec.CommandContext(ctx, git.GitExecutable, cmdArgs...) desc := fmt.Sprintf("checkAttr: (git check-attr) %s %v", attribute, cmdArgs) cmd.Dir = t.basePath cmd.Stdout = stdOut diff --git a/routers/repo/blame.go b/routers/repo/blame.go index 2b2f45f0bb..07952a4cae 100644 --- a/routers/repo/blame.go +++ b/routers/repo/blame.go @@ -131,14 +131,14 @@ func RefBlame(ctx *context.Context) { ctx.Data["FileSize"] = blob.Size() ctx.Data["FileName"] = blob.Name() - blameReader, err := models.CreateBlameReader(models.RepoPath(userName, repoName), commitID, fileName) + blameReader, err := git.CreateBlameReader(models.RepoPath(userName, repoName), commitID, fileName) if err != nil { ctx.NotFound("CreateBlameReader", err) return } defer blameReader.Close() - blameParts := make([]models.BlamePart, 0) + blameParts := make([]git.BlamePart, 0) for { blamePart, err := blameReader.NextPart() @@ -189,7 +189,7 @@ func RefBlame(ctx *context.Context) { ctx.HTML(200, tplBlame) } -func renderBlame(ctx *context.Context, blameParts []models.BlamePart, commitNames map[string]models.UserCommit) { +func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames map[string]models.UserCommit) { repoLink := ctx.Repo.RepoLink var lines = make([]string, 0) diff --git a/routers/repo/http.go b/routers/repo/http.go index 3072209448..48f5625051 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -343,19 +344,11 @@ var routes = []route{ {regexp.MustCompile(`(.*?)/objects/pack/pack-[0-9a-f]{40}\.idx$`), "GET", getIdxFile}, } -// FIXME: use process module -func gitCommand(dir string, args ...string) []byte { - cmd := exec.Command("git", args...) - cmd.Dir = dir - out, err := cmd.Output() +func getGitConfig(option, dir string) string { + out, err := git.NewCommand("config", option).RunInDir(dir) if err != nil { log.Error("%v - %s", err, out) } - return out -} - -func getGitConfig(option, dir string) string { - out := string(gitCommand(dir, "config", option)) return out[0 : len(out)-1] } @@ -422,7 +415,7 @@ func serviceRPC(h serviceHandler, service string) { h.environ = append(h.environ, "SSH_ORIGINAL_COMMAND="+service) var stderr bytes.Buffer - cmd := exec.Command("git", service, "--stateless-rpc", h.dir) + cmd := exec.Command(git.GitExecutable, service, "--stateless-rpc", h.dir) cmd.Dir = h.dir if service == "receive-pack" { cmd.Env = append(os.Environ(), h.environ...) @@ -453,7 +446,11 @@ func getServiceType(r *http.Request) string { } func updateServerInfo(dir string) []byte { - return gitCommand(dir, "update-server-info") + out, err := git.NewCommand("update-server-info").RunInDirBytes(dir) + if err != nil { + log.Error(fmt.Sprintf("%v - %s", err, string(out))) + } + return out } func packetWrite(str string) []byte { @@ -468,7 +465,10 @@ func getInfoRefs(h serviceHandler) { h.setHeaderNoCache() if hasAccess(getServiceType(h.r), h, false) { service := getServiceType(h.r) - refs := gitCommand(h.dir, service, "--stateless-rpc", "--advertise-refs", ".") + refs, err := git.NewCommand(service, "--stateless-rpc", "--advertise-refs", ".").RunInDirBytes(h.dir) + if err != nil { + log.Error(fmt.Sprintf("%v - %s", err, string(refs))) + } h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service)) h.w.WriteHeader(http.StatusOK) From da230412574daa9697b4cef24c7be6209b8884dc Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 26 Jun 2019 23:35:07 +0200 Subject: [PATCH 146/220] fix extra newlines when copying from diff in Firefox (#7288) * fix extra newlines when copying from diff See https://bugzilla.mozilla.org/show_bug.cgi?id=1273836 Basically, the
     seems to add a forced newline that is not
    possible to get rid of via CSS, so I replaced it with just a .
    
    Secondly, .lines-type-marker also forced a newline in the copied text,
    but that was possible to get rid of via user-select.
    
    Safari still has a extraneous newline in the copied text of unknown
    origin, but this should not block stop this PR.
    
    * simplify .line-type-marker
    
    * fix selector
    
    * remove erronous ^^^
    
    * Fix empty split diff
    
    * Fix arc-theme-green
    
    * fix add comment
    
    * ensure line-num is copied too
    
    * Update templates/repo/diff/box.tmpl
    
    Co-Authored-By: zeripath 
    
    * attempt to fix safari via removing 
    
    * remove useless whitespace at the end of 'class'
    
    * remove inter-tag whitespace for code 
    s * more inter-tag removal * final inter-tag removal * attempt to fix empty line copy * move and comment getLineContent * fix golint * make background grey for missing added code --- models/git_diff.go | 24 ++++++++----- public/css/index.css | 15 ++++----- public/css/theme-arc-green.css | 6 ++-- public/js/index.js | 4 +-- public/less/_base.less | 3 +- public/less/_repository.less | 11 +++--- public/less/themes/arc-green.less | 8 +++-- templates/repo/diff/box.tmpl | 43 +++++++++--------------- templates/repo/diff/section_unified.tmpl | 19 +++-------- 9 files changed, 59 insertions(+), 74 deletions(-) diff --git a/models/git_diff.go b/models/git_diff.go index bc79a73a4e..2f48f1b6fa 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -88,6 +88,14 @@ func (d *DiffLine) GetLineTypeMarker() string { return "" } +// escape a line's content or return
    needed for copy/paste purposes +func getLineContent(content string) string { + if len(content) > 0 { + return html.EscapeString(content) + } + return "
    " +} + // DiffSection represents a section of a DiffFile. type DiffSection struct { Name string @@ -107,14 +115,14 @@ func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTM switch { case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: buf.Write(addedCodePrefix) - buf.WriteString(html.EscapeString(diffs[i].Text)) + buf.WriteString(getLineContent(diffs[i].Text)) buf.Write(codeTagSuffix) case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: buf.Write(removedCodePrefix) - buf.WriteString(html.EscapeString(diffs[i].Text)) + buf.WriteString(getLineContent(diffs[i].Text)) buf.Write(codeTagSuffix) case diffs[i].Type == diffmatchpatch.DiffEqual: - buf.WriteString(html.EscapeString(diffs[i].Text)) + buf.WriteString(getLineContent(diffs[i].Text)) } } @@ -173,7 +181,7 @@ func init() { // GetComputedInlineDiffFor computes inline diff for the given line. func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML { if setting.Git.DisableDiffHighlight { - return template.HTML(html.EscapeString(diffLine.Content[1:])) + return template.HTML(getLineContent(diffLine.Content[1:])) } var ( compareDiffLine *DiffLine @@ -186,22 +194,22 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem case DiffLineAdd: compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx) if compareDiffLine == nil { - return template.HTML(html.EscapeString(diffLine.Content[1:])) + return template.HTML(getLineContent(diffLine.Content[1:])) } diff1 = compareDiffLine.Content diff2 = diffLine.Content case DiffLineDel: compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx) if compareDiffLine == nil { - return template.HTML(html.EscapeString(diffLine.Content[1:])) + return template.HTML(getLineContent(diffLine.Content[1:])) } diff1 = diffLine.Content diff2 = compareDiffLine.Content default: if strings.IndexByte(" +-", diffLine.Content[0]) > -1 { - return template.HTML(html.EscapeString(diffLine.Content[1:])) + return template.HTML(getLineContent(diffLine.Content[1:])) } - return template.HTML(html.EscapeString(diffLine.Content)) + return template.HTML(getLineContent(diffLine.Content)) } diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true) diff --git a/public/css/index.css b/public/css/index.css index 475a54f75f..5e2c7908e9 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -47,9 +47,9 @@ img{border-radius:3px} table{border-collapse:collapse} a{cursor:pointer} .rounded{border-radius:.28571429rem!important} -code,pre{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} -code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto} -code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word} +.mono,code,pre{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} +.mono.raw,code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto} +.mono.wrap,code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word} .dont-break-out{overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto} .full.height{flex-grow:1;padding-bottom:80px} .following.bar{z-index:900;left:0;margin:0!important} @@ -638,19 +638,18 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #ddd} .repository .diff-file-box .code-diff{font-size:12px} .repository .diff-file-box .code-diff td{padding:0 0 0 10px;border-top:0} -.repository .diff-file-box .code-diff pre{margin:0} .repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px} .repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%} .repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} .repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99} .repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9} -.repository .diff-file-box .code-diff tbody tr .lines-num[data-line-num]::before{content:attr(data-line-num);text-align:right} -.repository .diff-file-box .code-diff tbody tr .lines-type-marker{width:10px;min-width:10px} -.repository .diff-file-box .code-diff tbody tr .line-type-marker[data-type-marker]::before{content:attr(data-type-marker);text-align:right;display:inline-block} +.repository .diff-file-box .code-diff tbody tr [data-line-num]::before{content:attr(data-line-num);text-align:right} +.repository .diff-file-box .code-diff tbody tr .lines-type-marker{width:10px;min-width:10px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} +.repository .diff-file-box .code-diff tbody tr [data-type-marker]::before{content:attr(data-type-marker);text-align:right;display:inline-block} .repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important} .repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important} .repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%} -.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#fafafa} +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#fafafa} .repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#ffe0e0!important;border-color:#f1c0c0!important} .repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#d6fcd6!important;border-color:#c1e9c1!important} .repository .diff-file-box .code-diff-split tbody tr td:nth-child(4){border-left-width:1px;border-left-style:solid} diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index 05cc6e5ebb..f61fd2c96e 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -216,9 +216,9 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb .ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #a27558 inset!important;color:#a27558!important} .repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb} -.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#2a2e3a} -.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#283e2d!important;border-color:#314a37!important} -.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#3c2626!important;border-color:#634343!important} +.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a} +.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important} +.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important} .ui.blue.button:focus,.ui.blue.buttons .button:focus{background-color:#a27558} .ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558} #git-graph-container li a{color:#c79575} diff --git a/public/js/index.js b/public/js/index.js index 3b2527d986..53fcaa8ba1 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1069,8 +1069,8 @@ function initPullRequestReview() { var ntr = tr.next(); if (!ntr.hasClass('add-comment')) { ntr = $('
    - - -
    {{if $line.LeftIdx}}{{end}}
    -
    - {{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}} - + - {{end}} -
    {{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}
    -
    - - -
    {{if $line.RightIdx}}{{end}}
    -
    - {{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}} - + - {{end}} -
    {{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}
    -
    {{if $line.LeftIdx}}{{end}}{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}+{{end}}{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}{{if $line.RightIdx}}{{end}}{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}+{{end}}{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}
    - - - - -
    -
    - {{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles}} - + - {{end}} -
    {{$section.GetComputedInlineDiffFor $line}}
    -
    {{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles}}+{{end}}{{$section.GetComputedInlineDiffFor $line}}
    - + + {{if and $.IsWriter (not $.IsMirror)}} @@ -44,9 +45,10 @@ {{else}} {{.Name}}

    {{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}

    - {{end}} + + {{if and $.IsWriter (not $.IsMirror)}}
    {{.i18n.Tr "repo.branch.name"}}{{.i18n.Tr "repo.branch.name"}} {{.i18n.Tr "repo.branch.delete_head"}} + {{if not .IsDeleted}}
    {{.CommitsBehind}}
    @@ -57,6 +59,25 @@
    + {{end}} +
    + {{if not .LatestPullRequest}} + {{if not .IsDeleted}} + + + + {{end}} + {{else}} + #{{.LatestPullRequest.Issue.Index}} + {{if .LatestPullRequest.HasMerged}} + {{$.i18n.Tr "repo.pulls.merged"}} + {{else if .LatestPullRequest.Issue.IsClosed}} + {{$.i18n.Tr "repo.issues.closed_title"}} + {{else}} + {{$.i18n.Tr "repo.issues.open_title"}} + {{end}} + {{end}} From 855ebbd206deb7c8a9d34031e1ecefa743aaa83c Mon Sep 17 00:00:00 2001 From: Cherrg Date: Fri, 28 Jun 2019 04:45:54 +0200 Subject: [PATCH 149/220] gitea own dark codemirror theme (#7317) * modify dark codemirror theme fix #6573 Signed-off-by: Michael Gnehr * add selection color Signed-off-by: Michael Gnehr --- public/css/theme-arc-green.css | 30 ++++++- public/less/themes/arc-green.less | 125 ++++++++++++++++++++++++++---- 2 files changed, 137 insertions(+), 18 deletions(-) diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index f165ea8c84..bb79c335d1 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -169,7 +169,6 @@ input{background:#2e323e} .ui.bottom.attached.message{background-color:#2c662d;color:#87ab63} .ui.bottom.attached.message .pull-right{color:#87ab63} .ui.info.message{background-color:#2c3b4a;color:#9ebcc5} -.CodeMirror div.CodeMirror-cursor{border-left:1px solid #9e9e9e} .ui .warning.header{background-color:#5d3a22!important;border-color:#794f31} .ui.red.message{background-color:rgba(80,23,17,.6);color:#f9cbcb;box-shadow:0 0 0 1px rgba(121,71,66,.5) inset,0 0 0 0 transparent} .ui.red.button,.ui.red.buttons .button{background-color:#7d3434} @@ -219,8 +218,6 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb .ui.modal>.content{background:#383c4a} .editor-toolbar{background-color:#404552} .editor-toolbar a{color:#87ab63!important} -.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:0} -.CodeMirror-gutters{background-color:#2b2b2b} .repository .diff-detail-box{background-color:#383c4a} .repository .diff-detail-box .detail-files{background-color:inherit} .comment-code-cloud .ui.attached.tabular.menu{background:none transparent;border:0} @@ -229,4 +226,29 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb .ui.comments .comment .author{color:#dbdbdb} .ui.comments .comment .metadata{color:#808084} .ui.comments .comment .text{color:#9e9e9e} -.heatmap-color-0{background-color:#2d303b} \ No newline at end of file +.heatmap-color-0{background-color:#2d303b} +.CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:0} +.CodeMirror div.CodeMirror-cursor{border-left:1px solid #9e9e9e} +.CodeMirror .CodeMirror-gutters{background-color:#2b2b2b} +.CodeMirror .CodeMirror-selected,.CodeMirror ::-moz-selection,.CodeMirror ::selection{background:#42402f!important} +.CodeMirror.cm-s-default .cm-property,.CodeMirror.cm-s-paper .cm-property{color:#a0cc75} +.CodeMirror.cm-s-default .cm-header,.CodeMirror.cm-s-paper .cm-header{color:#9daccc} +.CodeMirror.cm-s-default .cm-quote,.CodeMirror.cm-s-paper .cm-quote{color:#090} +.CodeMirror.cm-s-default .cm-keyword,.CodeMirror.cm-s-paper .cm-keyword{color:#cc8a61} +.CodeMirror.cm-s-default .cm-atom,.CodeMirror.cm-s-paper .cm-atom{color:#ef5e77} +.CodeMirror.cm-s-default .cm-number,.CodeMirror.cm-s-paper .cm-number{color:#ff5656} +.CodeMirror.cm-s-default .cm-def,.CodeMirror.cm-s-paper .cm-def{color:#e4e4e4} +.CodeMirror.cm-s-default .cm-variable-2,.CodeMirror.cm-s-paper .cm-variable-2{color:#00bdbf} +.CodeMirror.cm-s-default .cm-variable-3,.CodeMirror.cm-s-paper .cm-variable-3{color:#085} +.CodeMirror.cm-s-default .cm-comment,.CodeMirror.cm-s-paper .cm-comment{color:#8e9ab3} +.CodeMirror.cm-s-default .cm-string,.CodeMirror.cm-s-paper .cm-string{color:#a77272} +.CodeMirror.cm-s-default .cm-string-2,.CodeMirror.cm-s-paper .cm-string-2{color:#f50} +.CodeMirror.cm-s-default .cm-meta,.CodeMirror.cm-s-default .cm-qualifier,.CodeMirror.cm-s-paper .cm-meta,.CodeMirror.cm-s-paper .cm-qualifier{color:#ffb176} +.CodeMirror.cm-s-default .cm-builtin,.CodeMirror.cm-s-paper .cm-builtin{color:#b7c951} +.CodeMirror.cm-s-default .cm-bracket,.CodeMirror.cm-s-paper .cm-bracket{color:#997} +.CodeMirror.cm-s-default .cm-tag,.CodeMirror.cm-s-paper .cm-tag{color:#f1d273} +.CodeMirror.cm-s-default .cm-attribute,.CodeMirror.cm-s-paper .cm-attribute{color:#bfcc70} +.CodeMirror.cm-s-default .cm-hr,.CodeMirror.cm-s-paper .cm-hr{color:#999} +.CodeMirror.cm-s-default .cm-url,.CodeMirror.cm-s-paper .cm-url{color:#c5cfd0} +.CodeMirror.cm-s-default .cm-link,.CodeMirror.cm-s-paper .cm-link{color:#d8c792} +.CodeMirror.cm-s-default .cm-error,.CodeMirror.cm-s-paper .cm-error{color:#dbdbeb} \ No newline at end of file diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index e4f3095154..d15e2bfdb3 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -857,10 +857,6 @@ input { color: #9ebcc5; } -.CodeMirror div.CodeMirror-cursor { - border-left: 1px solid #9e9e9e; -} - .ui .warning.header { background-color: #5d3a22 !important; border-color: #794f31; @@ -1134,16 +1130,6 @@ a.ui.labels .label:hover { } } -.CodeMirror { - color: #9daccc; - background-color: #2b2b2b; - border-top: 0; -} - -.CodeMirror-gutters { - background-color: #2b2b2b; -} - .repository .diff-detail-box { background-color: #383c4a; @@ -1184,3 +1170,114 @@ a.ui.labels .label:hover { .heatmap-color-0 { background-color: #2d303b; } + +/* code mirror dark theme */ + +.CodeMirror { + color: #9daccc; + background-color: #2b2b2b; + border-top: 0; + + div.CodeMirror-cursor { + border-left: 1px solid #9e9e9e; + } + + .CodeMirror-gutters { + background-color: #2b2b2b; + } + + ::selection, + ::-moz-selection, + .CodeMirror-selected { + background: #42402f !important; + } + + &.cm-s-default, + &.cm-s-paper { + .cm-property { + color: #a0cc75; + } + + .cm-header { + color: #9daccc; + } + + .cm-quote { + color: #009900; + } + + .cm-keyword { + color: #cc8a61; + } + + .cm-atom { + color: #ef5e77; + } + + .cm-number { + color: #ff5656; + } + + .cm-def { + color: #e4e4e4; + } + + .cm-variable-2 { + color: #00bdbf; + } + + .cm-variable-3 { + color: #008855; + } + + .cm-comment { + color: #8e9ab3; + } + + .cm-string { + color: #a77272; + } + + .cm-string-2 { + color: #ff5500; + } + + .cm-meta, + .cm-qualifier { + color: #ffb176; + } + + .cm-builtin { + color: #b7c951; + } + + .cm-bracket { + color: #999977; + } + + .cm-tag { + color: #f1d273; + } + + .cm-attribute { + color: #bfcc70; + } + + .cm-hr { + color: #999999; + } + + .cm-url { + color: #c5cfd0; + } + + .cm-link { + color: #d8c792; + } + + .cm-error { + /* color: #ff6e00; */ + color: #dbdbeb; + } + } +} From 123c70395e99419d70ff54126d1d08bed24dbfe4 Mon Sep 17 00:00:00 2001 From: Cherrg Date: Fri, 28 Jun 2019 23:17:21 +0200 Subject: [PATCH 150/220] Dark theme fixes (#7319) * add dark theme for jquery xdsoft_datetimepicker Signed-off-by: Michael Gnehr * add border to dark theme - not checked issue checkboxes Signed-off-by: Michael Gnehr --- public/css/theme-arc-green.css | 13 +++++ public/less/themes/arc-green.less | 79 +++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index bb79c335d1..e94b150cdc 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -178,6 +178,7 @@ input{background:#2e323e} .ui.checkbox input:checked~.box:before,.ui.checkbox input:checked~label:before{background:#304251;opacity:1;color:#7f98ad;border-color:#304251} .ui.checkbox .box:hover::before,.ui.checkbox label:hover::before{background:#304251} .ui.checkbox .box:before,.ui.checkbox label:before{background:#304251;border:1px solid #304251} +.ui.checkbox label:before{border-color:#476075} .ui.checkbox .box:active::before,.ui.checkbox label:active::before{background:#304251;border-color:rgba(34,36,38,.35)} .ui.checkbox input:focus~.box:before,.ui.checkbox input:focus~label:before{border-color:#304251;background:#304251} .ui.checkbox input:checked:focus~.box:before,.ui.checkbox input:checked:focus~label:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~.box:before,.ui.checkbox input:not([type=radio]):indeterminate:focus~label:before{border-color:#304251;background:#304251} @@ -226,6 +227,18 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb .ui.comments .comment .author{color:#dbdbdb} .ui.comments .comment .metadata{color:#808084} .ui.comments .comment .text{color:#9e9e9e} +.xdsoft_datetimepicker{background:#2a2e39;border:1px solid #4c505c;color:#9e9e9e} +.xdsoft_datetimepicker .xdsoft_mounthpicker{height:36px;background:#464c5d;margin:-2px -8px 2px;padding:2px 8px 0} +.xdsoft_datetimepicker .xdsoft_mounthpicker button{background-image:none;text-indent:0;text-align:center;color:#9e9e9e} +.xdsoft_datetimepicker .xdsoft_mounthpicker button.xdsoft_prev::before{content:"\f0d9";font:normal normal normal 14px/1 FontAwesome,serif;font-size:1.7em} +.xdsoft_datetimepicker .xdsoft_mounthpicker button.xdsoft_next::before{content:"\f0da";font:normal normal normal 14px/1 FontAwesome,serif;font-size:1.7em} +.xdsoft_datetimepicker .xdsoft_mounthpicker button.xdsoft_today_button::before{content:"\f015";font:normal normal normal 14px/1 FontAwesome,serif;font-size:1.4em} +.xdsoft_datetimepicker .xdsoft_mounthpicker>div.xdsoft_label{background:#464c5d} +.xdsoft_datetimepicker .xdsoft_mounthpicker>div.xdsoft_label i{line-height:14px;background-image:none;text-indent:0;text-align:center} +.xdsoft_datetimepicker .xdsoft_mounthpicker>div.xdsoft_label i ::before{content:"\f0dd";font:normal normal normal 14px/1 FontAwesome,serif;font-size:.7em} +.xdsoft_datetimepicker .xdsoft_mounthpicker>div.xdsoft_label .xdsoft_select{background:#353945} +.xdsoft_datetimepicker .xdsoft_datepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_datepicker .xdsoft_calendar th{border-color:#4c505c;background-color:#2a2e39} +.xdsoft_datetimepicker .xdsoft_datepicker .xdsoft_calendar td.xdsoft_disabled,.xdsoft_datetimepicker .xdsoft_datepicker .xdsoft_calendar td.xdsoft_other_month{opacity:.8;background:#a0cc75;color:#000} .heatmap-color-0{background-color:#2d303b} .CodeMirror{color:#9daccc;background-color:#2b2b2b;border-top:0} .CodeMirror div.CodeMirror-cursor{border-left:1px solid #9e9e9e} diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index d15e2bfdb3..4fd98280ef 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -907,6 +907,10 @@ input { border: 1px solid #304251; } +.ui.checkbox label:before { + border-color: #476075; +} + .ui.checkbox .box:active::before, .ui.checkbox label:active::before { background: #304251; @@ -1167,6 +1171,81 @@ a.ui.labels .label:hover { } } +.xdsoft_datetimepicker { + background: #2a2e39; + border: 1px solid #4c505c; + color: #9e9e9e; + + .xdsoft_mounthpicker { + height: 36px; + background: #464c5d; + margin: -2px -8px 2px; + padding: 2px 8px 0; + + button { + background-image: none; + text-indent: 0; + text-align: center; + color: #9e9e9e; + + &.xdsoft_prev::before { + content: "\f0d9"; + font: normal normal normal 14px/1 FontAwesome, serif; + font-size: 1.7em; + } + + &.xdsoft_next::before { + content: "\f0da"; + font: normal normal normal 14px/1 FontAwesome, serif; + font-size: 1.7em; + } + + &.xdsoft_today_button::before { + content: "\f015"; + font: normal normal normal 14px/1 FontAwesome, serif; + font-size: 1.4em; + } + } + + & > div.xdsoft_label { + background: #464c5d; + + i { + line-height: 14px; + background-image: none; + text-indent: 0; + text-align: center; + + ::before { + content: "\f0dd"; + font: normal normal normal 14px/1 FontAwesome, serif; + font-size: 0.7em; + } + } + + .xdsoft_select { + background: #353945; + } + } + } + + .xdsoft_datepicker .xdsoft_calendar { + td, + th { + border-color: #4c505c; + background-color: #2a2e39; + } + + td.xdsoft_other_month, + td.xdsoft_disabled { + opacity: 0.8; + background: #a0cc75; + color: #000000; + } + + } +} + .heatmap-color-0 { background-color: #2d303b; } From e005b5f6e6c96fe0dc70ee9e0a171230b7adf732 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 28 Jun 2019 21:18:16 +0000 Subject: [PATCH 151/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index adafc609ca..ac4e0b1b19 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -861,7 +861,7 @@ issues.unlock_comment=hat diese Diskussion %s entsperrt issues.lock_confirm=Sperren issues.unlock_confirm=Entsperren issues.lock.notice_1=- Andere Nutzer können keine neuen Kommentare beisteuern. -issues.lock.notice_2=- Du und andere Mitarbeitet mit Zugriff auf dieses Repository können weiterhin für andere sichtbare Kommentare hinterlassen. +issues.lock.notice_2=- Du und andere Mitarbeiter mit Zugriff auf dieses Repository können weiterhin für andere sichtbare Kommentare hinterlassen. issues.lock.notice_3=- Du kannst die Diskussion jederzeit wieder entsperren. issues.unlock.notice_1=- Jeder wird wieder in der Lage sein, zu diesem Issue zu kommentieren. issues.unlock.notice_2=- Du kannst den Issue jederzeit wieder sperren. From 711f6dc9b0f77b35706bcb31a41b5f6a9e50d401 Mon Sep 17 00:00:00 2001 From: Cherrg Date: Sat, 29 Jun 2019 11:18:49 +0200 Subject: [PATCH 152/220] Fix 7303 - remove unnessesary buttons on archived repos (#7326) * archived repo - remove - open/close button on issue list - assigne person on issue list Signed-off-by: Michael Gnehr * archived repo - remove - comment field on issue view - lock/unlock issue conversation button from sidebar on issue view Signed-off-by: Michael Gnehr * archived repo - add 'compare commits' button to pull request + remove new pull request button from compare view as the route is still working, and there is no need to be hidden Signed-off-by: Michael Gnehr --- options/locale/locale_en-US.ini | 1 + templates/repo/diff/compare.tmpl | 2 ++ templates/repo/issue/list.tmpl | 8 ++++++++ templates/repo/issue/view_content.tmpl | 4 +++- templates/repo/issue/view_content/sidebar.tmpl | 2 +- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 97e4e3f91c..acaa98c3a2 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1866,6 +1866,7 @@ push_tag = pushed tag %[2]s to %[3]s delete_tag = deleted tag %[2]s from %[3]s delete_branch = deleted branch %[2]s from %[3]s compare_commits = Compare %d commits +compare_commits_general = Compare commits mirror_sync_push = synced commits to %[3]s at %[4]s from mirror mirror_sync_create = synced new reference %[2]s to %[3]s from mirror mirror_sync_delete = synced and deleted reference %[2]s at %[3]s from mirror diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index cc727422d7..877241fb39 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -56,9 +56,11 @@ {{.i18n.Tr "repo.pulls.has_pull_request" $.RepoLink $.RepoRelPath .PullRequest.Index | Safe}} {{else}} + {{if not .Repository.IsArchived}}
    + {{end}} diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 448ab1a757..3007c99106 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -17,6 +17,12 @@ {{.i18n.Tr "repo.pulls.new"}} {{end}} + {{else}} + {{if not .PageIsIssueList}} + + {{end}} {{end}}
    @@ -132,6 +138,7 @@ this one correctly, but not the other one. */}}
    + {{end}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index de9ffdb930..cb85c5be97 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -70,7 +70,7 @@ {{ template "repo/issue/view_content/pull". }} {{end}} {{if .IsSigned}} - {{ if or .IsRepoAdmin .IsRepoIssuesWriter (or (not .Issue.IsLocked)) }} + {{ if and (or .IsRepoAdmin .IsRepoIssuesWriter (or (not .Issue.IsLocked))) (not .Repository.IsArchived) }} {{else}} {{if .IsSigned}} + {{if .Repository.IsArchived}} + {{end}} {{else}}
    {{.i18n.Tr "repo.issues.sign_in_require_desc" .SignInLink | Safe}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 853f681474..e50ac0a4b1 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -336,7 +336,7 @@ {{end}}
    - {{ if .IsRepoAdmin }} + {{ if and .IsRepoAdmin (not .Repository.IsArchived) }}
    From 7bd0dc4975a442cd8b28616b9c530d313ed1b685 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 29 Jun 2019 09:19:47 +0000 Subject: [PATCH 153/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 56c2791ef0..8a5eeb72f0 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -31,7 +31,16 @@ twofa_scratch=Código de autenticación de doble factor de un sólo uso passcode=Contraseña u2f_insert_key=Inserte su clave de seguridad +u2f_sign_in=Presione el botón en su clave de seguridad. Si su clave de seguridad no tiene ningún botón, vuelva a insertarla. +u2f_press_button=Por favor, presione el botón en su clave de seguridad… u2f_use_twofa=Use un código de doble factor de su celular +u2f_error=No se pudo leer la clave de seguridad. +u2f_unsupported_browser=Su navegador no soporta claves de seguridad U2F. +u2f_error_1=Ha ocurrido un error desconocido. Por favor, inténtelo de nuevo. +u2f_error_2=Por favor, asegúrese de utilizar la URL correcta y cifrada (https://). +u2f_error_3=El servidor no pudo procesar su petición. +u2f_error_4=La clave de seguridad no está permitida para esta solicitud. Por favor, asegúrese de que la clave no está ya registrada. +u2f_error_5=Tiempo de espera máximo alcanzado antes de que su clave pudiese ser leída. Por favor, cargue la página y vuelva a intentarlo. u2f_reload=Recargar repository=Repositorio @@ -43,6 +52,7 @@ new_mirror=Nueva réplica new_fork=Nuevo fork de repositorio new_org=Nueva organización manage_org=Administrar organizaciones +admin_panel=Administración del sitio account_settings=Configuraciones de la cuenta settings=Configuraciones your_profile=Perfil @@ -61,38 +71,81 @@ issues=Incidencias cancel=Cancelar +write=Escribir +preview=Vista previa +loading=Cargando… [install] install=Instalación title=Configuración inicial +docker_helper=Si está ejecutando Gitea dentro de un contenedor Docker, por favor lea la documentación antes de realizar cambios en la configuración. +requite_db_desc=Gitea requiere una base de datos MySQL, PostgreSQL, MSSQL o SQLite3. db_title=Configuración de base de datos db_type=Tipo de base de datos host=Servidor user=Nombre de usuario password=Contraseña db_name=Nombre de la base de datos +db_helper=Nota para los usuarios de MySQL: por favor, utilice el motor de almacenamiento InnoDB y si utiliza "utf8mb4", su versión de InnoDB debe ser mayor que 5.6 . ssl_mode=SSL +charset=Juego de caracteres path=Ruta +sqlite_helper=Ruta del archivo de la base de datos SQLite3.
    Escriba una ruta de acceso absoluta si ejecuta Gitea como servicio. +err_empty_db_path=La ruta a la base de datos SQLite3 no puede estar vacía. +no_admin_and_disable_registration=No puede deshabilitar el auto-registro sin crear una cuenta de administrador. +err_empty_admin_password=La contraseña del administrador no puede estar vacía. +err_empty_admin_email=El correo electrónico del administrador no puede estar vacío. +err_admin_name_is_reserved=Nombre de usuario del administrador no es válido, el nombre de usuario está reservado +err_admin_name_pattern_not_allowed=Nombre de usuario del administrador no es válido, el nombre de usuario no está permitido +err_admin_name_is_invalid=Nombre de usuario del administrador no es válido general_title=Configuración general app_name=Título del Sitio app_name_helper=Puedes colocar aquí el nombre de tu empresa. repo_path=Ruta del repositorio de Raiz (Root) +repo_path_helper=Los repositorios Git se guardarán en este directorio. +lfs_path=Ruta raíz de Git LFS +lfs_path_helper=Los archivos almacenados con Git LFS se almacenarán en este directorio. Déjelo vacío para deshabilitarlo. run_user=Ejecutar como usuario +run_user_helper=Introduzca el nombre de usuario del sistema operativo sobre el que está ejecutando Gitea. Tenga en cuenta que este usuario debe tener acceso a la ruta a la raíz de los repositorios. domain=Dominio del servidor SSH +domain_helper=Dominio o dirección del host para URLs de clonación vía SSH. +ssh_port=Puerto de servidor SSH +ssh_port_helper=Número de puerto en el que está escuchando su servidor SSH. Déjelo vacío para deshabilitarlo. +http_port=Puerto de escucha HTTP de Gitea +http_port_helper=Número de puerto en el que escuchará el servidor web de Gitea. +app_url=URL base de Gitea +app_url_helper=Dirección base para URLs de clonación HTTP(S) y notificaciones de correo electrónico. log_root_path=Ruta del registro +log_root_path_helper=Archivos de registro se escribirán en este directorio. optional_title=Configuración opcional email_title=Configuración de Correo smtp_host=Servidor SMTP +smtp_from=Enviar correos electrónicos como +smtp_from_helper=Dirección de correo electrónico que utilizará Gitea. Introduzca una dirección de correo electrónico normal o utilice el formato "Nombre" . mailer_user=Nombre de usuario SMTP mailer_password=Contraseña SMTP +register_confirm=Requerir confirmación de correo electrónico para registrarse +mail_notify=Habilitar las notificaciones por correo electrónico +server_service_title=Configuración del servidor y de servicios de terceros offline_mode=Habilitar autenticación Local +offline_mode_popup=Deshabilitar redes de distribución de contenido de terceros y servir todos los recursos localmente. disable_gravatar=Desactivar Gravatar +disable_gravatar_popup=Desactivar el Gravatar y fuentes de avatares de terceros. Se utilizará un avatar por defecto a menos que un usuario suba un avatar localmente. +federated_avatar_lookup=Habilitar avatares federados federated_avatar_lookup_popup=Habilitar búsqueda de avatares federador para usar el servicio federado de código abierto basado en libravatar. +disable_registration=Deshabilitar auto-registro +disable_registration_popup=Deshabilitar auto-registro de usuarios. Sólo los administradores podrán crear nuevas cuentas de usuario. +allow_only_external_registration_popup=Permitir el registro únicamente a través de servicios externos +openid_signin=Habilitar el inicio de sesión con OpenID +openid_signin_popup=Habilitar el inicio de sesión de usuarios con OpenID. +openid_signup=Habilitar el auto-registro con OpenID +openid_signup_popup=Habilitar autorregistro de usuario basado en OpenID. enable_captcha=Activar CAPTCHA enable_captcha_popup=Requerir CAPTCHA para auto-registro de usuario. require_sign_in_view=Requerir inicio de sesión para ver páginas +require_sign_in_view_popup=Limitar el acceso a las páginas a usuarios que hayan iniciado sesión. Los visitantes solamente verán las páginas de inicio de sesión y registro. admin_password=Contraseña confirm_password=Confirmar Contraseña admin_email=Correo electrónico From 567e117df894c6d0307f4a026cafabb3220ac3d6 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Sat, 29 Jun 2019 06:44:17 -0400 Subject: [PATCH 154/220] Fixes #7238 - Annotated tag commit ID incorrect (#7321) * Fixes #7238 - Annotated tag commit ID incorrect * Fixes #7238 - Annotated tag commit ID incorrect --- modules/git/repo_tag.go | 7 ++++--- routers/api/v1/convert/convert.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index df49e9acd6..6d490af9b5 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -141,9 +141,10 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { fields := strings.Fields(tagRef) if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], TagPrefix) { name := fields[1][len(TagPrefix):] - // annotated tags show up twice, their name for commit ID is suffixed with ^{} - name = strings.TrimSuffix(name, "^{}") - return name, nil + // annotated tags show up twice, we should only return if is not the ^{} ref + if !strings.HasSuffix(name, "^{}") { + return name, nil + } } } } diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index 80c0811aed..f1cb23de43 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -281,7 +281,7 @@ func ToCommitUser(sig *git.Signature) *api.CommitUser { // ToCommitMeta convert a git.Tag to an api.CommitMeta func ToCommitMeta(repo *models.Repository, tag *git.Tag) *api.CommitMeta { return &api.CommitMeta{ - SHA: tag.ID.String(), + SHA: tag.Object.String(), // TODO: Add the /commits API endpoint and use it here (https://developer.github.com/v3/repos/commits/#get-a-single-commit) URL: util.URLJoin(repo.APIURL(), "git/commits", tag.ID.String()), } From 37b6ee178705cd7e545ca3a8ae00b1f6cee89083 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 29 Jun 2019 10:45:07 +0000 Subject: [PATCH 155/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 8a5eeb72f0..03f7c7437a 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -265,9 +265,16 @@ password_not_match=Las contraseñas no coinciden. username_been_taken=El nombre de usuario ya está en uso. user_not_exist=Este usuario no existe. +last_org_owner=No puedes eliminar al último usuario del equipo de 'propietarios'. Debe haber al menos un propietario en ningún equipo dado. +cannot_add_org_to_team=Una organización no puede ser añadida como miembro de un equipo. +invalid_ssh_key=No se puede verificar su clave SSH: %s +invalid_gpg_key=No se puede verificar su clave GPG: %s +unable_verify_ssh_key=No se puede verificar su clave SSH: compruebe si contiene errores. auth_failed=Autenticación fallo: %v +still_own_repo=Su cuenta posee uno o más repositorios; elimine o transfiera primero. +still_has_org=Su cuenta es miembro de una o más organizaciones; déjalas primero. target_branch_not_exist=La rama de destino no existe From d741316aaeecbafb82434fa9e57ab54e79cbb09d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 29 Jun 2019 19:46:25 +0800 Subject: [PATCH 156/220] add commitgraph support global default true when git version >= 2.18 (#7313) --- modules/git/git.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/git/git.go b/modules/git/git.go index bda39da918..fda6f45251 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -114,6 +114,18 @@ func Init() error { GitExecutable, "config", "--global", "core.quotepath", "false"); err != nil { return fmt.Errorf("Failed to execute 'git config --global core.quotepath false': %s", stderr) } + + if version.Compare(gitVersion, "2.18", ">=") { + if _, stderr, err := process.GetManager().Exec("git.Init(git config --global core.commitGraph true)", + GitExecutable, "config", "--global", "core.commitGraph", "true"); err != nil { + return fmt.Errorf("Failed to execute 'git config --global core.commitGraph true': %s", stderr) + } + + if _, stderr, err := process.GetManager().Exec("git.Init(git config --global gc.writeCommitGraph true)", + GitExecutable, "config", "--global", "gc.writeCommitGraph", "true"); err != nil { + return fmt.Errorf("Failed to execute 'git config --global gc.writeCommitGraph true': %s", stderr) + } + } return nil } From e463bdaf8d995d0b399c1848a780ac5aa8798f0d Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 29 Jun 2019 11:47:09 +0000 Subject: [PATCH 157/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 0b6b1f4e44..f99ae4bda5 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1721,6 +1721,10 @@ config.ssh_keygen_path=密钥生成器('ssh-keygen')路径 config.ssh_minimum_key_size_check=密钥最小长度检查 config.ssh_minimum_key_sizes=密钥最小长度限制 +config.lfs_config=LFS 配置 +config.lfs_enabled=启用 +config.lfs_content_path=LFS 内容存放目录 +config.lfs_http_auth_expiry=LFS HTTP 身份验证过期时间 config.db_config=数据库配置 config.db_type=类型 From 462284e2f5768cf04d71c7abd8c01eef20cff73d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 29 Jun 2019 21:38:22 +0800 Subject: [PATCH 158/220] Use batch insert on migrating repository to make the process faster (#7050) * Use batch insert on migrating repository to make the process faster * fix lint * fix tests * fix comments --- models/migrate.go | 131 ++++++---- modules/migrations/base/comment.go | 1 + modules/migrations/base/uploader.go | 14 +- modules/migrations/gitea.go | 359 ++++++++++++++++------------ modules/migrations/github.go | 1 + modules/migrations/github_test.go | 3 + modules/migrations/migrate.go | 76 ++++-- 7 files changed, 343 insertions(+), 242 deletions(-) diff --git a/models/migrate.go b/models/migrate.go index 54f9a3e24c..b30e6a9d1c 100644 --- a/models/migrate.go +++ b/models/migrate.go @@ -6,38 +6,58 @@ package models import "github.com/go-xorm/xorm" -// InsertIssue insert one issue to database -func InsertIssue(issue *Issue, labelIDs []int64) error { +// InsertMilestones creates milestones of repository. +func InsertMilestones(ms ...*Milestone) (err error) { + if len(ms) == 0 { + return nil + } + sess := x.NewSession() - if err := sess.Begin(); err != nil { + defer sess.Close() + if err = sess.Begin(); err != nil { return err } - if err := insertIssue(sess, issue, labelIDs); err != nil { + // to return the id, so we should not use batch insert + for _, m := range ms { + if _, err = sess.NoAutoTime().Insert(m); err != nil { + return err + } + } + + if _, err = sess.Exec("UPDATE `repository` SET num_milestones = num_milestones + ? WHERE id = ?", len(ms), ms[0].RepoID); err != nil { return err } return sess.Commit() } -func insertIssue(sess *xorm.Session, issue *Issue, labelIDs []int64) error { - if issue.MilestoneID > 0 { - sess.Incr("num_issues") - if issue.IsClosed { - sess.Incr("num_closed_issues") - } - if _, err := sess.ID(issue.MilestoneID).NoAutoTime().Update(new(Milestone)); err != nil { +// InsertIssues insert issues to database +func InsertIssues(issues ...*Issue) error { + sess := x.NewSession() + if err := sess.Begin(); err != nil { + return err + } + + for _, issue := range issues { + if err := insertIssue(sess, issue); err != nil { return err } } + return sess.Commit() +} + +func insertIssue(sess *xorm.Session, issue *Issue) error { if _, err := sess.NoAutoTime().Insert(issue); err != nil { return err } - var issueLabels = make([]IssueLabel, 0, len(labelIDs)) - for _, labelID := range labelIDs { + var issueLabels = make([]IssueLabel, 0, len(issue.Labels)) + var labelIDs = make([]int64, 0, len(issue.Labels)) + for _, label := range issue.Labels { issueLabels = append(issueLabels, IssueLabel{ IssueID: issue.ID, - LabelID: labelID, + LabelID: label.ID, }) + labelIDs = append(labelIDs, label.ID) } if _, err := sess.Insert(issueLabels); err != nil { return err @@ -61,12 +81,20 @@ func insertIssue(sess *xorm.Session, issue *Issue, labelIDs []int64) error { if issue.IsClosed { sess.Incr("num_closed_issues") } - if _, err := sess.In("id", labelIDs).Update(new(Label)); err != nil { + if _, err := sess.In("id", labelIDs).NoAutoTime().Update(new(Label)); err != nil { return err } if issue.MilestoneID > 0 { - if _, err := sess.ID(issue.MilestoneID).SetExpr("completeness", "num_closed_issues * 100 / num_issues").Update(new(Milestone)); err != nil { + sess.Incr("num_issues") + if issue.IsClosed { + sess.Incr("num_closed_issues") + } + + if _, err := sess.ID(issue.MilestoneID). + SetExpr("completeness", "num_closed_issues * 100 / num_issues"). + NoAutoTime(). + Update(new(Milestone)); err != nil { return err } } @@ -74,72 +102,73 @@ func insertIssue(sess *xorm.Session, issue *Issue, labelIDs []int64) error { return nil } -// InsertComment inserted a comment -func InsertComment(comment *Comment) error { +// InsertIssueComments inserts many comments of issues. +func InsertIssueComments(comments []*Comment) error { + if len(comments) == 0 { + return nil + } + + var issueIDs = make(map[int64]bool) + for _, comment := range comments { + issueIDs[comment.IssueID] = true + } + sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err } - if _, err := sess.NoAutoTime().Insert(comment); err != nil { + if _, err := sess.NoAutoTime().Insert(comments); err != nil { return err } - if _, err := sess.ID(comment.IssueID).Incr("num_comments").Update(new(Issue)); err != nil { - return err + for issueID := range issueIDs { + if _, err := sess.Exec("UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ?) WHERE id = ?", issueID, issueID); err != nil { + return err + } } return sess.Commit() } -// InsertPullRequest inserted a pull request -func InsertPullRequest(pr *PullRequest, labelIDs []int64) error { +// InsertPullRequests inserted pull requests +func InsertPullRequests(prs ...*PullRequest) error { sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err } - if err := insertIssue(sess, pr.Issue, labelIDs); err != nil { - return err - } - pr.IssueID = pr.Issue.ID - if _, err := sess.NoAutoTime().Insert(pr); err != nil { - return err + for _, pr := range prs { + if err := insertIssue(sess, pr.Issue); err != nil { + return err + } + pr.IssueID = pr.Issue.ID + if _, err := sess.NoAutoTime().Insert(pr); err != nil { + return err + } } + return sess.Commit() } -// MigrateRelease migrates release -func MigrateRelease(rel *Release) error { +// InsertReleases migrates release +func InsertReleases(rels ...*Release) error { sess := x.NewSession() if err := sess.Begin(); err != nil { return err } - var oriRel = Release{ - RepoID: rel.RepoID, - TagName: rel.TagName, - } - exist, err := sess.Get(&oriRel) - if err != nil { - return err - } - if !exist { + for _, rel := range rels { if _, err := sess.NoAutoTime().Insert(rel); err != nil { return err } - } else { - rel.ID = oriRel.ID - if _, err := sess.ID(rel.ID).Cols("target, title, note, is_tag, num_commits").Update(rel); err != nil { + + for i := 0; i < len(rel.Attachments); i++ { + rel.Attachments[i].ReleaseID = rel.ID + } + + if _, err := sess.NoAutoTime().Insert(rel.Attachments); err != nil { return err } } - for i := 0; i < len(rel.Attachments); i++ { - rel.Attachments[i].ReleaseID = rel.ID - } - - if _, err := sess.NoAutoTime().Insert(rel.Attachments); err != nil { - return err - } - return sess.Commit() } diff --git a/modules/migrations/base/comment.go b/modules/migrations/base/comment.go index 0ff0963f07..d89ec3a3f5 100644 --- a/modules/migrations/base/comment.go +++ b/modules/migrations/base/comment.go @@ -9,6 +9,7 @@ import "time" // Comment is a standard comment information type Comment struct { + IssueIndex int64 PosterName string PosterEmail string Created time.Time diff --git a/modules/migrations/base/uploader.go b/modules/migrations/base/uploader.go index eaeb10314a..096a8ab8f0 100644 --- a/modules/migrations/base/uploader.go +++ b/modules/migrations/base/uploader.go @@ -5,14 +5,14 @@ package base -// Uploader uploads all the informations +// Uploader uploads all the informations of one repository type Uploader interface { CreateRepo(repo *Repository, includeWiki bool) error - CreateMilestone(milestone *Milestone) error - CreateRelease(release *Release) error - CreateLabel(label *Label) error - CreateIssue(issue *Issue) error - CreateComment(issueNumber int64, comment *Comment) error - CreatePullRequest(pr *PullRequest) error + CreateMilestones(milestones ...*Milestone) error + CreateReleases(releases ...*Release) error + CreateLabels(labels ...*Label) error + CreateIssues(issues ...*Issue) error + CreateComments(comments ...*Comment) error + CreatePullRequests(prs ...*PullRequest) error Rollback() error } diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 4e930fa831..7d5a50d307 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -76,238 +76,280 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, includeWiki bool) return err } -// CreateMilestone creates milestone -func (g *GiteaLocalUploader) CreateMilestone(milestone *base.Milestone) error { - var deadline util.TimeStamp - if milestone.Deadline != nil { - deadline = util.TimeStamp(milestone.Deadline.Unix()) +// CreateMilestones creates milestones +func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) error { + var mss = make([]*models.Milestone, 0, len(milestones)) + for _, milestone := range milestones { + var deadline util.TimeStamp + if milestone.Deadline != nil { + deadline = util.TimeStamp(milestone.Deadline.Unix()) + } + if deadline == 0 { + deadline = util.TimeStamp(time.Date(9999, 1, 1, 0, 0, 0, 0, setting.UILocation).Unix()) + } + var ms = models.Milestone{ + RepoID: g.repo.ID, + Name: milestone.Title, + Content: milestone.Description, + IsClosed: milestone.State == "close", + DeadlineUnix: deadline, + } + if ms.IsClosed && milestone.Closed != nil { + ms.ClosedDateUnix = util.TimeStamp(milestone.Closed.Unix()) + } + mss = append(mss, &ms) } - if deadline == 0 { - deadline = util.TimeStamp(time.Date(9999, 1, 1, 0, 0, 0, 0, setting.UILocation).Unix()) - } - var ms = models.Milestone{ - RepoID: g.repo.ID, - Name: milestone.Title, - Content: milestone.Description, - IsClosed: milestone.State == "close", - DeadlineUnix: deadline, - } - if ms.IsClosed && milestone.Closed != nil { - ms.ClosedDateUnix = util.TimeStamp(milestone.Closed.Unix()) - } - err := models.NewMilestone(&ms) + err := models.InsertMilestones(mss...) if err != nil { return err } - g.milestones.Store(ms.Name, ms.ID) + + for _, ms := range mss { + g.milestones.Store(ms.Name, ms.ID) + } return nil } -// CreateLabel creates label -func (g *GiteaLocalUploader) CreateLabel(label *base.Label) error { - var lb = models.Label{ - RepoID: g.repo.ID, - Name: label.Name, - Description: label.Description, - Color: fmt.Sprintf("#%s", label.Color), +// CreateLabels creates labels +func (g *GiteaLocalUploader) CreateLabels(labels ...*base.Label) error { + var lbs = make([]*models.Label, 0, len(labels)) + for _, label := range labels { + lbs = append(lbs, &models.Label{ + RepoID: g.repo.ID, + Name: label.Name, + Description: label.Description, + Color: fmt.Sprintf("#%s", label.Color), + }) } - err := models.NewLabel(&lb) + + err := models.NewLabels(lbs...) if err != nil { return err } - g.labels.Store(lb.Name, lb.ID) + for _, lb := range lbs { + g.labels.Store(lb.Name, lb) + } return nil } -// CreateRelease creates release -func (g *GiteaLocalUploader) CreateRelease(release *base.Release) error { - var rel = models.Release{ - RepoID: g.repo.ID, - PublisherID: g.doer.ID, - TagName: release.TagName, - LowerTagName: strings.ToLower(release.TagName), - Target: release.TargetCommitish, - Title: release.Name, - Sha1: release.TargetCommitish, - Note: release.Body, - IsDraft: release.Draft, - IsPrerelease: release.Prerelease, - IsTag: false, - CreatedUnix: util.TimeStamp(release.Created.Unix()), - } - - // calc NumCommits - commit, err := g.gitRepo.GetCommit(rel.TagName) - if err != nil { - return fmt.Errorf("GetCommit: %v", err) - } - rel.NumCommits, err = commit.CommitsCount() - if err != nil { - return fmt.Errorf("CommitsCount: %v", err) - } - - for _, asset := range release.Assets { - var attach = models.Attachment{ - UUID: gouuid.NewV4().String(), - Name: asset.Name, - DownloadCount: int64(*asset.DownloadCount), - Size: int64(*asset.Size), - CreatedUnix: util.TimeStamp(asset.Created.Unix()), +// CreateReleases creates releases +func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { + var rels = make([]*models.Release, 0, len(releases)) + for _, release := range releases { + var rel = models.Release{ + RepoID: g.repo.ID, + PublisherID: g.doer.ID, + TagName: release.TagName, + LowerTagName: strings.ToLower(release.TagName), + Target: release.TargetCommitish, + Title: release.Name, + Sha1: release.TargetCommitish, + Note: release.Body, + IsDraft: release.Draft, + IsPrerelease: release.Prerelease, + IsTag: false, + CreatedUnix: util.TimeStamp(release.Created.Unix()), } - // download attachment - resp, err := http.Get(asset.URL) + // calc NumCommits + commit, err := g.gitRepo.GetCommit(rel.TagName) if err != nil { - return err + return fmt.Errorf("GetCommit: %v", err) } - defer resp.Body.Close() - - localPath := attach.LocalPath() - if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil { - return fmt.Errorf("MkdirAll: %v", err) - } - - fw, err := os.Create(localPath) + rel.NumCommits, err = commit.CommitsCount() if err != nil { - return fmt.Errorf("Create: %v", err) - } - defer fw.Close() - - if _, err := io.Copy(fw, resp.Body); err != nil { - return err + return fmt.Errorf("CommitsCount: %v", err) } - rel.Attachments = append(rel.Attachments, &attach) + for _, asset := range release.Assets { + var attach = models.Attachment{ + UUID: gouuid.NewV4().String(), + Name: asset.Name, + DownloadCount: int64(*asset.DownloadCount), + Size: int64(*asset.Size), + CreatedUnix: util.TimeStamp(asset.Created.Unix()), + } + + // download attachment + resp, err := http.Get(asset.URL) + if err != nil { + return err + } + defer resp.Body.Close() + + localPath := attach.LocalPath() + if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil { + return fmt.Errorf("MkdirAll: %v", err) + } + + fw, err := os.Create(localPath) + if err != nil { + return fmt.Errorf("Create: %v", err) + } + defer fw.Close() + + if _, err := io.Copy(fw, resp.Body); err != nil { + return err + } + + rel.Attachments = append(rel.Attachments, &attach) + } + + rels = append(rels, &rel) } - - return models.MigrateRelease(&rel) + return models.InsertReleases(rels...) } -// CreateIssue creates issue -func (g *GiteaLocalUploader) CreateIssue(issue *base.Issue) error { - var labelIDs []int64 - for _, label := range issue.Labels { - id, ok := g.labels.Load(label.Name) - if !ok { - return fmt.Errorf("Label %s missing when create issue", label.Name) +// CreateIssues creates issues +func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { + var iss = make([]*models.Issue, 0, len(issues)) + for _, issue := range issues { + var labels []*models.Label + for _, label := range issue.Labels { + lb, ok := g.labels.Load(label.Name) + if ok { + labels = append(labels, lb.(*models.Label)) + } } - labelIDs = append(labelIDs, id.(int64)) - } - var milestoneID int64 - if issue.Milestone != "" { - milestone, ok := g.milestones.Load(issue.Milestone) - if !ok { - return fmt.Errorf("Milestone %s missing when create issue", issue.Milestone) + var milestoneID int64 + if issue.Milestone != "" { + milestone, ok := g.milestones.Load(issue.Milestone) + if ok { + milestoneID = milestone.(int64) + } } - milestoneID = milestone.(int64) + + var is = models.Issue{ + RepoID: g.repo.ID, + Repo: g.repo, + Index: issue.Number, + PosterID: g.doer.ID, + Title: issue.Title, + Content: issue.Content, + IsClosed: issue.State == "closed", + IsLocked: issue.IsLocked, + MilestoneID: milestoneID, + Labels: labels, + CreatedUnix: util.TimeStamp(issue.Created.Unix()), + } + if issue.Closed != nil { + is.ClosedUnix = util.TimeStamp(issue.Closed.Unix()) + } + // TODO: add reactions + iss = append(iss, &is) } - var is = models.Issue{ - RepoID: g.repo.ID, - Repo: g.repo, - Index: issue.Number, - PosterID: g.doer.ID, - Title: issue.Title, - Content: issue.Content, - IsClosed: issue.State == "closed", - IsLocked: issue.IsLocked, - MilestoneID: milestoneID, - CreatedUnix: util.TimeStamp(issue.Created.Unix()), - } - if issue.Closed != nil { - is.ClosedUnix = util.TimeStamp(issue.Closed.Unix()) - } - - err := models.InsertIssue(&is, labelIDs) + err := models.InsertIssues(iss...) if err != nil { return err } - g.issues.Store(issue.Number, is.ID) - // TODO: add reactions - return err + for _, is := range iss { + g.issues.Store(is.Index, is.ID) + } + return nil } -// CreateComment creates comment -func (g *GiteaLocalUploader) CreateComment(issueNumber int64, comment *base.Comment) error { - var issueID int64 - if issueIDStr, ok := g.issues.Load(issueNumber); !ok { - issue, err := models.GetIssueByIndex(g.repo.ID, issueNumber) +// CreateComments creates comments of issues +func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { + var cms = make([]*models.Comment, 0, len(comments)) + for _, comment := range comments { + var issueID int64 + if issueIDStr, ok := g.issues.Load(comment.IssueIndex); !ok { + issue, err := models.GetIssueByIndex(g.repo.ID, comment.IssueIndex) + if err != nil { + return err + } + issueID = issue.ID + g.issues.Store(comment.IssueIndex, issueID) + } else { + issueID = issueIDStr.(int64) + } + + cms = append(cms, &models.Comment{ + IssueID: issueID, + Type: models.CommentTypeComment, + PosterID: g.doer.ID, + Content: comment.Content, + CreatedUnix: util.TimeStamp(comment.Created.Unix()), + }) + + // TODO: Reactions + } + + return models.InsertIssueComments(cms) +} + +// CreatePullRequests creates pull requests +func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error { + var gprs = make([]*models.PullRequest, 0, len(prs)) + for _, pr := range prs { + gpr, err := g.newPullRequest(pr) if err != nil { return err } - issueID = issue.ID - g.issues.Store(issueNumber, issueID) - } else { - issueID = issueIDStr.(int64) + gprs = append(gprs, gpr) } - - var cm = models.Comment{ - IssueID: issueID, - Type: models.CommentTypeComment, - PosterID: g.doer.ID, - Content: comment.Content, - CreatedUnix: util.TimeStamp(comment.Created.Unix()), + if err := models.InsertPullRequests(gprs...); err != nil { + return err } - err := models.InsertComment(&cm) - // TODO: Reactions - return err + for _, pr := range gprs { + g.issues.Store(pr.Issue.Index, pr.Issue.ID) + } + return nil } -// CreatePullRequest creates pull request -func (g *GiteaLocalUploader) CreatePullRequest(pr *base.PullRequest) error { - var labelIDs []int64 +func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullRequest, error) { + var labels []*models.Label for _, label := range pr.Labels { - id, ok := g.labels.Load(label.Name) - if !ok { - return fmt.Errorf("Label %s missing when create issue", label.Name) + lb, ok := g.labels.Load(label.Name) + if ok { + labels = append(labels, lb.(*models.Label)) } - labelIDs = append(labelIDs, id.(int64)) } var milestoneID int64 if pr.Milestone != "" { milestone, ok := g.milestones.Load(pr.Milestone) - if !ok { - return fmt.Errorf("Milestone %s missing when create issue", pr.Milestone) + if ok { + milestoneID = milestone.(int64) } - milestoneID = milestone.(int64) } // download patch file resp, err := http.Get(pr.PatchURL) if err != nil { - return err + return nil, err } defer resp.Body.Close() pullDir := filepath.Join(g.repo.RepoPath(), "pulls") if err = os.MkdirAll(pullDir, os.ModePerm); err != nil { - return err + return nil, err } f, err := os.Create(filepath.Join(pullDir, fmt.Sprintf("%d.patch", pr.Number))) if err != nil { - return err + return nil, err } defer f.Close() _, err = io.Copy(f, resp.Body) if err != nil { - return err + return nil, err } // set head information pullHead := filepath.Join(g.repo.RepoPath(), "refs", "pull", fmt.Sprintf("%d", pr.Number)) if err := os.MkdirAll(pullHead, os.ModePerm); err != nil { - return err + return nil, err } p, err := os.Create(filepath.Join(pullHead, "head")) if err != nil { - return err + return nil, err } defer p.Close() _, err = p.WriteString(pr.Head.SHA) if err != nil { - return err + return nil, err } var head = "unknown repository" @@ -333,16 +375,16 @@ func (g *GiteaLocalUploader) CreatePullRequest(pr *base.PullRequest) error { } else { headBranch := filepath.Join(g.repo.RepoPath(), "refs", "heads", pr.Head.OwnerName, pr.Head.Ref) if err := os.MkdirAll(filepath.Dir(headBranch), os.ModePerm); err != nil { - return err + return nil, err } b, err := os.Create(headBranch) if err != nil { - return err + return nil, err } defer b.Close() _, err = b.WriteString(pr.Head.SHA) if err != nil { - return err + return nil, err } head = pr.Head.OwnerName + "/" + pr.Head.Ref } @@ -373,6 +415,7 @@ func (g *GiteaLocalUploader) CreatePullRequest(pr *base.PullRequest) error { IsPull: true, IsClosed: pr.State == "closed", IsLocked: pr.IsLocked, + Labels: labels, CreatedUnix: util.TimeStamp(pr.Created.Unix()), }, } @@ -389,7 +432,7 @@ func (g *GiteaLocalUploader) CreatePullRequest(pr *base.PullRequest) error { // TODO: reactions // TODO: assignees - return models.InsertPullRequest(&pullRequest, labelIDs) + return &pullRequest, nil } // Rollback when migrating failed, this will rollback all the changes. diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 6847787ace..e6b532df9c 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -358,6 +358,7 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er reactions = convertGithubReactions(comment.Reactions) } allComments = append(allComments, &base.Comment{ + IssueIndex: issueNumber, PosterName: *comment.User.Login, PosterEmail: email, Content: *comment.Body, diff --git a/modules/migrations/github_test.go b/modules/migrations/github_test.go index c14292ecc6..700183bdc1 100644 --- a/modules/migrations/github_test.go +++ b/modules/migrations/github_test.go @@ -269,6 +269,7 @@ func TestGitHubDownloadRepo(t *testing.T) { assert.EqualValues(t, 35, len(comments)) assert.EqualValues(t, []*base.Comment{ { + IssueIndex: 6, PosterName: "bkcsoft", Created: time.Date(2016, 11, 02, 18, 59, 48, 0, time.UTC), Content: `I would prefer a solution that is in the backend, unless it's required to have it update without reloading. Unfortunately I can't seem to find anything that does that :unamused: @@ -286,6 +287,7 @@ Also this would _require_ caching, since it will fetch huge amounts of data from }, }, { + IssueIndex: 6, PosterName: "joubertredrat", Created: time.Date(2016, 11, 02, 19, 16, 56, 0, time.UTC), Content: `Yes, this plugin build on front-end, with backend I don't know too, but we can consider make component for this. @@ -303,6 +305,7 @@ In my case I use ajax to get data, but build on frontend anyway }, }, { + IssueIndex: 6, PosterName: "xinity", Created: time.Date(2016, 11, 03, 13, 04, 56, 0, time.UTC), Content: `following @bkcsoft retention strategy in cache is a must if we don't want gitea to waste ressources. diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 4b1229f949..3a4e6b2dbe 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -91,10 +91,8 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - for _, milestone := range milestones { - if err := uploader.CreateMilestone(milestone); err != nil { - return err - } + if err := uploader.CreateMilestones(milestones...); err != nil { + return err } } @@ -105,10 +103,8 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - for _, label := range labels { - if err := uploader.CreateLabel(label); err != nil { - return err - } + if err := uploader.CreateLabels(labels...); err != nil { + return err } } @@ -119,10 +115,8 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - for _, release := range releases { - if err := uploader.CreateRelease(release); err != nil { - return err - } + if err := uploader.CreateReleases(releases...); err != nil { + return err } } @@ -137,15 +131,18 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if !opts.IgnoreIssueAuthor { issue.Content = fmt.Sprintf("Author: @%s \n\n%s", issue.PosterName, issue.Content) } + } - if err := uploader.CreateIssue(issue); err != nil { - return err - } + if err := uploader.CreateIssues(issues...); err != nil { + return err + } - if !opts.Comments { - continue - } + if !opts.Comments { + continue + } + var allComments = make([]*base.Comment, 0, 100) + for _, issue := range issues { comments, err := downloader.GetComments(issue.Number) if err != nil { return err @@ -154,9 +151,20 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if !opts.IgnoreIssueAuthor { comment.Content = fmt.Sprintf("Author: @%s \n\n%s", comment.PosterName, comment.Content) } - if err := uploader.CreateComment(issue.Number, comment); err != nil { + } + allComments = append(allComments, comments...) + + if len(allComments) >= 100 { + if err := uploader.CreateComments(allComments...); err != nil { return err } + allComments = make([]*base.Comment, 0, 100) + } + } + + if len(allComments) > 0 { + if err := uploader.CreateComments(allComments...); err != nil { + return err } } @@ -178,13 +186,17 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if !opts.IgnoreIssueAuthor { pr.Content = fmt.Sprintf("Author: @%s \n\n%s", pr.PosterName, pr.Content) } - if err := uploader.CreatePullRequest(pr); err != nil { - return err - } - if !opts.Comments { - continue - } + } + if err := uploader.CreatePullRequests(prs...); err != nil { + return err + } + if !opts.Comments { + continue + } + + var allComments = make([]*base.Comment, 0, 100) + for _, pr := range prs { comments, err := downloader.GetComments(pr.Number) if err != nil { return err @@ -193,11 +205,23 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if !opts.IgnoreIssueAuthor { comment.Content = fmt.Sprintf("Author: @%s \n\n%s", comment.PosterName, comment.Content) } - if err := uploader.CreateComment(pr.Number, comment); err != nil { + } + + allComments = append(allComments, comments...) + + if len(allComments) >= 100 { + if err := uploader.CreateComments(allComments...); err != nil { return err } + allComments = make([]*base.Comment, 0, 100) } } + if len(allComments) > 0 { + if err := uploader.CreateComments(allComments...); err != nil { + return err + } + } + if len(prs) < 100 { break } From 002b597c1f87cd5c69d32053a62f57c08d48d3ee Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Sat, 29 Jun 2019 11:19:24 -0400 Subject: [PATCH 159/220] Fixes #7152 - Allow create/update/delete message to be empty, use default message (#7324) * Fixes #7152 - Allow create/update/delete message to be empty, use default message * Linting fix * Fix to delete integration tests --- integrations/api_repo_file_create_test.go | 15 +++++++- integrations/api_repo_file_delete_test.go | 16 ++++++++- integrations/api_repo_file_update_test.go | 36 +++++++++++++++++-- integrations/repofiles_delete_test.go | 44 ++++++++++++----------- modules/repofiles/delete.go | 5 +++ modules/structs/repo_file.go | 2 +- routers/api/v1/repo/file.go | 13 +++++++ 7 files changed, 104 insertions(+), 27 deletions(-) diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index 973ed9dfa5..b00583c191 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -28,7 +28,7 @@ func getCreateFileOptions() api.CreateFileOptions { FileOptions: api.FileOptions{ BranchName: "master", NewBranchName: "master", - Message: "Creates new/file.txt", + Message: "Making this new file new/file.txt", Author: api.Identity{ Name: "John Doe", Email: "johndoe@example.com", @@ -150,6 +150,19 @@ func TestAPICreateFile(t *testing.T) { assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) + assert.EqualValues(t, createFileOptions.Message+"\n", fileResponse.Commit.Message) + + // Test creating a file without a message + createFileOptions = getCreateFileOptions() + createFileOptions.Message = "" + fileID++ + treePath = fmt.Sprintf("new/file%d.txt", fileID) + url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2) + req = NewRequestWithJSON(t, "POST", url, &createFileOptions) + resp = session.MakeRequest(t, req, http.StatusCreated) + DecodeJSON(t, resp, &fileResponse) + expectedMessage := "Add '" + treePath + "'\n" + assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message) // Test trying to create a file that already exists, should fail createFileOptions = getCreateFileOptions() diff --git a/integrations/api_repo_file_delete_test.go b/integrations/api_repo_file_delete_test.go index 2f5f9028a8..59b3ff91b6 100644 --- a/integrations/api_repo_file_delete_test.go +++ b/integrations/api_repo_file_delete_test.go @@ -23,7 +23,7 @@ func getDeleteFileOptions() *api.DeleteFileOptions { FileOptions: api.FileOptions{ BranchName: "master", NewBranchName: "master", - Message: "Updates new/file.txt", + Message: "Removing the file new/file.txt", Author: api.Identity{ Name: "John Doe", Email: "johndoe@example.com", @@ -89,6 +89,20 @@ func TestAPIDeleteFile(t *testing.T) { DecodeJSON(t, resp, &fileResponse) assert.NotNil(t, fileResponse) assert.Nil(t, fileResponse.Content) + assert.EqualValues(t, deleteFileOptions.Message+"\n", fileResponse.Commit.Message) + + // Test deleting file without a message + fileID++ + treePath = fmt.Sprintf("delete/file%d.txt", fileID) + createFile(user2, repo1, treePath) + deleteFileOptions = getDeleteFileOptions() + deleteFileOptions.Message = "" + url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2) + req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &fileResponse) + expectedMessage := "Delete '" + treePath + "'\n" + assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message) // Test deleting a file with the wrong SHA fileID++ diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index 90fecf59d0..17fa2adb26 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -25,8 +25,23 @@ func getUpdateFileOptions() *api.UpdateFileOptions { content := "This is updated text" contentEncoded := base64.StdEncoding.EncodeToString([]byte(content)) return &api.UpdateFileOptions{ - DeleteFileOptions: *getDeleteFileOptions(), - Content: contentEncoded, + DeleteFileOptions: api.DeleteFileOptions{ + FileOptions: api.FileOptions{ + BranchName: "master", + NewBranchName: "master", + Message: "My update of new/file.txt", + Author: api.Identity{ + Name: "John Doe", + Email: "johndoe@example.com", + }, + Committer: api.Identity{ + Name: "Jane Doe", + Email: "janedoe@example.com", + }, + }, + SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885", + }, + Content: contentEncoded, } } @@ -67,7 +82,7 @@ func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileRespon Email: "johndoe@example.com", }, }, - Message: "Updates README.md\n", + Message: "My update of README.md\n", }, Verification: &api.PayloadCommitVerification{ Verified: false, @@ -140,6 +155,7 @@ func TestAPIUpdateFile(t *testing.T) { assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) + assert.EqualValues(t, updateFileOptions.Message+"\n", fileResponse.Commit.Message) // Test updating a file and renaming it updateFileOptions = getUpdateFileOptions() @@ -160,6 +176,20 @@ func TestAPIUpdateFile(t *testing.T) { assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) + // Test updating a file without a message + updateFileOptions = getUpdateFileOptions() + updateFileOptions.Message = "" + updateFileOptions.BranchName = repo1.DefaultBranch + fileID++ + treePath = fmt.Sprintf("update/file%d.txt", fileID) + createFile(user2, repo1, treePath) + url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2) + req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &fileResponse) + expectedMessage := "Update '" + treePath + "'\n" + assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message) + // Test updating a file with the wrong SHA fileID++ treePath = fmt.Sprintf("update/file%d.txt", fileID) diff --git a/integrations/repofiles_delete_test.go b/integrations/repofiles_delete_test.go index c3bb18ec9c..f4cb4510be 100644 --- a/integrations/repofiles_delete_test.go +++ b/integrations/repofiles_delete_test.go @@ -24,40 +24,32 @@ func getDeleteRepoFileOptions(repo *models.Repository) *repofiles.DeleteRepoFile TreePath: "README.md", Message: "Deletes README.md", SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", - Author: nil, - Committer: nil, + Author: &repofiles.IdentityOptions{ + Name: "Bob Smith", + Email: "bob@smith.com", + }, + Committer: nil, } } func getExpectedDeleteFileResponse(u *url.URL) *api.FileResponse { + // Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined return &api.FileResponse{ Content: nil, Commit: &api.FileCommitResponse{ - CommitMeta: api.CommitMeta{ - URL: u.String() + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", - SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", - }, - HTMLURL: u.String() + "user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d", Author: &api.CommitUser{ Identity: api.Identity{ - Name: "user1", - Email: "address1@example.com", + Name: "Bob Smith", + Email: "bob@smith.com", }, - Date: "2017-03-19T20:47:59Z", }, Committer: &api.CommitUser{ Identity: api.Identity{ - Name: "Ethan Koenig", - Email: "ethantkoenig@gmail.com", + Name: "Bob Smith", + Email: "bob@smith.com", }, - Date: "2017-03-19T20:47:59Z", - }, - Parents: []*api.CommitMeta{}, - Message: "Initial commit\n", - Tree: &api.CommitMeta{ - URL: u.String() + "api/v1/repos/user2/repo1/git/trees/2a2f1d4670728a2e10049e345bd7a276468beab6", - SHA: "2a2f1d4670728a2e10049e345bd7a276468beab6", }, + Message: "Deletes README.md\n", }, Verification: &api.PayloadCommitVerification{ Verified: false, @@ -89,7 +81,12 @@ func testDeleteRepoFile(t *testing.T, u *url.URL) { fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) assert.Nil(t, err) expectedFileResponse := getExpectedDeleteFileResponse(u) - assert.EqualValues(t, expectedFileResponse, fileResponse) + assert.NotNil(t, fileResponse) + assert.Nil(t, fileResponse.Content) + assert.EqualValues(t, expectedFileResponse.Commit.Message, fileResponse.Commit.Message) + assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, fileResponse.Commit.Author.Identity) + assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, fileResponse.Commit.Committer.Identity) + assert.EqualValues(t, expectedFileResponse.Verification, fileResponse.Verification) }) t.Run("Verify README.md has been deleted", func(t *testing.T) { @@ -124,7 +121,12 @@ func testDeleteRepoFileWithoutBranchNames(t *testing.T, u *url.URL) { fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) assert.Nil(t, err) expectedFileResponse := getExpectedDeleteFileResponse(u) - assert.EqualValues(t, expectedFileResponse, fileResponse) + assert.NotNil(t, fileResponse) + assert.Nil(t, fileResponse.Content) + assert.EqualValues(t, expectedFileResponse.Commit.Message, fileResponse.Commit.Message) + assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, fileResponse.Commit.Author.Identity) + assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, fileResponse.Commit.Committer.Identity) + assert.EqualValues(t, expectedFileResponse.Verification, fileResponse.Verification) }) } diff --git a/modules/repofiles/delete.go b/modules/repofiles/delete.go index 91910fa860..3d9b06b1c1 100644 --- a/modules/repofiles/delete.go +++ b/modules/repofiles/delete.go @@ -198,6 +198,11 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo return nil, fmt.Errorf("PushUpdate: %v", err) } + commit, err = t.GetCommit(commitHash) + if err != nil { + return nil, err + } + file, err := GetFileResponseFromCommit(repo, commit, opts.NewBranch, treePath) if err != nil { return nil, err diff --git a/modules/structs/repo_file.go b/modules/structs/repo_file.go index c447d26724..e5be9ce108 100644 --- a/modules/structs/repo_file.go +++ b/modules/structs/repo_file.go @@ -8,7 +8,7 @@ package structs // FileOptions options for all file APIs type FileOptions struct { // message (optional) for the commit of this file. if not supplied, a default message will be used - Message string `json:"message" binding:"Required"` + Message string `json:"message"` // branch (optional) to base this file from. if not given, the default branch is used BranchName string `json:"branch"` // new_branch (optional) will make a new branch from `branch` before creating the file diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 20f80f37f4..d510756283 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -204,6 +204,11 @@ func CreateFile(ctx *context.APIContext, apiOpts api.CreateFileOptions) { Email: apiOpts.Author.Email, }, } + + if opts.Message == "" { + opts.Message = ctx.Tr("repo.editor.add", opts.TreePath) + } + if fileResponse, err := createOrUpdateFile(ctx, opts); err != nil { ctx.Error(http.StatusInternalServerError, "CreateFile", err) } else { @@ -264,6 +269,10 @@ func UpdateFile(ctx *context.APIContext, apiOpts api.UpdateFileOptions) { }, } + if opts.Message == "" { + opts.Message = ctx.Tr("repo.editor.update", opts.TreePath) + } + if fileResponse, err := createOrUpdateFile(ctx, opts); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateFile", err) } else { @@ -346,6 +355,10 @@ func DeleteFile(ctx *context.APIContext, apiOpts api.DeleteFileOptions) { }, } + if opts.Message == "" { + opts.Message = ctx.Tr("repo.editor.delete", opts.TreePath) + } + if fileResponse, err := repofiles.DeleteRepoFile(ctx.Repo.Repository, ctx.User, opts); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteFile", err) } else { From 738285a4aac5df2e60f4038aa79be3e9fe921bdb Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 29 Jun 2019 15:22:08 +0000 Subject: [PATCH 160/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 36 +++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 03f7c7437a..2827a2d854 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -27,8 +27,8 @@ password=Contraseña re_type=Vuelva a escribir la contraseña captcha=CAPTCHA twofa=Autenticación de doble factor -twofa_scratch=Código de autenticación de doble factor de un sólo uso -passcode=Contraseña +twofa_scratch=Código de respaldo +passcode=Código de acceso u2f_insert_key=Inserte su clave de seguridad u2f_sign_in=Presione el botón en su clave de seguridad. Si su clave de seguridad no tiene ningún botón, vuelva a insertarla. @@ -146,11 +146,15 @@ enable_captcha=Activar CAPTCHA enable_captcha_popup=Requerir CAPTCHA para auto-registro de usuario. require_sign_in_view=Requerir inicio de sesión para ver páginas require_sign_in_view_popup=Limitar el acceso a las páginas a usuarios que hayan iniciado sesión. Los visitantes solamente verán las páginas de inicio de sesión y registro. +admin_setting_desc=Crear una cuenta de administrador es opcional. El primer usuario registrado se convertirá automáticamente en administrador. +admin_title=Configuración de la cuenta de administrador +admin_name=Nombre de usuario del administrador admin_password=Contraseña confirm_password=Confirmar Contraseña admin_email=Correo electrónico install_btn_confirm=Instalar Gitea test_git_failed=Fallo al probar el comando 'git': %v +sqlite3_not_available=Esta versión de Gitea no soporta SQLite3. Por favor, descarga la versión binaria oficial de %s (no la versión 'gobuild'). invalid_db_setting=La configuración de la base de datos no es válida: %v invalid_repo_path=La ruta de la raíz del repositorio no es válida: %v run_user_not_match=El nombre de usuario 'ejecutar como' no es el nombre actual de usuario: %s -> %s @@ -165,6 +169,7 @@ default_allow_create_organization_popup=Permitir que las nuevas cuentas de usuar default_enable_timetracking=Activar el seguimiento de tiempo por defecto default_enable_timetracking_popup=Activar el seguimiento de tiempo para nuevos repositorios por defecto. no_reply_address=Dominio de correos electrónicos ocultos +no_reply_address_helper=Nombre de dominio para usuarios con dirección de correo electrónico oculta. Por ejemplo, el usuario 'joe' quedará registrado en Git como 'joe@noreply.example.org' si el dominio de correo electrónico oculto se establece a 'noreply.example.org'. [home] uname_holder=Nombre de usuario o correo electrónico @@ -176,6 +181,7 @@ collaborative_repos=Repositorios colaborativos my_orgs=Mis organizaciones my_mirrors=Mis réplicas view_home=Ver %s +search_repos=Buscar un repositorio… issues.in_your_repos=En tus repositorios @@ -201,21 +207,37 @@ remember_me=Recuérdame forgot_password_title=He olvidado mi contraseña forgot_password=¿Has olvidado tu contraseña? sign_up_now=¿Necesitas una cuenta? Regístrate ahora. +sign_up_successful=La cuenta se ha creado correctamente. confirmation_mail_sent_prompt=Un nuevo correo de confirmación se ha enviado a %s. Comprueba tu bandeja de entrada en las siguientes %s para completar el registro. +must_change_password=Actualizar su contraseña +allow_password_change=Obligar al usuario a cambiar la contraseña (recomendado) +reset_password_mail_sent_prompt=Un correo de confirmación se ha enviado a %s. Compruebe su bandeja de entrada en las siguientes %s para completar el proceso de recuperación de la cuenta. active_your_account=Activa tu cuenta +account_activated=La cuenta ha sido activada prohibit_login=Ingreso prohibido prohibit_login_desc=Su cuenta tiene prohibido ingresar al sistema. Por favor contacte con el administrador del sistema. resent_limit_prompt=Ya ha solicitado recientemente un correo de activación. Por favor, espere 3 minutos y vuelva a intentarlo. has_unconfirmed_mail=Hola %s, tu correo electrónico (%s) no está confirmado. Si no has recibido un correo de confirmación o necesitas que lo enviemos de nuevo, por favor, haz click en el siguiente botón. resend_mail=Haz click aquí para reenviar tu correo electrónico de activación email_not_associate=Esta dirección de correo electrónico no esta asociada a ninguna cuenta. +send_reset_mail=Enviar correo de recuperación de cuenta +reset_password=Recuperación de cuenta invalid_code=Su código de confirmación no es válido o ha caducado. +reset_password_helper=Recuperar cuenta +reset_password_wrong_user=Has iniciado sesión como %s, pero el enlace de recuperación de cuenta es para %s +password_too_short=La longitud de la contraseña no puede ser menor a %d caracteres. non_local_account=Los usuarios no locales no pueden actualizar su contraseña a través de la interfaz web de Gitea. verify=Verificar -twofa_scratch_used=Ya has utilizado el código. Has sido redirigido a la página de configuración de doble factor poder retirar la inscripción del dispositivo o generar un nuevo código. -twofa_scratch_token_incorrect=El código cero es incorrecto. +scratch_code=Código de respaldo +use_scratch_code=Usar un código de respaldo +twofa_scratch_used=Ya ha utilizado su código de respaldo. Ha sido redirigido a la página de configuración de doble factor poder retirar la inscripción del dispositivo o generar un nuevo código de respaldo. +twofa_passcode_incorrect=Su código de acceso es incorrecta. Si extravió el dispositivo, use su código de respaldo para iniciar sesión. +twofa_scratch_token_incorrect=El código de respaldo es incorrecto. login_userpass=Iniciar sesión login_openid=OpenID +oauth_signup_tab=Registrar nueva cuenta +oauth_signup_title=Añadir email y contraseña (para la recuperación de la cuenta) +oauth_signup_submit=Completar Cuenta openid_connect_submit=Conectar openid_connect_title=Accede con una cuenta existente openid_register_title=Crear una nueva cuenta @@ -357,9 +379,15 @@ delete_token=Eliminar twofa_is_enrolled=Su cuenta actualmente está registrada en la autenticación de doble factor. twofa_not_enrolled=Tu cuenta no está actualmente inscrita en la autenticación de doble factor. +twofa_scratch_token_regenerate=Regenerar código de respaldo +twofa_scratch_token_regenerated=Su código de respaldo ahora es %s. Guárdelo en un lugar seguro. +regenerate_scratch_token_desc=Si extravió su código de respaldo, o ya lo usó para iniciar sesión, puede restablecerlo aquí. twofa_disabled=La autenticación de doble factor ha sido deshabilitada. scan_this_image=Analiza esta imagen con la aplicación de autenticación: or_enter_secret=O introduzca el secreto: %s +then_enter_passcode=E introduzca el código de acceso mostrado en la aplicación: +passcode_invalid=El código de acceso es incorrecto. Vuelva a intentarlo. +twofa_enrolled=Su cuenta ha sido inscrita en la autenticación de doble factor. ¡Guarde su código de respaldo (%s) en un lugar seguro, ya que sólo se muestra una vez! From cd96dee9822c8b744526ba862fd8b5ec0e2c30ff Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Sat, 29 Jun 2019 16:51:10 -0400 Subject: [PATCH 161/220] Fixes #7292 - API File Contents bug (#7301) --- integrations/api_repo_file_content_test.go | 117 ----------- integrations/api_repo_file_create_test.go | 32 +-- integrations/api_repo_file_update_test.go | 38 ++-- .../api_repo_get_contents_list_test.go | 156 ++++++++++++++ integrations/api_repo_get_contents_test.go | 157 ++++++++++++++ integrations/repofiles_update_test.go | 79 ++++--- modules/git/blob.go | 13 ++ modules/git/repo_object.go | 17 ++ modules/repofiles/content.go | 189 ++++++++++++++--- modules/repofiles/content_test.go | 156 +++++++++++--- modules/repofiles/file.go | 4 +- modules/repofiles/file_test.go | 35 ++-- modules/structs/repo_file.go | 41 ++-- routers/api/v1/api.go | 3 +- routers/api/v1/repo/file.go | 53 ++++- routers/api/v1/swagger/repo.go | 15 +- templates/swagger/v1_json.tmpl | 193 ++++++++++++------ 17 files changed, 963 insertions(+), 335 deletions(-) delete mode 100644 integrations/api_repo_file_content_test.go create mode 100644 integrations/api_repo_get_contents_list_test.go create mode 100644 integrations/api_repo_get_contents_test.go diff --git a/integrations/api_repo_file_content_test.go b/integrations/api_repo_file_content_test.go deleted file mode 100644 index 7a6025d423..0000000000 --- a/integrations/api_repo_file_content_test.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2019 The Gitea 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 integrations - -import ( - "net/http" - "net/url" - "path/filepath" - "testing" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - - "github.com/stretchr/testify/assert" -) - -func getExpectedFileContentResponseForFileContents(branch string) *api.FileContentResponse { - treePath := "README.md" - sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f" - return &api.FileContentResponse{ - Name: filepath.Base(treePath), - Path: treePath, - SHA: sha, - Size: 30, - URL: setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath, - HTMLURL: setting.AppURL + "user2/repo1/blob/" + branch + "/" + treePath, - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha, - DownloadURL: setting.AppURL + "user2/repo1/raw/branch/" + branch + "/" + treePath, - Type: "blob", - Links: &api.FileLinksResponse{ - Self: setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath, - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha, - HTMLURL: setting.AppURL + "user2/repo1/blob/" + branch + "/" + treePath, - }, - } -} - -func TestAPIGetFileContents(t *testing.T) { - onGiteaRun(t, testAPIGetFileContents) -} - -func testAPIGetFileContents(t *testing.T, u *url.URL) { - user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) // owner of the repo1 & repo16 - user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User) // owner of the repo3, is an org - user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User) // owner of neither repos - repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) // public repo - repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo - repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo - treePath := "README.md" - - // Get user2's token - session := loginUser(t, user2.Name) - token2 := getTokenForLoggedInUser(t, session) - session = emptyTestSession(t) - // Get user4's token - session = loginUser(t, user4.Name) - token4 := getTokenForLoggedInUser(t, session) - session = emptyTestSession(t) - - // Make a second master branch in repo1 - repo1.CreateNewBranch(user2, repo1.DefaultBranch, "master2") - - // ref is default branch - branch := repo1.DefaultBranch - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, branch) - resp := session.MakeRequest(t, req, http.StatusOK) - var fileContentResponse api.FileContentResponse - DecodeJSON(t, resp, &fileContentResponse) - assert.NotNil(t, fileContentResponse) - expectedFileContentResponse := getExpectedFileContentResponseForFileContents(branch) - assert.EqualValues(t, *expectedFileContentResponse, fileContentResponse) - - // No ref - req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath) - resp = session.MakeRequest(t, req, http.StatusOK) - DecodeJSON(t, resp, &fileContentResponse) - assert.NotNil(t, fileContentResponse) - expectedFileContentResponse = getExpectedFileContentResponseForFileContents(repo1.DefaultBranch) - assert.EqualValues(t, *expectedFileContentResponse, fileContentResponse) - - // ref is master2 - branch = "master2" - req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, branch) - resp = session.MakeRequest(t, req, http.StatusOK) - DecodeJSON(t, resp, &fileContentResponse) - assert.NotNil(t, fileContentResponse) - expectedFileContentResponse = getExpectedFileContentResponseForFileContents("master2") - assert.EqualValues(t, *expectedFileContentResponse, fileContentResponse) - - // Test file contents a file with the wrong branch - branch = "badbranch" - req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, branch) - resp = session.MakeRequest(t, req, http.StatusInternalServerError) - expectedAPIError := context.APIError{ - Message: "object does not exist [id: " + branch + ", rel_path: ]", - URL: setting.API.SwaggerURL, - } - var apiError context.APIError - DecodeJSON(t, resp, &apiError) - assert.Equal(t, expectedAPIError, apiError) - - // Test accessing private branch with user token that does not have access - should fail - req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4) - session.MakeRequest(t, req, http.StatusNotFound) - - // Test access private branch of owner of token - req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/readme.md?token=%s", user2.Name, repo16.Name, token2) - session.MakeRequest(t, req, http.StatusOK) - - // Test access of org user3 private repo file by owner user2 - req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2) - session.MakeRequest(t, req, http.StatusOK) -} diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index b00583c191..42898bf259 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -44,21 +44,29 @@ func getCreateFileOptions() api.CreateFileOptions { func getExpectedFileResponseForCreate(commitID, treePath string) *api.FileResponse { sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf" + encoding := "base64" + content := "VGhpcyBpcyBuZXcgdGV4dA==" + selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master" + htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath + gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha + downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath return &api.FileResponse{ - Content: &api.FileContentResponse{ + Content: &api.ContentsResponse{ Name: filepath.Base(treePath), Path: treePath, SHA: sha, Size: 16, - URL: setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath, - HTMLURL: setting.AppURL + "user2/repo1/blob/master/" + treePath, - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha, - DownloadURL: setting.AppURL + "user2/repo1/raw/branch/master/" + treePath, - Type: "blob", + Type: "file", + Encoding: &encoding, + Content: &content, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, Links: &api.FileLinksResponse{ - Self: setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath, - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha, - HTMLURL: setting.AppURL + "user2/repo1/blob/master/" + treePath, + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, }, }, Commit: &api.FileCommitResponse{ @@ -145,11 +153,11 @@ func TestAPICreateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf" - expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/new/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/new_branch/new/file%d.txt", fileID) expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) - assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) - assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) + assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL) + assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL) assert.EqualValues(t, createFileOptions.Message+"\n", fileResponse.Commit.Message) // Test creating a file without a message diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index 17fa2adb26..366eb5e918 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -47,21 +47,29 @@ func getUpdateFileOptions() *api.UpdateFileOptions { func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileResponse { sha := "08bd14b2e2852529157324de9c226b3364e76136" + encoding := "base64" + content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ=" + selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master" + htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath + gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha + downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath return &api.FileResponse{ - Content: &api.FileContentResponse{ + Content: &api.ContentsResponse{ Name: filepath.Base(treePath), Path: treePath, SHA: sha, + Type: "file", Size: 20, - URL: setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath, - HTMLURL: setting.AppURL + "user2/repo1/blob/master/" + treePath, - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha, - DownloadURL: setting.AppURL + "user2/repo1/raw/branch/master/" + treePath, - Type: "blob", + Encoding: &encoding, + Content: &content, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, Links: &api.FileLinksResponse{ - Self: setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath, - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha, - HTMLURL: setting.AppURL + "user2/repo1/blob/master/" + treePath, + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, }, }, Commit: &api.FileCommitResponse{ @@ -150,11 +158,11 @@ func TestAPIUpdateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/update/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/new_branch/update/file%d.txt", fileID) expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) - assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) - assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) + assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL) + assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL) assert.EqualValues(t, updateFileOptions.Message+"\n", fileResponse.Commit.Message) // Test updating a file and renaming it @@ -170,11 +178,11 @@ func TestAPIUpdateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &fileResponse) expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/blob/master/rename/update/file%d.txt", fileID) + expectedHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/master/rename/update/file%d.txt", fileID) expectedDownloadURL = fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) - assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) - assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) + assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL) + assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL) // Test updating a file without a message updateFileOptions = getUpdateFileOptions() diff --git a/integrations/api_repo_get_contents_list_test.go b/integrations/api_repo_get_contents_list_test.go new file mode 100644 index 0000000000..f74ceb514a --- /dev/null +++ b/integrations/api_repo_get_contents_list_test.go @@ -0,0 +1,156 @@ +// Copyright 2019 The Gitea 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 integrations + +import ( + "net/http" + "net/url" + "path/filepath" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + + "github.com/stretchr/testify/assert" +) + +func getExpectedContentsListResponseForContents(ref, refType string) []*api.ContentsResponse { + treePath := "README.md" + sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f" + selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref + htmlURL := setting.AppURL + "user2/repo1/src/" + refType + "/" + ref + "/" + treePath + gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha + downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath + return []*api.ContentsResponse{ + { + Name: filepath.Base(treePath), + Path: treePath, + SHA: sha, + Type: "file", + Size: 30, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, + Links: &api.FileLinksResponse{ + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, + }, + }, + } +} + +func TestAPIGetContentsList(t *testing.T) { + onGiteaRun(t, testAPIGetContentsList) +} + +func testAPIGetContentsList(t *testing.T, u *url.URL) { + /*** SETUP ***/ + user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) // owner of the repo1 & repo16 + user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User) // owner of the repo3, is an org + user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User) // owner of neither repos + repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) // public repo + repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo + repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo + treePath := "" // root dir + + // Get user2's token + session := loginUser(t, user2.Name) + token2 := getTokenForLoggedInUser(t, session) + session = emptyTestSession(t) + // Get user4's token + session = loginUser(t, user4.Name) + token4 := getTokenForLoggedInUser(t, session) + session = emptyTestSession(t) + + // Make a new branch in repo1 + newBranch := "test_branch" + repo1.CreateNewBranch(user2, repo1.DefaultBranch, newBranch) + // Get the commit ID of the default branch + gitRepo, _ := git.OpenRepository(repo1.RepoPath()) + commitID, _ := gitRepo.GetBranchCommitID(repo1.DefaultBranch) + // Make a new tag in repo1 + newTag := "test_tag" + gitRepo.CreateTag(newTag, commitID) + /*** END SETUP ***/ + + // ref is default ref + ref := repo1.DefaultBranch + refType := "branch" + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp := session.MakeRequest(t, req, http.StatusOK) + var contentsListResponse []*api.ContentsResponse + DecodeJSON(t, resp, &contentsListResponse) + assert.NotNil(t, contentsListResponse) + expectedContentsListResponse := getExpectedContentsListResponseForContents(ref, refType) + assert.EqualValues(t, expectedContentsListResponse, contentsListResponse) + + // No ref + refType = "branch" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsListResponse) + assert.NotNil(t, contentsListResponse) + expectedContentsListResponse = getExpectedContentsListResponseForContents(repo1.DefaultBranch, refType) + assert.EqualValues(t, expectedContentsListResponse, contentsListResponse) + + // ref is the branch we created above in setup + ref = newBranch + refType = "branch" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsListResponse) + assert.NotNil(t, contentsListResponse) + expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType) + assert.EqualValues(t, expectedContentsListResponse, contentsListResponse) + + // ref is the new tag we created above in setup + ref = newTag + refType = "tag" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsListResponse) + assert.NotNil(t, contentsListResponse) + expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType) + assert.EqualValues(t, expectedContentsListResponse, contentsListResponse) + + // ref is a commit + ref = commitID + refType = "commit" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsListResponse) + assert.NotNil(t, contentsListResponse) + expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType) + assert.EqualValues(t, expectedContentsListResponse, contentsListResponse) + + // Test file contents a file with a bad ref + ref = "badref" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusInternalServerError) + expectedAPIError := context.APIError{ + Message: "object does not exist [id: " + ref + ", rel_path: ]", + URL: setting.API.SwaggerURL, + } + var apiError context.APIError + DecodeJSON(t, resp, &apiError) + assert.Equal(t, expectedAPIError, apiError) + + // Test accessing private ref with user token that does not have access - should fail + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4) + session.MakeRequest(t, req, http.StatusNotFound) + + // Test access private ref of owner of token + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/readme.md?token=%s", user2.Name, repo16.Name, token2) + session.MakeRequest(t, req, http.StatusOK) + + // Test access of org user3 private repo file by owner user2 + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2) + session.MakeRequest(t, req, http.StatusOK) +} diff --git a/integrations/api_repo_get_contents_test.go b/integrations/api_repo_get_contents_test.go new file mode 100644 index 0000000000..f6a43bc5c6 --- /dev/null +++ b/integrations/api_repo_get_contents_test.go @@ -0,0 +1,157 @@ +// Copyright 2019 The Gitea 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 integrations + +import ( + "net/http" + "net/url" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + + "github.com/stretchr/testify/assert" +) + +func getExpectedContentsResponseForContents(ref, refType string) *api.ContentsResponse { + treePath := "README.md" + sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f" + encoding := "base64" + content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x" + selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref + htmlURL := setting.AppURL + "user2/repo1/src/" + refType + "/" + ref + "/" + treePath + gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha + downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath + return &api.ContentsResponse{ + Name: treePath, + Path: treePath, + SHA: sha, + Type: "file", + Size: 30, + Encoding: &encoding, + Content: &content, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, + Links: &api.FileLinksResponse{ + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, + }, + } +} + +func TestAPIGetContents(t *testing.T) { + onGiteaRun(t, testAPIGetContents) +} + +func testAPIGetContents(t *testing.T, u *url.URL) { + /*** SETUP ***/ + user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) // owner of the repo1 & repo16 + user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User) // owner of the repo3, is an org + user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User) // owner of neither repos + repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) // public repo + repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo + repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo + treePath := "README.md" + + // Get user2's token + session := loginUser(t, user2.Name) + token2 := getTokenForLoggedInUser(t, session) + session = emptyTestSession(t) + // Get user4's token + session = loginUser(t, user4.Name) + token4 := getTokenForLoggedInUser(t, session) + session = emptyTestSession(t) + + // Make a new branch in repo1 + newBranch := "test_branch" + repo1.CreateNewBranch(user2, repo1.DefaultBranch, newBranch) + // Get the commit ID of the default branch + gitRepo, _ := git.OpenRepository(repo1.RepoPath()) + commitID, _ := gitRepo.GetBranchCommitID(repo1.DefaultBranch) + // Make a new tag in repo1 + newTag := "test_tag" + gitRepo.CreateTag(newTag, commitID) + /*** END SETUP ***/ + + // ref is default ref + ref := repo1.DefaultBranch + refType := "branch" + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp := session.MakeRequest(t, req, http.StatusOK) + var contentsResponse api.ContentsResponse + DecodeJSON(t, resp, &contentsResponse) + assert.NotNil(t, contentsResponse) + expectedContentsResponse := getExpectedContentsResponseForContents(ref, refType) + assert.EqualValues(t, *expectedContentsResponse, contentsResponse) + + // No ref + refType = "branch" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsResponse) + assert.NotNil(t, contentsResponse) + expectedContentsResponse = getExpectedContentsResponseForContents(repo1.DefaultBranch, refType) + assert.EqualValues(t, *expectedContentsResponse, contentsResponse) + + // ref is the branch we created above in setup + ref = newBranch + refType = "branch" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsResponse) + assert.NotNil(t, contentsResponse) + expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType) + assert.EqualValues(t, *expectedContentsResponse, contentsResponse) + + // ref is the new tag we created above in setup + ref = newTag + refType = "tag" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsResponse) + assert.NotNil(t, contentsResponse) + expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType) + assert.EqualValues(t, *expectedContentsResponse, contentsResponse) + + // ref is a commit + ref = commitID + refType = "commit" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &contentsResponse) + assert.NotNil(t, contentsResponse) + expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType) + assert.EqualValues(t, *expectedContentsResponse, contentsResponse) + + // Test file contents a file with a bad ref + ref = "badref" + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) + resp = session.MakeRequest(t, req, http.StatusInternalServerError) + expectedAPIError := context.APIError{ + Message: "object does not exist [id: " + ref + ", rel_path: ]", + URL: setting.API.SwaggerURL, + } + var apiError context.APIError + DecodeJSON(t, resp, &apiError) + assert.Equal(t, expectedAPIError, apiError) + + // Test accessing private ref with user token that does not have access - should fail + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4) + session.MakeRequest(t, req, http.StatusNotFound) + + // Test access private ref of owner of token + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/readme.md?token=%s", user2.Name, repo16.Name, token2) + session.MakeRequest(t, req, http.StatusOK) + + // Test access of org user3 private repo file by owner user2 + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2) + session.MakeRequest(t, req, http.StatusOK) +} diff --git a/integrations/repofiles_update_test.go b/integrations/repofiles_update_test.go index 02a9bbeb16..a4ce16d847 100644 --- a/integrations/repofiles_update_test.go +++ b/integrations/repofiles_update_test.go @@ -6,6 +6,7 @@ package integrations import ( "net/url" + "path/filepath" "testing" "time" @@ -47,21 +48,30 @@ func getUpdateRepoFileOptions(repo *models.Repository) *repofiles.UpdateRepoFile } func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileResponse { + treePath := "new/file.txt" + encoding := "base64" + content := "VGhpcyBpcyBhIE5FVyBmaWxl" + selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master" + htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath + gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885" + downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath return &api.FileResponse{ - Content: &api.FileContentResponse{ - Name: "file.txt", - Path: "new/file.txt", + Content: &api.ContentsResponse{ + Name: filepath.Base(treePath), + Path: treePath, SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885", + Type: "file", Size: 18, - URL: setting.AppURL + "api/v1/repos/user2/repo1/contents/new/file.txt", - HTMLURL: setting.AppURL + "user2/repo1/blob/master/new/file.txt", - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885", - DownloadURL: setting.AppURL + "user2/repo1/raw/branch/master/new/file.txt", - Type: "blob", + Encoding: &encoding, + Content: &content, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, Links: &api.FileLinksResponse{ - Self: setting.AppURL + "api/v1/repos/user2/repo1/contents/new/file.txt", - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885", - HTMLURL: setting.AppURL + "user2/repo1/blob/master/new/file.txt", + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, }, }, Commit: &api.FileCommitResponse{ @@ -105,22 +115,30 @@ func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileRespons } } -func getExpectedFileResponseForRepofilesUpdate(commitID string) *api.FileResponse { +func getExpectedFileResponseForRepofilesUpdate(commitID, filename string) *api.FileResponse { + encoding := "base64" + content := "VGhpcyBpcyBVUERBVEVEIGNvbnRlbnQgZm9yIHRoZSBSRUFETUUgZmlsZQ==" + selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + filename + "?ref=master" + htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + filename + gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647" + downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + filename return &api.FileResponse{ - Content: &api.FileContentResponse{ - Name: "README.md", - Path: "README.md", + Content: &api.ContentsResponse{ + Name: filename, + Path: filename, SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647", + Type: "file", Size: 43, - URL: setting.AppURL + "api/v1/repos/user2/repo1/contents/README.md", - HTMLURL: setting.AppURL + "user2/repo1/blob/master/README.md", - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647", - DownloadURL: setting.AppURL + "user2/repo1/raw/branch/master/README.md", - Type: "blob", + Encoding: &encoding, + Content: &content, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, Links: &api.FileLinksResponse{ - Self: setting.AppURL + "api/v1/repos/user2/repo1/contents/README.md", - GitURL: setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647", - HTMLURL: setting.AppURL + "user2/repo1/blob/master/README.md", + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, }, }, Commit: &api.FileCommitResponse{ @@ -213,7 +231,7 @@ func TestCreateOrUpdateRepoFileForUpdate(t *testing.T) { assert.Nil(t, err) gitRepo, _ := git.OpenRepository(repo.RepoPath()) commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch) - expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID) + expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID, opts.TreePath) assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content) assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA) assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL) @@ -234,9 +252,8 @@ func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) { repo := ctx.Repo.Repository doer := ctx.User opts := getUpdateRepoFileOptions(repo) - suffix := "_new" opts.FromTreePath = "README.md" - opts.TreePath = "README.md" + suffix // new file name, README.md_new + opts.TreePath = "README_new.md" // new file name, README_new.md // test fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) @@ -245,7 +262,7 @@ func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) { assert.Nil(t, err) gitRepo, _ := git.OpenRepository(repo.RepoPath()) commit, _ := gitRepo.GetBranchCommit(opts.NewBranch) - expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String()) + expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath) // assert that the old file no longer exists in the last commit of the branch fromEntry, err := commit.GetTreeEntryByPath(opts.FromTreePath) toEntry, err := commit.GetTreeEntryByPath(opts.TreePath) @@ -253,9 +270,9 @@ func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) { assert.NotNil(t, toEntry) // Should exist here // assert SHA has remained the same but paths use the new file name assert.EqualValues(t, expectedFileResponse.Content.SHA, fileResponse.Content.SHA) - assert.EqualValues(t, expectedFileResponse.Content.Name+suffix, fileResponse.Content.Name) - assert.EqualValues(t, expectedFileResponse.Content.Path+suffix, fileResponse.Content.Path) - assert.EqualValues(t, expectedFileResponse.Content.URL+suffix, fileResponse.Content.URL) + assert.EqualValues(t, expectedFileResponse.Content.Name, fileResponse.Content.Name) + assert.EqualValues(t, expectedFileResponse.Content.Path, fileResponse.Content.Path) + assert.EqualValues(t, expectedFileResponse.Content.URL, fileResponse.Content.URL) assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA) assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL) }) @@ -284,7 +301,7 @@ func TestCreateOrUpdateRepoFileWithoutBranchNames(t *testing.T) { assert.Nil(t, err) gitRepo, _ := git.OpenRepository(repo.RepoPath()) commitID, _ := gitRepo.GetBranchCommitID(repo.DefaultBranch) - expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID) + expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID, opts.TreePath) assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content) }) } diff --git a/modules/git/blob.go b/modules/git/blob.go index 73ac89dfdf..68147673a3 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -37,6 +37,19 @@ func (b *Blob) Name() string { return b.name } +// GetBlobContent Gets the content of the blob as raw text +func (b *Blob) GetBlobContent() (string, error) { + dataRc, err := b.DataAsync() + if err != nil { + return "", err + } + defer dataRc.Close() + buf := make([]byte, 1024) + n, _ := dataRc.Read(buf) + buf = buf[:n] + return string(buf), nil +} + // GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string func (b *Blob) GetBlobContentBase64() (string, error) { dataRc, err := b.DataAsync() diff --git a/modules/git/repo_object.go b/modules/git/repo_object.go index 67060e30b0..d4d638a743 100644 --- a/modules/git/repo_object.go +++ b/modules/git/repo_object.go @@ -1,4 +1,5 @@ // Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -22,6 +23,8 @@ const ( ObjectBlob ObjectType = "blob" // ObjectTag tag object type ObjectTag ObjectType = "tag" + // ObjectBranch branch object type + ObjectBranch ObjectType = "branch" ) // HashObject takes a reader and returns SHA1 hash for that reader @@ -44,3 +47,17 @@ func (repo *Repository) hashObject(reader io.Reader) (string, error) { } return strings.TrimSpace(stdout.String()), nil } + +// GetRefType gets the type of the ref based on the string +func (repo *Repository) GetRefType(ref string) ObjectType { + if repo.IsTagExist(ref) { + return ObjectTag + } else if repo.IsBranchExist(ref) { + return ObjectBranch + } else if repo.IsCommitExist(ref) { + return ObjectCommit + } else if _, err := repo.GetBlob(ref); err == nil { + return ObjectBlob + } + return ObjectType("invalid") +} diff --git a/modules/repofiles/content.go b/modules/repofiles/content.go index 3098087dc6..9637658e78 100644 --- a/modules/repofiles/content.go +++ b/modules/repofiles/content.go @@ -5,26 +5,52 @@ package repofiles import ( + "fmt" "net/url" + "path" + "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" ) -// GetFileContents gets the meta data on a file's contents -func GetFileContents(repo *models.Repository, treePath, ref string) (*api.FileContentResponse, error) { +// ContentType repo content type +type ContentType string + +// The string representations of different content types +const ( + // ContentTypeRegular regular content type (file) + ContentTypeRegular ContentType = "file" + // ContentTypeDir dir content type (dir) + ContentTypeDir ContentType = "dir" + // ContentLink link content type (symlink) + ContentTypeLink ContentType = "symlink" + // ContentTag submodule content type (submodule) + ContentTypeSubmodule ContentType = "submodule" +) + +// String gets the string of ContentType +func (ct *ContentType) String() string { + return string(*ct) +} + +// GetContentsOrList gets the meta data of a file's contents (*ContentsResponse) if treePath not a tree +// directory, otherwise a listing of file contents ([]*ContentsResponse). Ref can be a branch, commit or tag +func GetContentsOrList(repo *models.Repository, treePath, ref string) (interface{}, error) { if ref == "" { ref = repo.DefaultBranch } + origRef := ref // Check that the path given in opts.treePath is valid (not a git path) - treePath = CleanUploadFileName(treePath) - if treePath == "" { + cleanTreePath := CleanUploadFileName(treePath) + if cleanTreePath == "" && treePath != "" { return nil, models.ErrFilenameInvalid{ Path: treePath, } } + treePath = cleanTreePath gitRepo, err := git.OpenRepository(repo.RepoPath()) if err != nil { @@ -42,32 +68,145 @@ func GetFileContents(repo *models.Repository, treePath, ref string) (*api.FileCo return nil, err } - urlRef := ref - if _, err := gitRepo.GetBranchCommit(ref); err == nil { - urlRef = "branch/" + ref + if entry.Type() != "tree" { + return GetContents(repo, treePath, origRef, false) } - selfURL, _ := url.Parse(repo.APIURL() + "/contents/" + treePath) - gitURL, _ := url.Parse(repo.APIURL() + "/git/blobs/" + entry.ID.String()) - downloadURL, _ := url.Parse(repo.HTMLURL() + "/raw/" + urlRef + "/" + treePath) - htmlURL, _ := url.Parse(repo.HTMLURL() + "/blob/" + ref + "/" + treePath) + // We are in a directory, so we return a list of FileContentResponse objects + var fileList []*api.ContentsResponse - fileContent := &api.FileContentResponse{ - Name: entry.Name(), - Path: treePath, - SHA: entry.ID.String(), - Size: entry.Size(), - URL: selfURL.String(), - HTMLURL: htmlURL.String(), - GitURL: gitURL.String(), - DownloadURL: downloadURL.String(), - Type: entry.Type(), + gitTree, err := commit.SubTree(treePath) + if err != nil { + return nil, err + } + entries, err := gitTree.ListEntries() + if err != nil { + return nil, err + } + for _, e := range entries { + subTreePath := path.Join(treePath, e.Name()) + fileContentResponse, err := GetContents(repo, subTreePath, origRef, true) + if err != nil { + return nil, err + } + fileList = append(fileList, fileContentResponse) + } + return fileList, nil +} + +// GetContents gets the meta data on a file's contents. Ref can be a branch, commit or tag +func GetContents(repo *models.Repository, treePath, ref string, forList bool) (*api.ContentsResponse, error) { + if ref == "" { + ref = repo.DefaultBranch + } + origRef := ref + + // Check that the path given in opts.treePath is valid (not a git path) + cleanTreePath := CleanUploadFileName(treePath) + if cleanTreePath == "" && treePath != "" { + return nil, models.ErrFilenameInvalid{ + Path: treePath, + } + } + treePath = cleanTreePath + + gitRepo, err := git.OpenRepository(repo.RepoPath()) + if err != nil { + return nil, err + } + + // Get the commit object for the ref + commit, err := gitRepo.GetCommit(ref) + if err != nil { + return nil, err + } + commitID := commit.ID.String() + if len(ref) >= 4 && strings.HasPrefix(commitID, ref) { + ref = commit.ID.String() + } + + entry, err := commit.GetTreeEntryByPath(treePath) + if err != nil { + return nil, err + } + + refType := gitRepo.GetRefType(ref) + if refType == "invalid" { + return nil, fmt.Errorf("no commit found for the ref [ref: %s]", ref) + } + + selfURL, err := url.Parse(fmt.Sprintf("%s/contents/%s?ref=%s", repo.APIURL(), treePath, origRef)) + if err != nil { + return nil, err + } + selfURLString := selfURL.String() + + // All content types have these fields in populated + contentsResponse := &api.ContentsResponse{ + Name: entry.Name(), + Path: treePath, + SHA: entry.ID.String(), + Size: entry.Size(), + URL: &selfURLString, Links: &api.FileLinksResponse{ - Self: selfURL.String(), - GitURL: gitURL.String(), - HTMLURL: htmlURL.String(), + Self: &selfURLString, }, } - return fileContent, nil + // Now populate the rest of the ContentsResponse based on entry type + if entry.IsRegular() { + contentsResponse.Type = string(ContentTypeRegular) + if blobResponse, err := GetBlobBySHA(repo, entry.ID.String()); err != nil { + return nil, err + } else if !forList { + // We don't show the content if we are getting a list of FileContentResponses + contentsResponse.Encoding = &blobResponse.Encoding + contentsResponse.Content = &blobResponse.Content + } + } else if entry.IsDir() { + contentsResponse.Type = string(ContentTypeDir) + } else if entry.IsLink() { + contentsResponse.Type = string(ContentTypeLink) + // The target of a symlink file is the content of the file + targetFromContent, err := entry.Blob().GetBlobContent() + if err != nil { + return nil, err + } + contentsResponse.Target = &targetFromContent + } else if entry.IsSubModule() { + contentsResponse.Type = string(ContentTypeSubmodule) + submodule, err := commit.GetSubModule(treePath) + if err != nil { + return nil, err + } + contentsResponse.SubmoduleGitURL = &submodule.URL + } + // Handle links + if entry.IsRegular() || entry.IsLink() { + downloadURL, err := url.Parse(fmt.Sprintf("%s/raw/%s/%s/%s", repo.HTMLURL(), refType, ref, treePath)) + if err != nil { + return nil, err + } + downloadURLString := downloadURL.String() + contentsResponse.DownloadURL = &downloadURLString + } + if !entry.IsSubModule() { + htmlURL, err := url.Parse(fmt.Sprintf("%s/src/%s/%s/%s", repo.HTMLURL(), refType, ref, treePath)) + if err != nil { + return nil, err + } + htmlURLString := htmlURL.String() + contentsResponse.HTMLURL = &htmlURLString + contentsResponse.Links.HTMLURL = &htmlURLString + + gitURL, err := url.Parse(fmt.Sprintf("%s/git/blobs/%s", repo.APIURL(), entry.ID.String())) + if err != nil { + return nil, err + } + gitURLString := gitURL.String() + contentsResponse.GitURL = &gitURLString + contentsResponse.Links.GitURL = &gitURLString + } + + return contentsResponse, nil } diff --git a/modules/repofiles/content_test.go b/modules/repofiles/content_test.go index ce3f5f3678..ef6c5eafc2 100644 --- a/modules/repofiles/content_test.go +++ b/modules/repofiles/content_test.go @@ -9,7 +9,7 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/structs" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" @@ -19,7 +19,36 @@ func TestMain(m *testing.M) { models.MainTest(m, filepath.Join("..", "..")) } -func TestGetFileContents(t *testing.T) { +func getExpectedReadmeContentsResponse() *api.ContentsResponse { + treePath := "README.md" + sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f" + encoding := "base64" + content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x" + selfURL := "https://try.gitea.io/api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master" + htmlURL := "https://try.gitea.io/user2/repo1/src/branch/master/" + treePath + gitURL := "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/" + sha + downloadURL := "https://try.gitea.io/user2/repo1/raw/branch/master/" + treePath + return &api.ContentsResponse{ + Name: treePath, + Path: treePath, + SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", + Type: "file", + Size: 30, + Encoding: &encoding, + Content: &content, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, + Links: &api.FileLinksResponse{ + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, + }, + } +} + +func TestGetContents(t *testing.T) { models.PrepareTestEnv(t) ctx := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") @@ -30,37 +59,81 @@ func TestGetFileContents(t *testing.T) { treePath := "README.md" ref := ctx.Repo.Repository.DefaultBranch - expectedFileContentResponse := &structs.FileContentResponse{ - Name: treePath, - Path: treePath, - SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", - Size: 30, - URL: "https://try.gitea.io/api/v1/repos/user2/repo1/contents/README.md", - HTMLURL: "https://try.gitea.io/user2/repo1/blob/master/README.md", - GitURL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/4b4851ad51df6a7d9f25c979345979eaeb5b349f", - DownloadURL: "https://try.gitea.io/user2/repo1/raw/branch/master/README.md", - Type: "blob", - Links: &structs.FileLinksResponse{ - Self: "https://try.gitea.io/api/v1/repos/user2/repo1/contents/README.md", - GitURL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/4b4851ad51df6a7d9f25c979345979eaeb5b349f", - HTMLURL: "https://try.gitea.io/user2/repo1/blob/master/README.md", - }, - } + expectedContentsResponse := getExpectedReadmeContentsResponse() - t.Run("Get README.md contents", func(t *testing.T) { - fileContentResponse, err := GetFileContents(ctx.Repo.Repository, treePath, ref) - assert.EqualValues(t, expectedFileContentResponse, fileContentResponse) + t.Run("Get README.md contents with GetContents()", func(t *testing.T) { + fileContentResponse, err := GetContents(ctx.Repo.Repository, treePath, ref, false) + assert.EqualValues(t, expectedContentsResponse, fileContentResponse) assert.Nil(t, err) }) - t.Run("Get REAMDE.md contents with ref as empty string (should then use the repo's default branch)", func(t *testing.T) { - fileContentResponse, err := GetFileContents(ctx.Repo.Repository, treePath, "") - assert.EqualValues(t, expectedFileContentResponse, fileContentResponse) + t.Run("Get REAMDE.md contents with ref as empty string (should then use the repo's default branch) with GetContents()", func(t *testing.T) { + fileContentResponse, err := GetContents(ctx.Repo.Repository, treePath, "", false) + assert.EqualValues(t, expectedContentsResponse, fileContentResponse) assert.Nil(t, err) }) } -func TestGetFileContentsErrors(t *testing.T) { +func TestGetContentsOrListForDir(t *testing.T) { + models.PrepareTestEnv(t) + ctx := test.MockContext(t, "user2/repo1") + ctx.SetParams(":id", "1") + test.LoadRepo(t, ctx, 1) + test.LoadRepoCommit(t, ctx) + test.LoadUser(t, ctx, 2) + test.LoadGitRepo(t, ctx) + treePath := "" // root dir + ref := ctx.Repo.Repository.DefaultBranch + + readmeContentsResponse := getExpectedReadmeContentsResponse() + // because will be in a list, doesn't have encoding and content + readmeContentsResponse.Encoding = nil + readmeContentsResponse.Content = nil + + expectedContentsListResponse := []*api.ContentsResponse{ + readmeContentsResponse, + } + + t.Run("Get root dir contents with GetContentsOrList()", func(t *testing.T) { + fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, ref) + assert.EqualValues(t, expectedContentsListResponse, fileContentResponse) + assert.Nil(t, err) + }) + + t.Run("Get root dir contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList()", func(t *testing.T) { + fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, "") + assert.EqualValues(t, expectedContentsListResponse, fileContentResponse) + assert.Nil(t, err) + }) +} + +func TestGetContentsOrListForFile(t *testing.T) { + models.PrepareTestEnv(t) + ctx := test.MockContext(t, "user2/repo1") + ctx.SetParams(":id", "1") + test.LoadRepo(t, ctx, 1) + test.LoadRepoCommit(t, ctx) + test.LoadUser(t, ctx, 2) + test.LoadGitRepo(t, ctx) + treePath := "README.md" + ref := ctx.Repo.Repository.DefaultBranch + + expectedContentsResponse := getExpectedReadmeContentsResponse() + + t.Run("Get README.md contents with GetContentsOrList()", func(t *testing.T) { + fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, ref) + assert.EqualValues(t, expectedContentsResponse, fileContentResponse) + assert.Nil(t, err) + }) + + t.Run("Get REAMDE.md contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList()", func(t *testing.T) { + fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, "") + assert.EqualValues(t, expectedContentsResponse, fileContentResponse) + assert.Nil(t, err) + }) +} + +func TestGetContentsErrors(t *testing.T) { models.PrepareTestEnv(t) ctx := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") @@ -74,7 +147,7 @@ func TestGetFileContentsErrors(t *testing.T) { t.Run("bad treePath", func(t *testing.T) { badTreePath := "bad/tree.md" - fileContentResponse, err := GetFileContents(repo, badTreePath, ref) + fileContentResponse, err := GetContents(repo, badTreePath, ref, false) assert.Error(t, err) assert.EqualError(t, err, "object does not exist [id: , rel_path: bad]") assert.Nil(t, fileContentResponse) @@ -82,7 +155,36 @@ func TestGetFileContentsErrors(t *testing.T) { t.Run("bad ref", func(t *testing.T) { badRef := "bad_ref" - fileContentResponse, err := GetFileContents(repo, treePath, badRef) + fileContentResponse, err := GetContents(repo, treePath, badRef, false) + assert.Error(t, err) + assert.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]") + assert.Nil(t, fileContentResponse) + }) +} + +func TestGetContentsOrListErrors(t *testing.T) { + models.PrepareTestEnv(t) + ctx := test.MockContext(t, "user2/repo1") + ctx.SetParams(":id", "1") + test.LoadRepo(t, ctx, 1) + test.LoadRepoCommit(t, ctx) + test.LoadUser(t, ctx, 2) + test.LoadGitRepo(t, ctx) + repo := ctx.Repo.Repository + treePath := "README.md" + ref := repo.DefaultBranch + + t.Run("bad treePath", func(t *testing.T) { + badTreePath := "bad/tree.md" + fileContentResponse, err := GetContentsOrList(repo, badTreePath, ref) + assert.Error(t, err) + assert.EqualError(t, err, "object does not exist [id: , rel_path: bad]") + assert.Nil(t, fileContentResponse) + }) + + t.Run("bad ref", func(t *testing.T) { + badRef := "bad_ref" + fileContentResponse, err := GetContentsOrList(repo, treePath, badRef) assert.Error(t, err) assert.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]") assert.Nil(t, fileContentResponse) diff --git a/modules/repofiles/file.go b/modules/repofiles/file.go index 70fd57bba0..801f770e02 100644 --- a/modules/repofiles/file.go +++ b/modules/repofiles/file.go @@ -17,8 +17,8 @@ import ( // GetFileResponseFromCommit Constructs a FileResponse from a Commit object func GetFileResponseFromCommit(repo *models.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) { - fileContents, _ := GetFileContents(repo, treeName, branch) // ok if fails, then will be nil - fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil + fileContents, _ := GetContents(repo, treeName, branch, false) // ok if fails, then will be nil + fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil verification := GetPayloadCommitVerification(commit) fileResponse := &api.FileResponse{ Content: fileContents, diff --git a/modules/repofiles/file_test.go b/modules/repofiles/file_test.go index 5f6320a938..00feb93fff 100644 --- a/modules/repofiles/file_test.go +++ b/modules/repofiles/file_test.go @@ -5,6 +5,7 @@ package repofiles import ( + "code.gitea.io/gitea/modules/setting" "testing" "code.gitea.io/gitea/models" @@ -16,21 +17,31 @@ import ( ) func getExpectedFileResponse() *api.FileResponse { + treePath := "README.md" + sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f" + encoding := "base64" + content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x" + selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master" + htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath + gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha + downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath return &api.FileResponse{ - Content: &api.FileContentResponse{ - Name: "README.md", - Path: "README.md", - SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", + Content: &api.ContentsResponse{ + Name: treePath, + Path: treePath, + SHA: sha, + Type: "file", Size: 30, - URL: "https://try.gitea.io/api/v1/repos/user2/repo1/contents/README.md", - HTMLURL: "https://try.gitea.io/user2/repo1/blob/master/README.md", - GitURL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/4b4851ad51df6a7d9f25c979345979eaeb5b349f", - DownloadURL: "https://try.gitea.io/user2/repo1/raw/branch/master/README.md", - Type: "blob", + Encoding: &encoding, + Content: &content, + URL: &selfURL, + HTMLURL: &htmlURL, + GitURL: &gitURL, + DownloadURL: &downloadURL, Links: &api.FileLinksResponse{ - Self: "https://try.gitea.io/api/v1/repos/user2/repo1/contents/README.md", - GitURL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/4b4851ad51df6a7d9f25c979345979eaeb5b349f", - HTMLURL: "https://try.gitea.io/user2/repo1/blob/master/README.md", + Self: &selfURL, + GitURL: &gitURL, + HTMLURL: &htmlURL, }, }, Commit: &api.FileCommitResponse{ diff --git a/modules/structs/repo_file.go b/modules/structs/repo_file.go index e5be9ce108..b2eeb7f13a 100644 --- a/modules/structs/repo_file.go +++ b/modules/structs/repo_file.go @@ -49,23 +49,32 @@ type UpdateFileOptions struct { // FileLinksResponse contains the links for a repo's file type FileLinksResponse struct { - Self string `json:"url"` - GitURL string `json:"git_url"` - HTMLURL string `json:"html_url"` + Self *string `json:"self"` + GitURL *string `json:"git"` + HTMLURL *string `json:"html"` } -// FileContentResponse contains information about a repo's file stats and content -type FileContentResponse struct { - Name string `json:"name"` - Path string `json:"path"` - SHA string `json:"sha"` - Size int64 `json:"size"` - URL string `json:"url"` - HTMLURL string `json:"html_url"` - GitURL string `json:"git_url"` - DownloadURL string `json:"download_url"` - Type string `json:"type"` - Links *FileLinksResponse `json:"_links"` +// ContentsResponse contains information about a repo's entry's (dir, file, symlink, submodule) metadata and content +type ContentsResponse struct { + Name string `json:"name"` + Path string `json:"path"` + SHA string `json:"sha"` + // `type` will be `file`, `dir`, `symlink`, or `submodule` + Type string `json:"type"` + Size int64 `json:"size"` + // `encoding` is populated when `type` is `file`, otherwise null + Encoding *string `json:"encoding"` + // `content` is populated when `type` is `file`, otherwise null + Content *string `json:"content"` + // `target` is populated when `type` is `symlink`, otherwise null + Target *string `json:"target"` + URL *string `json:"url"` + HTMLURL *string `json:"html_url"` + GitURL *string `json:"git_url"` + DownloadURL *string `json:"download_url"` + // `submodule_git_url` is populated when `type` is `submodule`, otherwise null + SubmoduleGitURL *string `json:"submodule_git_url"` + Links *FileLinksResponse `json:"_links"` } // FileCommitResponse contains information generated from a Git commit for a repo's file. @@ -81,7 +90,7 @@ type FileCommitResponse struct { // FileResponse contains information about a repo's file type FileResponse struct { - Content *FileContentResponse `json:"content"` + Content *ContentsResponse `json:"content"` Commit *FileCommitResponse `json:"commit"` Verification *PayloadCommitVerification `json:"verification"` } diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 2268c1be38..8e7a74eca2 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -766,7 +766,8 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/tags/:sha", context.RepoRef(), repo.GetTag) }, reqRepoReader(models.UnitTypeCode)) m.Group("/contents", func() { - m.Get("/*", repo.GetFileContents) + m.Get("", repo.GetContentsList) + m.Get("/*", repo.GetContents) m.Group("/*", func() { m.Post("", bind(api.CreateFileOptions{}), repo.CreateFile) m.Put("", bind(api.UpdateFileOptions{}), repo.UpdateFile) diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index d510756283..ae20e1e96b 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -366,11 +366,11 @@ func DeleteFile(ctx *context.APIContext, apiOpts api.DeleteFileOptions) { } } -// GetFileContents Get the contents of a fle in a repository -func GetFileContents(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/contents/{filepath} repository repoGetFileContents +// GetContents Get the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir +func GetContents(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/contents/{filepath} repository repoGetContents // --- - // summary: Gets the contents of a file or directory in a repository + // summary: Gets the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir // produces: // - application/json // parameters: @@ -386,20 +386,20 @@ func GetFileContents(ctx *context.APIContext) { // required: true // - name: filepath // in: path - // description: path of the file to delete + // description: path of the dir, file, symlink or submodule in the repo // type: string // required: true // - name: ref // in: query // description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)" - // required: false // type: string + // required: false // responses: // "200": - // "$ref": "#/responses/FileContentResponse" + // "$ref": "#/responses/ContentsResponse" if !CanReadFiles(ctx.Repo) { - ctx.Error(http.StatusInternalServerError, "GetFileContents", models.ErrUserDoesNotHaveAccessToRepo{ + ctx.Error(http.StatusInternalServerError, "GetContentsOrList", models.ErrUserDoesNotHaveAccessToRepo{ UserID: ctx.User.ID, RepoName: ctx.Repo.Repository.LowerName, }) @@ -409,9 +409,40 @@ func GetFileContents(ctx *context.APIContext) { treePath := ctx.Params("*") ref := ctx.QueryTrim("ref") - if fileContents, err := repofiles.GetFileContents(ctx.Repo.Repository, treePath, ref); err != nil { - ctx.Error(http.StatusInternalServerError, "GetFileContents", err) + if fileList, err := repofiles.GetContentsOrList(ctx.Repo.Repository, treePath, ref); err != nil { + ctx.Error(http.StatusInternalServerError, "GetContentsOrList", err) } else { - ctx.JSON(http.StatusOK, fileContents) + ctx.JSON(http.StatusOK, fileList) } } + +// GetContentsList Get the metadata of all the entries of the root dir +func GetContentsList(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/contents repository repoGetContentsList + // --- + // summary: Gets the metadata of all the entries of the root dir + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: ref + // in: query + // description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)" + // type: string + // required: false + // responses: + // "200": + // "$ref": "#/responses/ContentsListResponse" + + // same as GetContents(), this function is here because swagger fails if path is empty in GetContents() interface + GetContents(ctx) +} diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index 25354b3d66..2cab5b0ed4 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -197,11 +197,18 @@ type swaggerFileResponse struct { Body api.FileResponse `json:"body"` } -// FileContentResponse -// swagger:response FileContentResponse -type swaggerFileContentResponse struct { +// ContentsResponse +// swagger:response ContentsResponse +type swaggerContentsResponse struct { //in: body - Body api.FileContentResponse `json:"body"` + Body api.ContentsResponse `json:"body"` +} + +// ContentsListResponse +// swagger:response ContentsListResponse +type swaggerContentsListResponse struct { + // in:body + Body []api.ContentsResponse `json:"body"` } // FileDeleteResponse diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 6c2708dd96..d6d501ed22 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -1570,7 +1570,7 @@ } } }, - "/repos/{owner}/{repo}/contents/{filepath}": { + "/repos/{owner}/{repo}/contents": { "get": { "produces": [ "application/json" @@ -1578,8 +1578,8 @@ "tags": [ "repository" ], - "summary": "Gets the contents of a file or directory in a repository", - "operationId": "repoGetFileContents", + "summary": "Gets the metadata of all the entries of the root dir", + "operationId": "repoGetContentsList", "parameters": [ { "type": "string", @@ -1597,7 +1597,46 @@ }, { "type": "string", - "description": "path of the file to delete", + "description": "The name of the commit/branch/tag. Default the repository’s default branch (usually master)", + "name": "ref", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/ContentsListResponse" + } + } + } + }, + "/repos/{owner}/{repo}/contents/{filepath}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Gets the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir", + "operationId": "repoGetContents", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "path of the dir, file, symlink or submodule in the repo", "name": "filepath", "in": "path", "required": true @@ -1611,7 +1650,7 @@ ], "responses": { "200": { - "$ref": "#/responses/FileContentResponse" + "$ref": "#/responses/ContentsResponse" } } }, @@ -7017,6 +7056,74 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "ContentsResponse": { + "description": "ContentsResponse contains information about a repo's entry's (dir, file, symlink, submodule) metadata and content", + "type": "object", + "properties": { + "_links": { + "$ref": "#/definitions/FileLinksResponse" + }, + "content": { + "description": "`content` is populated when `type` is `file`, otherwise null", + "type": "string", + "x-go-name": "Content" + }, + "download_url": { + "type": "string", + "x-go-name": "DownloadURL" + }, + "encoding": { + "description": "`encoding` is populated when `type` is `file`, otherwise null", + "type": "string", + "x-go-name": "Encoding" + }, + "git_url": { + "type": "string", + "x-go-name": "GitURL" + }, + "html_url": { + "type": "string", + "x-go-name": "HTMLURL" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "path": { + "type": "string", + "x-go-name": "Path" + }, + "sha": { + "type": "string", + "x-go-name": "SHA" + }, + "size": { + "type": "integer", + "format": "int64", + "x-go-name": "Size" + }, + "submodule_git_url": { + "description": "`submodule_git_url` is populated when `type` is `submodule`, otherwise null", + "type": "string", + "x-go-name": "SubmoduleGitURL" + }, + "target": { + "description": "`target` is populated when `type` is `symlink`, otherwise null", + "type": "string", + "x-go-name": "Target" + }, + "type": { + "description": "`type` will be `file`, `dir`, `symlink`, or `submodule`", + "type": "string", + "x-go-name": "Type" + }, + "url": { + "type": "string", + "x-go-name": "URL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "CreateEmailOption": { "description": "CreateEmailOption options when creating email addresses", "type": "object", @@ -8179,53 +8286,6 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, - "FileContentResponse": { - "description": "FileContentResponse contains information about a repo's file stats and content", - "type": "object", - "properties": { - "_links": { - "$ref": "#/definitions/FileLinksResponse" - }, - "download_url": { - "type": "string", - "x-go-name": "DownloadURL" - }, - "git_url": { - "type": "string", - "x-go-name": "GitURL" - }, - "html_url": { - "type": "string", - "x-go-name": "HTMLURL" - }, - "name": { - "type": "string", - "x-go-name": "Name" - }, - "path": { - "type": "string", - "x-go-name": "Path" - }, - "sha": { - "type": "string", - "x-go-name": "SHA" - }, - "size": { - "type": "integer", - "format": "int64", - "x-go-name": "Size" - }, - "type": { - "type": "string", - "x-go-name": "Type" - }, - "url": { - "type": "string", - "x-go-name": "URL" - } - }, - "x-go-package": "code.gitea.io/gitea/modules/structs" - }, "FileDeleteResponse": { "description": "FileDeleteResponse contains information about a repo's file that was deleted", "type": "object", @@ -8247,15 +8307,15 @@ "description": "FileLinksResponse contains the links for a repo's file", "type": "object", "properties": { - "git_url": { + "git": { "type": "string", "x-go-name": "GitURL" }, - "html_url": { + "html": { "type": "string", "x-go-name": "HTMLURL" }, - "url": { + "self": { "type": "string", "x-go-name": "Self" } @@ -8270,7 +8330,7 @@ "$ref": "#/definitions/FileCommitResponse" }, "content": { - "$ref": "#/definitions/FileContentResponse" + "$ref": "#/definitions/ContentsResponse" }, "verification": { "$ref": "#/definitions/PayloadCommitVerification" @@ -9898,6 +9958,21 @@ "$ref": "#/definitions/Commit" } }, + "ContentsListResponse": { + "description": "ContentsListResponse", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ContentsResponse" + } + } + }, + "ContentsResponse": { + "description": "ContentsResponse", + "schema": { + "$ref": "#/definitions/ContentsResponse" + } + }, "DeployKey": { "description": "DeployKey", "schema": { @@ -9922,12 +9997,6 @@ } } }, - "FileContentResponse": { - "description": "FileContentResponse", - "schema": { - "$ref": "#/definitions/FileContentResponse" - } - }, "FileDeleteResponse": { "description": "FileDeleteResponse", "schema": { From aeb8f7aad8b71909fdc81e34c29a70a0bb700f33 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 29 Jun 2019 20:52:06 +0000 Subject: [PATCH 162/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 14 ++++ options/locale/locale_ml-IN.ini | 116 ++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 options/locale/locale_ml-IN.ini diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 2827a2d854..4f07874cfc 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -238,9 +238,23 @@ login_openid=OpenID oauth_signup_tab=Registrar nueva cuenta oauth_signup_title=Añadir email y contraseña (para la recuperación de la cuenta) oauth_signup_submit=Completar Cuenta +oauth_signin_tab=Vincular a una Cuenta Existente +oauth_signin_title=Regístrese para autorizar cuenta vinculada +oauth_signin_submit=Vincular Cuenta openid_connect_submit=Conectar openid_connect_title=Accede con una cuenta existente +openid_connect_desc=La URI OpenID elegida es desconocida. Asóciela a una nueva cuenta aquí. openid_register_title=Crear una nueva cuenta +openid_register_desc=La URI OpenID elegida es desconocida. Asóciela a una nueva cuenta aquí. +openid_signin_desc=Introduzca su URI OpenID. Por ejemplo: https://anne.me, bob.openid.org.cn o gnusocial.net/carry. +disable_forgot_password_mail=La recuperación de cuentas está desactivada. Por favor, contacte con el administrador del sitio. +email_domain_blacklisted=No puede registrarse con su correo electrónico. +authorize_application=Autorizar aplicación +authroize_redirect_notice=Será redirigido a %s si autoriza esta aplicación. +authorize_application_created_by=Esta aplicación fue creada por %s. +authorize_application_description=Si concede el acceso, podrá acceder y escribir a toda la información de su cuenta, incluyendo repositorios privado y organizaciones. +authorize_title=¿Autorizar a "%s" a acceder a su cuenta? +authorization_failed=Autorización fallida [mail] activate_account=Por favor, active su cuenta diff --git a/options/locale/locale_ml-IN.ini b/options/locale/locale_ml-IN.ini new file mode 100644 index 0000000000..8efc2a4d50 --- /dev/null +++ b/options/locale/locale_ml-IN.ini @@ -0,0 +1,116 @@ + + + + + + + + + +[install] + + + +[home] + + +[explore] + +[auth] + +[mail] + +[modal] + +[form] + + + + + + + +[user] + + +[settings] + + + + + + + + + + + + + + + +[repo] + + + + + + + + + + + + + + + + + + + + + + +[org] + + + + + + +[admin] + + + + + + + + + + + + + + + + + + + + + + +[action] + +[tool] + +[dropzone] + +[notification] + +[gpg] + +[units] + From 1e46eedce721e22e3e1e94eec6e0afccd36147c1 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 30 Jun 2019 05:28:17 +0200 Subject: [PATCH 163/220] update mssql drive to last working version 20180314172330-6a30f4e59a44 (#7306) --- go.mod | 2 +- go.sum | 4 +- .../denisenkom/go-mssqldb/README.md | 174 +++-- .../denisenkom/go-mssqldb/appveyor.yml | 45 ++ .../github.com/denisenkom/go-mssqldb/buf.go | 145 ++-- .../denisenkom/go-mssqldb/bulkcopy.go | 616 ++++++++++++++++ .../denisenkom/go-mssqldb/bulkcopy_sql.go | 93 +++ .../denisenkom/go-mssqldb/collation.go | 39 - .../denisenkom/go-mssqldb/decimal.go | 22 +- .../github.com/denisenkom/go-mssqldb/doc.go | 12 + .../go-mssqldb/{ => internal/cp}/charset.go | 8 +- .../go-mssqldb/internal/cp/collation.go | 20 + .../go-mssqldb/{ => internal/cp}/cp1250.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1251.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1252.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1253.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1254.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1255.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1256.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1257.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp1258.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp437.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp850.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp874.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp932.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp936.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp949.go | 2 +- .../go-mssqldb/{ => internal/cp}/cp950.go | 2 +- .../github.com/denisenkom/go-mssqldb/log.go | 21 +- .../github.com/denisenkom/go-mssqldb/mssql.go | 611 ++++++++++++---- .../denisenkom/go-mssqldb/mssql_go1.3.go | 11 - .../denisenkom/go-mssqldb/mssql_go1.3pre.go | 11 - .../denisenkom/go-mssqldb/mssql_go18.go | 91 +++ .../denisenkom/go-mssqldb/mssql_go19.go | 64 ++ .../denisenkom/go-mssqldb/mssql_go19pre.go | 12 + .../github.com/denisenkom/go-mssqldb/net.go | 2 +- .../github.com/denisenkom/go-mssqldb/ntlm.go | 2 +- .../denisenkom/go-mssqldb/parser.go | 40 +- .../denisenkom/go-mssqldb/sspi_windows.go | 2 +- .../github.com/denisenkom/go-mssqldb/tds.go | 358 ++++++++- .../github.com/denisenkom/go-mssqldb/token.go | 387 ++++++++-- .../denisenkom/go-mssqldb/token_string.go | 53 ++ .../github.com/denisenkom/go-mssqldb/tran.go | 16 +- .../github.com/denisenkom/go-mssqldb/types.go | 679 +++++++++++++++++- .../denisenkom/go-mssqldb/uniqueidentifier.go | 74 ++ vendor/modules.txt | 3 +- 46 files changed, 3158 insertions(+), 491 deletions(-) create mode 100644 vendor/github.com/denisenkom/go-mssqldb/appveyor.yml create mode 100644 vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go delete mode 100644 vendor/github.com/denisenkom/go-mssqldb/collation.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/doc.go rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/charset.go (94%) create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1250.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1251.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1252.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1253.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1254.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1255.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1256.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1257.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp1258.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp437.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp850.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp874.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp932.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp936.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp949.go (99%) rename vendor/github.com/denisenkom/go-mssqldb/{ => internal/cp}/cp950.go (99%) delete mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3.go delete mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3pre.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go18.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/token_string.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go diff --git a/go.mod b/go.mod index 6087e52d3e..614f3639f8 100644 --- a/go.mod +++ b/go.mod @@ -140,4 +140,4 @@ require ( xorm.io/core v0.6.3 ) -replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 +replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 diff --git a/go.sum b/go.sum index 9d5e2c9c50..f34fe7f3ec 100644 --- a/go.sum +++ b/go.sum @@ -60,8 +60,8 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 h1:JpA+YMG4JLW8nzLmU05mTiuB0O17xHGxpWolEZ0zDuA= -github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 h1:x0uHqLQTSEL9LKic8sWDt3ASkq07ve5ojIIUl5uF64M= +github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac h1:xrQJVwQCGqDvOO7/0+RyIq5J2M3Q4ZF7Ug/BMQtML1E= github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= diff --git a/vendor/github.com/denisenkom/go-mssqldb/README.md b/vendor/github.com/denisenkom/go-mssqldb/README.md index 8570ae9f61..cd19ded516 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/README.md +++ b/vendor/github.com/denisenkom/go-mssqldb/README.md @@ -1,79 +1,131 @@ # A pure Go MSSQL driver for Go's database/sql package +[![GoDoc](https://godoc.org/github.com/denisenkom/go-mssqldb?status.svg)](http://godoc.org/github.com/denisenkom/go-mssqldb) +[![Build status](https://ci.appveyor.com/api/projects/status/jrln8cs62wj9i0a2?svg=true)](https://ci.appveyor.com/project/denisenkom/go-mssqldb) +[![codecov](https://codecov.io/gh/denisenkom/go-mssqldb/branch/master/graph/badge.svg)](https://codecov.io/gh/denisenkom/go-mssqldb) + ## Install - go get github.com/denisenkom/go-mssqldb +Requires Go 1.8 or above. -## Tests +Install with `go get github.com/denisenkom/go-mssqldb` . -`go test` is used for testing. A running instance of MSSQL server is required. -Environment variables are used to pass login information. +## Connection Parameters and DSN -Example: +The recommended connection string uses a URL format: +`sqlserver://username:password@host/instance?param1=value¶m2=value` +Other supported formats are listed below. - env HOST=localhost SQLUSER=sa SQLPASSWORD=sa DATABASE=test go test +### Common parameters: -## Connection Parameters +* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. +* `password` +* `database` +* `connection timeout` - in seconds (default is 30) +* `dial timeout` - in seconds (default is 5) +* `encrypt` + * `disable` - Data send between client and server is not encrypted. + * `false` - Data sent between client and server is not encrypted beyond the login packet. (Default) + * `true` - Data sent between client and server is encrypted. +* `keepAlive` - in seconds; 0 to disable (default is 30) +* `app name` - The application name (default is go-mssqldb) -* "server" - host or host\instance (default localhost) -* "port" - used only when there is no instance in server (default 1433) -* "failoverpartner" - host or host\instance (default is no partner). -* "failoverport" - used only when there is no instance in failoverpartner (default 1433) -* "user id" - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. -* "password" -* "database" -* "connection timeout" - in seconds (default is 30) -* "dial timeout" - in seconds (default is 5) -* "keepAlive" - in seconds; 0 to disable (default is 0) -* "log" - logging flags (default 0/no logging, 63 for full logging) +### Connection parameters for ODBC and ADO style connection strings: + +* `server` - host or host\instance (default localhost) +* `port` - used only when there is no instance in server (default 1433) + +### Less common parameters: + +* `failoverpartner` - host or host\instance (default is no partner). +* `failoverport` - used only when there is no instance in failoverpartner (default 1433) +* `packet size` - in bytes; 512 to 32767 (default is 4096) + * Encrypted connections have a maximum packet size of 16383 bytes + * Further information on usage: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option +* `log` - logging flags (default 0/no logging, 63 for full logging) * 1 log errors * 2 log messages * 4 log rows affected * 8 trace sql statements * 16 log statement parameters * 32 log transaction begin/end -* "encrypt" - * disable - Data send between client and server is not encrypted. - * false - Data sent between client and server is not encrypted beyond the login packet. (Default) - * true - Data sent between client and server is encrypted. -* "TrustServerCertificate" +* `TrustServerCertificate` * false - Server certificate is checked. Default is false if encypt is specified. * true - Server certificate is not checked. Default is true if encrypt is not specified. If trust server certificate is true, driver accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing. -* "certificate" - The file that contains the public key certificate of the CA that signed the SQL Server certificate. The specified certificate overrides the go platform specific CA certificates. -* "hostNameInCertificate" - Specifies the Common Name (CN) in the server certificate. Default value is the server host. -* "ServerSPN" - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port. -* "Workstation ID" - The workstation name (default is the host name) -* "app name" - The application name (default is go-mssqldb) -* "ApplicationIntent" - Can be given the value "ReadOnly" to initiate a read-only connection to an Availability Group listener. +* `certificate` - The file that contains the public key certificate of the CA that signed the SQL Server certificate. The specified certificate overrides the go platform specific CA certificates. +* `hostNameInCertificate` - Specifies the Common Name (CN) in the server certificate. Default value is the server host. +* `ServerSPN` - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port. +* `Workstation ID` - The workstation name (default is the host name) +* `ApplicationIntent` - Can be given the value `ReadOnly` to initiate a read-only connection to an Availability Group listener. -Example: +### The connection string can be specified in one of three formats: + + +1. URL: with `sqlserver` scheme. username and password appears before the host. Any instance appears as + the first segment in the path. All other options are query parameters. Examples: + + * `sqlserver://username:password@host/instance?param1=value¶m2=value` + * `sqlserver://username:password@host:port?param1=value¶m2=value` + * `sqlserver://sa@localhost/SQLExpress?database=master&connection+timeout=30` // `SQLExpress instance. + * `sqlserver://sa:mypass@localhost?database=master&connection+timeout=30` // username=sa, password=mypass. + * `sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30"` // port 1234 on localhost. + * `sqlserver://sa:my%7Bpass@somehost?connection+timeout=30` // password is "my{pass" + + A string of this format can be constructed using the `URL` type in the `net/url` package. ```go - db, err := sql.Open("mssql", "server=localhost;user id=sa") + query := url.Values{} + query.Add("connection timeout", "30") + + u := &url.URL{ + Scheme: "sqlserver", + User: url.UserPassword(username, password), + Host: fmt.Sprintf("%s:%d", hostname, port), + // Path: instance, // if connecting to an instance instead of a port + RawQuery: query.Encode(), + } + db, err := sql.Open("sqlserver", u.String()) +``` + +2. ADO: `key=value` pairs separated by `;`. Values may not contain `;`, leading and trailing whitespace is ignored. + Examples: + + * `server=localhost\\SQLExpress;user id=sa;database=master;connection timeout=30` + * `server=localhost;user id=sa;database=master;connection timeout=30` + +3. ODBC: Prefix with `odbc`, `key=value` pairs separated by `;`. Allow `;` by wrapping + values in `{}`. Examples: + + * `odbc:server=localhost\\SQLExpress;user id=sa;database=master;connection timeout=30` + * `odbc:server=localhost;user id=sa;database=master;connection timeout=30` + * `odbc:server=localhost;user id=sa;password={foo;bar}` // Value marked with `{}`, password is "foo;bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Value marked with `{}`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foobar }` // Value marked with `{}`, password is "foobar " + * `odbc:server=localhost;user id=sa;password=foo{bar` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password=foo}bar` // Literal `}`, password is "foo}bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foo}}bar}` // Escaped `} with `}}`, password is "foo}bar" + +## Executing Stored Procedures + +To run a stored procedure, set the query text to the procedure name: +```go +var account = "abc" +_, err := db.ExecContext(ctx, "sp_RunMe", + sql.Named("ID", 123), + sql.Out{Dest{sql.Named("Account", &account)} +) ``` ## Statement Parameters -In the SQL statement text, literals may be replaced by a parameter that matches one of the following: - -* ? -* ?nnn -* :nnn -* $nnn - -where nnn represents an integer that specifies a 1-indexed positional parameter. Ex: +The `sqlserver` driver uses normal MS SQL Server syntax and expects parameters in +the sql query to be in the form of either `@Name` or `@p1` to `@pN` (ordinal position). ```go -db.Query("SELECT * FROM t WHERE a = ?3, b = ?2, c = ?1", "x", "y", "z") +db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob") ``` -will expand to roughly - -```sql -SELECT * FROM t WHERE a = 'z', b = 'y', c = 'x' -``` - - ## Features * Can be used with SQL Server 2005 or newer @@ -87,6 +139,34 @@ SELECT * FROM t WHERE a = 'z', b = 'y', c = 'x' * Supports connections to AlwaysOn Availability Group listeners, including re-direction to read-only replicas. * Supports query notifications +## Tests + +`go test` is used for testing. A running instance of MSSQL server is required. +Environment variables are used to pass login information. + +Example: + + env SQLSERVER_DSN=sqlserver://user:pass@hostname/instance?database=test1 go test + +## Deprecated + +These features still exist in the driver, but they are are deprecated. + +### Query Parameter Token Replace (driver "mssql") + +If you use the driver name "mssql" (rather then "sqlserver" the SQL text +will be loosly parsed and an attempt to extract identifiers using one of + +* ? +* ?nnn +* :nnn +* $nnn + +will be used. This is not recommended with SQL Server. +There is at least one existing `won't fix` issue with the query parsing. + +Use the native "@Name" parameters instead with the "sqlserver" driver name. + ## Known Issues * SQL Server 2008 and 2008 R2 engine cannot handle login records when SSL encryption is not disabled. diff --git a/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml new file mode 100644 index 0000000000..2c1435507b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml @@ -0,0 +1,45 @@ +version: 1.0.{build} + +os: Windows Server 2012 R2 + +clone_folder: c:\gopath\src\github.com\denisenkom\go-mssqldb + +environment: + GOPATH: c:\gopath + HOST: localhost + SQLUSER: sa + SQLPASSWORD: Password12! + DATABASE: test + GOVERSION: 110 + matrix: + - GOVERSION: 18 + SQLINSTANCE: SQL2016 + - GOVERSION: 110 + SQLINSTANCE: SQL2016 + - SQLINSTANCE: SQL2014 + - SQLINSTANCE: SQL2012SP1 + - SQLINSTANCE: SQL2008R2SP2 + +install: + - set GOROOT=c:\go%GOVERSION% + - set PATH=%GOPATH%\bin;%GOROOT%\bin;%PATH% + - go version + - go env + +build_script: + - go build + +before_test: + # setup SQL Server + - ps: | + $instanceName = $env:SQLINSTANCE + Start-Service "MSSQL`$$instanceName" + Start-Service "SQLBrowser" + - sqlcmd -S "(local)\%SQLINSTANCE%" -Q "Use [master]; CREATE DATABASE test;" + - sqlcmd -S "(local)\%SQLINSTANCE%" -h -1 -Q "set nocount on; Select @@version" + - pip install codecov + + +test_script: + - go test -race -coverprofile=coverage.txt -covermode=atomic + - codecov -f coverage.txt diff --git a/vendor/github.com/denisenkom/go-mssqldb/buf.go b/vendor/github.com/denisenkom/go-mssqldb/buf.go index 42e8ae345c..365acd4833 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/buf.go +++ b/vendor/github.com/denisenkom/go-mssqldb/buf.go @@ -2,12 +2,14 @@ package mssql import ( "encoding/binary" - "io" "errors" + "io" ) +type packetType uint8 + type header struct { - PacketType uint8 + PacketType packetType Status uint8 Size uint16 Spid uint16 @@ -15,55 +17,84 @@ type header struct { Pad uint8 } +// tdsBuffer reads and writes TDS packets of data to the transport. +// The write and read buffers are separate to make sending attn signals +// possible without locks. Currently attn signals are only sent during +// reads, not writes. type tdsBuffer struct { - buf []byte - pos uint16 - transport io.ReadWriteCloser - size uint16 + transport io.ReadWriteCloser + + packetSize int + + // Write fields. + wbuf []byte + wpos int + wPacketSeq byte + wPacketType packetType + + // Read fields. + rbuf []byte + rpos int + rsize int final bool - packet_type uint8 - afterFirst func() + rPacketType packetType + + // afterFirst is assigned to right after tdsBuffer is created and + // before the first use. It is executed after the first packet is + // written and then removed. + afterFirst func() } -func newTdsBuffer(bufsize int, transport io.ReadWriteCloser) *tdsBuffer { - buf := make([]byte, bufsize) - w := new(tdsBuffer) - w.buf = buf - w.pos = 8 - w.transport = transport - w.size = 0 - return w +func newTdsBuffer(bufsize uint16, transport io.ReadWriteCloser) *tdsBuffer { + return &tdsBuffer{ + packetSize: int(bufsize), + wbuf: make([]byte, 1<<16), + rbuf: make([]byte, 1<<16), + rpos: 8, + transport: transport, + } +} + +func (rw *tdsBuffer) ResizeBuffer(packetSize int) { + rw.packetSize = packetSize +} + +func (w *tdsBuffer) PackageSize() int { + return w.packetSize } func (w *tdsBuffer) flush() (err error) { - // writing packet size - binary.BigEndian.PutUint16(w.buf[2:], w.pos) + // Write packet size. + w.wbuf[0] = byte(w.wPacketType) + binary.BigEndian.PutUint16(w.wbuf[2:], uint16(w.wpos)) + w.wbuf[6] = w.wPacketSeq - // writing packet into underlying transport - if _, err = w.transport.Write(w.buf[:w.pos]); err != nil { + // Write packet into underlying transport. + if _, err = w.transport.Write(w.wbuf[:w.wpos]); err != nil { return err } + // It is possible to create a whole new buffer after a flush. + // Useful for debugging. Normally reuse the buffer. + // w.wbuf = make([]byte, 1<<16) - // execute afterFirst hook if it is set + // Execute afterFirst hook if it is set. if w.afterFirst != nil { w.afterFirst() w.afterFirst = nil } - w.pos = 8 - // packet number - w.buf[6] += 1 + w.wpos = 8 + w.wPacketSeq++ return nil } func (w *tdsBuffer) Write(p []byte) (total int, err error) { - total = 0 for { - copied := copy(w.buf[w.pos:], p) - w.pos += uint16(copied) + copied := copy(w.wbuf[w.wpos:w.packetSize], p) + w.wpos += copied total += copied if copied == len(p) { - break + return } if err = w.flush(); err != nil { return @@ -74,66 +105,64 @@ func (w *tdsBuffer) Write(p []byte) (total int, err error) { } func (w *tdsBuffer) WriteByte(b byte) error { - if int(w.pos) == len(w.buf) { + if int(w.wpos) == len(w.wbuf) { if err := w.flush(); err != nil { return err } } - w.buf[w.pos] = b - w.pos += 1 + w.wbuf[w.wpos] = b + w.wpos += 1 return nil } -func (w *tdsBuffer) BeginPacket(packet_type byte) { - w.buf[0] = packet_type - w.buf[1] = 0 // packet is incomplete - w.buf[4] = 0 // spid - w.buf[5] = 0 - w.buf[6] = 1 // packet id - w.buf[7] = 0 // window - w.pos = 8 +func (w *tdsBuffer) BeginPacket(packetType packetType) { + w.wbuf[1] = 0 // Packet is incomplete. This byte is set again in FinishPacket. + w.wpos = 8 + w.wPacketSeq = 1 + w.wPacketType = packetType } func (w *tdsBuffer) FinishPacket() error { - w.buf[1] = 1 // this is last packet + w.wbuf[1] = 1 // Mark this as the last packet in the message. return w.flush() } +var headerSize = binary.Size(header{}) + func (r *tdsBuffer) readNextPacket() error { - header := header{} + h := header{} var err error - err = binary.Read(r.transport, binary.BigEndian, &header) + err = binary.Read(r.transport, binary.BigEndian, &h) if err != nil { return err } - offset := uint16(binary.Size(header)) - if int(header.Size) > len(r.buf) { + if int(h.Size) > len(r.rbuf) { return errors.New("Invalid packet size, it is longer than buffer size") } - if int(offset) > int(header.Size) { + if headerSize > int(h.Size) { return errors.New("Invalid packet size, it is shorter than header size") } - _, err = io.ReadFull(r.transport, r.buf[offset:header.Size]) + _, err = io.ReadFull(r.transport, r.rbuf[headerSize:h.Size]) if err != nil { return err } - r.pos = offset - r.size = header.Size - r.final = header.Status != 0 - r.packet_type = header.PacketType + r.rpos = headerSize + r.rsize = int(h.Size) + r.final = h.Status != 0 + r.rPacketType = h.PacketType return nil } -func (r *tdsBuffer) BeginRead() (uint8, error) { +func (r *tdsBuffer) BeginRead() (packetType, error) { err := r.readNextPacket() if err != nil { return 0, err } - return r.packet_type, nil + return r.rPacketType, nil } func (r *tdsBuffer) ReadByte() (res byte, err error) { - if r.pos == r.size { + if r.rpos == r.rsize { if r.final { return 0, io.EOF } @@ -142,8 +171,8 @@ func (r *tdsBuffer) ReadByte() (res byte, err error) { return 0, err } } - res = r.buf[r.pos] - r.pos++ + res = r.rbuf[r.rpos] + r.rpos++ return res, nil } @@ -207,7 +236,7 @@ func (r *tdsBuffer) readUcs2(numchars int) string { func (r *tdsBuffer) Read(buf []byte) (copied int, err error) { copied = 0 err = nil - if r.pos == r.size { + if r.rpos == r.rsize { if r.final { return 0, io.EOF } @@ -216,7 +245,7 @@ func (r *tdsBuffer) Read(buf []byte) (copied int, err error) { return } } - copied = copy(buf, r.buf[r.pos:r.size]) - r.pos += uint16(copied) + copied = copy(buf, r.rbuf[r.rpos:r.rsize]) + r.rpos += copied return } diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go new file mode 100644 index 0000000000..8c0a4e0a2a --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go @@ -0,0 +1,616 @@ +package mssql + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "math" + "reflect" + "strconv" + "strings" + "time" +) + +type Bulk struct { + cn *Conn + metadata []columnStruct + bulkColumns []columnStruct + columnsName []string + tablename string + numRows int + + headerSent bool + Options BulkOptions + Debug bool +} +type BulkOptions struct { + CheckConstraints bool + FireTriggers bool + KeepNulls bool + KilobytesPerBatch int + RowsPerBatch int + Order []string + Tablock bool +} + +type DataValue interface{} + +func (cn *Conn) CreateBulk(table string, columns []string) (_ *Bulk) { + b := Bulk{cn: cn, tablename: table, headerSent: false, columnsName: columns} + b.Debug = false + return &b +} + +func (b *Bulk) sendBulkCommand() (err error) { + //get table columns info + err = b.getMetadata() + if err != nil { + return err + } + + //match the columns + for _, colname := range b.columnsName { + var bulkCol *columnStruct + + for _, m := range b.metadata { + if m.ColName == colname { + bulkCol = &m + break + } + } + if bulkCol != nil { + + if bulkCol.ti.TypeId == typeUdt { + //send udt as binary + bulkCol.ti.TypeId = typeBigVarBin + } + b.bulkColumns = append(b.bulkColumns, *bulkCol) + b.dlogf("Adding column %s %s %#x", colname, bulkCol.ColName, bulkCol.ti.TypeId) + } else { + return fmt.Errorf("Column %s does not exist in destination table %s", colname, b.tablename) + } + } + + //create the bulk command + + //columns definitions + var col_defs bytes.Buffer + for i, col := range b.bulkColumns { + if i != 0 { + col_defs.WriteString(", ") + } + col_defs.WriteString("[" + col.ColName + "] " + makeDecl(col.ti)) + } + + //options + var with_opts []string + + if b.Options.CheckConstraints { + with_opts = append(with_opts, "CHECK_CONSTRAINTS") + } + if b.Options.FireTriggers { + with_opts = append(with_opts, "FIRE_TRIGGERS") + } + if b.Options.KeepNulls { + with_opts = append(with_opts, "KEEP_NULLS") + } + if b.Options.KilobytesPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("KILOBYTES_PER_BATCH = %d", b.Options.KilobytesPerBatch)) + } + if b.Options.RowsPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("ROWS_PER_BATCH = %d", b.Options.RowsPerBatch)) + } + if len(b.Options.Order) > 0 { + with_opts = append(with_opts, fmt.Sprintf("ORDER(%s)", strings.Join(b.Options.Order, ","))) + } + if b.Options.Tablock { + with_opts = append(with_opts, "TABLOCK") + } + var with_part string + if len(with_opts) > 0 { + with_part = fmt.Sprintf("WITH (%s)", strings.Join(with_opts, ",")) + } + + query := fmt.Sprintf("INSERT BULK %s (%s) %s", b.tablename, col_defs.String(), with_part) + + stmt, err := b.cn.Prepare(query) + if err != nil { + return fmt.Errorf("Prepare failed: %s", err.Error()) + } + b.dlogf(query) + + _, err = stmt.Exec(nil) + if err != nil { + return err + } + + b.headerSent = true + + var buf = b.cn.sess.buf + buf.BeginPacket(packBulkLoadBCP) + + // send the columns metadata + columnMetadata := b.createColMetadata() + _, err = buf.Write(columnMetadata) + + return +} + +// AddRow immediately writes the row to the destination table. +// The arguments are the row values in the order they were specified. +func (b *Bulk) AddRow(row []interface{}) (err error) { + if !b.headerSent { + err = b.sendBulkCommand() + if err != nil { + return + } + } + + if len(row) != len(b.bulkColumns) { + return fmt.Errorf("Row does not have the same number of columns than the destination table %d %d", + len(row), len(b.bulkColumns)) + } + + bytes, err := b.makeRowData(row) + if err != nil { + return + } + + _, err = b.cn.sess.buf.Write(bytes) + if err != nil { + return + } + + b.numRows = b.numRows + 1 + return +} + +func (b *Bulk) makeRowData(row []interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenRow)) + + var logcol bytes.Buffer + for i, col := range b.bulkColumns { + + if b.Debug { + logcol.WriteString(fmt.Sprintf(" col[%d]='%v' ", i, row[i])) + } + param, err := b.makeParam(row[i], col) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + + if col.ti.Writer == nil { + return nil, fmt.Errorf("no writer for column: %s, TypeId: %#x", + col.ColName, col.ti.TypeId) + } + err = col.ti.Writer(buf, param.ti, param.buffer) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + } + + b.dlogf("row[%d] %s\n", b.numRows, logcol.String()) + + return buf.Bytes(), nil +} + +func (b *Bulk) Done() (rowcount int64, err error) { + if b.headerSent == false { + //no rows had been sent + return 0, nil + } + var buf = b.cn.sess.buf + buf.WriteByte(byte(tokenDone)) + + binary.Write(buf, binary.LittleEndian, uint16(doneFinal)) + binary.Write(buf, binary.LittleEndian, uint16(0)) // curcmd + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint64(0)) //rowcount 0 + } else { + binary.Write(buf, binary.LittleEndian, uint32(0)) //rowcount 0 + } + + buf.FinishPacket() + + tokchan := make(chan tokenStruct, 5) + go processResponse(context.Background(), b.cn.sess, tokchan, nil) + + var rowCount int64 + for token := range tokchan { + switch token := token.(type) { + case doneStruct: + if token.Status&doneCount != 0 { + rowCount = int64(token.RowCount) + } + if token.isError() { + return 0, token.getError() + } + case error: + return 0, b.cn.checkBadConn(token) + } + } + return rowCount, nil +} + +func (b *Bulk) createColMetadata() []byte { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenColMetadata)) // token + binary.Write(buf, binary.LittleEndian, uint16(len(b.bulkColumns))) // column count + + for i, col := range b.bulkColumns { + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint32(col.UserType)) // usertype, always 0? + } else { + binary.Write(buf, binary.LittleEndian, uint16(col.UserType)) + } + binary.Write(buf, binary.LittleEndian, uint16(col.Flags)) + + writeTypeInfo(buf, &b.bulkColumns[i].ti) + + if col.ti.TypeId == typeNText || + col.ti.TypeId == typeText || + col.ti.TypeId == typeImage { + + tablename_ucs2 := str2ucs2(b.tablename) + binary.Write(buf, binary.LittleEndian, uint16(len(tablename_ucs2)/2)) + buf.Write(tablename_ucs2) + } + colname_ucs2 := str2ucs2(col.ColName) + buf.WriteByte(uint8(len(colname_ucs2) / 2)) + buf.Write(colname_ucs2) + } + + return buf.Bytes() +} + +func (b *Bulk) getMetadata() (err error) { + stmt, err := b.cn.Prepare("SET FMTONLY ON") + if err != nil { + return + } + + _, err = stmt.Exec(nil) + if err != nil { + return + } + + //get columns info + stmt, err = b.cn.Prepare(fmt.Sprintf("select * from %s SET FMTONLY OFF", b.tablename)) + if err != nil { + return + } + stmt2 := stmt.(*Stmt) + cols, err := stmt2.QueryMeta() + if err != nil { + return fmt.Errorf("get columns info failed: %v", err.Error()) + } + b.metadata = cols + + if b.Debug { + for _, col := range b.metadata { + b.dlogf("col: %s typeId: %#x size: %d scale: %d prec: %d flags: %d lcid: %#x\n", + col.ColName, col.ti.TypeId, col.ti.Size, col.ti.Scale, col.ti.Prec, + col.Flags, col.ti.Collation.LcidAndFlags) + } + } + + return nil +} + +// QueryMeta is almost the same as mssql.Stmt.Query, but returns all the columns info. +func (s *Stmt) QueryMeta() (cols []columnStruct, err error) { + if err = s.sendQuery(nil); err != nil { + return + } + tokchan := make(chan tokenStruct, 5) + go processResponse(context.Background(), s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() +loop: + for tok := range tokchan { + switch token := tok.(type) { + case doneStruct: + break loop + case []columnStruct: + cols = token + break loop + case error: + return nil, s.c.checkBadConn(token) + } + } + return cols, nil +} + +func (b *Bulk) makeParam(val DataValue, col columnStruct) (res Param, err error) { + res.ti.Size = col.ti.Size + res.ti.TypeId = col.ti.TypeId + + if val == nil { + res.ti.Size = 0 + return + } + + switch col.ti.TypeId { + + case typeInt1, typeInt2, typeInt4, typeInt8, typeIntN: + var intvalue int64 + + switch val := val.(type) { + case int: + intvalue = int64(val) + case int32: + intvalue = int64(val) + case int64: + intvalue = val + default: + err = fmt.Errorf("mssql: invalid type for int column") + return + } + + res.buffer = make([]byte, res.ti.Size) + if col.ti.Size == 1 { + res.buffer[0] = byte(intvalue) + } else if col.ti.Size == 2 { + binary.LittleEndian.PutUint16(res.buffer, uint16(intvalue)) + } else if col.ti.Size == 4 { + binary.LittleEndian.PutUint32(res.buffer, uint32(intvalue)) + } else if col.ti.Size == 8 { + binary.LittleEndian.PutUint64(res.buffer, uint64(intvalue)) + } + case typeFlt4, typeFlt8, typeFltN: + var floatvalue float64 + + switch val := val.(type) { + case float32: + floatvalue = float64(val) + case float64: + floatvalue = val + case int: + floatvalue = float64(val) + case int64: + floatvalue = float64(val) + default: + err = fmt.Errorf("mssql: invalid type for float column: %s", val) + return + } + + if col.ti.Size == 4 { + res.buffer = make([]byte, 4) + binary.LittleEndian.PutUint32(res.buffer, math.Float32bits(float32(floatvalue))) + } else if col.ti.Size == 8 { + res.buffer = make([]byte, 8) + binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(floatvalue)) + } + case typeNVarChar, typeNText, typeNChar: + + switch val := val.(type) { + case string: + res.buffer = str2ucs2(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for nvarchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeVarChar, typeBigVarChar, typeText, typeChar, typeBigChar: + switch val := val.(type) { + case string: + res.buffer = []byte(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for varchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeBit, typeBitN: + if reflect.TypeOf(val).Kind() != reflect.Bool { + err = fmt.Errorf("mssql: invalid type for bit column: %s", val) + return + } + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = make([]byte, 1) + if val.(bool) { + res.buffer[0] = 1 + } + + case typeDateTime2N, typeDateTimeOffsetN: + switch val := val.(type) { + case time.Time: + days, ns := dateTime2(val) + ns /= int64(math.Pow10(int(col.ti.Scale)*-1) * 1000000000) + + var data = make([]byte, 5) + + data[0] = byte(ns) + data[1] = byte(ns >> 8) + data[2] = byte(ns >> 16) + data[3] = byte(ns >> 24) + data[4] = byte(ns >> 32) + + if col.ti.Scale <= 2 { + res.ti.Size = 6 + } else if col.ti.Scale <= 4 { + res.ti.Size = 7 + } else { + res.ti.Size = 8 + } + var buf []byte + buf = make([]byte, res.ti.Size) + copy(buf, data[0:res.ti.Size-3]) + + buf[res.ti.Size-3] = byte(days) + buf[res.ti.Size-2] = byte(days >> 8) + buf[res.ti.Size-1] = byte(days >> 16) + + if col.ti.TypeId == typeDateTimeOffsetN { + _, offset := val.Zone() + var offsetMinute = uint16(offset / 60) + buf = append(buf, byte(offsetMinute)) + buf = append(buf, byte(offsetMinute>>8)) + res.ti.Size = res.ti.Size + 2 + } + + res.buffer = buf + + default: + err = fmt.Errorf("mssql: invalid type for datetime2 column: %s", val) + return + } + case typeDateN: + switch val := val.(type) { + case time.Time: + days, _ := dateTime2(val) + + res.ti.Size = 3 + res.buffer = make([]byte, 3) + res.buffer[0] = byte(days) + res.buffer[1] = byte(days >> 8) + res.buffer[2] = byte(days >> 16) + default: + err = fmt.Errorf("mssql: invalid type for date column: %s", val) + return + } + case typeDateTime, typeDateTimeN, typeDateTim4: + switch val := val.(type) { + case time.Time: + if col.ti.Size == 4 { + res.ti.Size = 4 + res.buffer = make([]byte, 4) + + ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + dur := val.Sub(ref) + days := dur / (24 * time.Hour) + if days < 0 { + err = fmt.Errorf("mssql: Date %s is out of range", val) + return + } + mins := val.Hour()*60 + val.Minute() + + binary.LittleEndian.PutUint16(res.buffer[0:2], uint16(days)) + binary.LittleEndian.PutUint16(res.buffer[2:4], uint16(mins)) + } else if col.ti.Size == 8 { + res.ti.Size = 8 + res.buffer = make([]byte, 8) + + days := divFloor(val.Unix(), 24*60*60) + //25567 - number of days since Jan 1 1900 UTC to Jan 1 1970 + days = days + 25567 + tm := (val.Hour()*60*60+val.Minute()*60+val.Second())*300 + int(val.Nanosecond()/10000000*3) + + binary.LittleEndian.PutUint32(res.buffer[0:4], uint32(days)) + binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm)) + } else { + err = fmt.Errorf("mssql: invalid size of column") + } + + default: + err = fmt.Errorf("mssql: invalid type for datetime column: %s", val) + } + + // case typeMoney, typeMoney4, typeMoneyN: + case typeDecimal, typeDecimalN, typeNumeric, typeNumericN: + var value float64 + switch v := val.(type) { + case int: + value = float64(v) + case int8: + value = float64(v) + case int16: + value = float64(v) + case int32: + value = float64(v) + case int64: + value = float64(v) + case float32: + value = float64(v) + case float64: + value = v + case string: + if value, err = strconv.ParseFloat(v, 64); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to float: %v", err) + } + default: + return res, fmt.Errorf("unknown value for decimal: %#v", v) + } + + perc := col.ti.Prec + scale := col.ti.Scale + var dec Decimal + dec, err = Float64ToDecimalScale(value, scale) + if err != nil { + return res, err + } + dec.prec = perc + + var length byte + switch { + case perc <= 9: + length = 4 + case perc <= 19: + length = 8 + case perc <= 28: + length = 12 + default: + length = 16 + } + + buf := make([]byte, length+1) + // first byte length written by typeInfo.writer + res.ti.Size = int(length) + 1 + // second byte sign + if value < 0 { + buf[0] = 0 + } else { + buf[0] = 1 + } + + ub := dec.UnscaledBytes() + l := len(ub) + if l > int(length) { + err = fmt.Errorf("decimal out of range: %s", dec) + return res, err + } + // reverse the bytes + for i, j := 1, l-1; j >= 0; i, j = i+1, j-1 { + buf[i] = ub[j] + } + res.buffer = buf + case typeBigVarBin: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Binary column: %s", val) + return + } + case typeGuid: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Guid column: %s", val) + return + } + + default: + err = fmt.Errorf("mssql: type %x not implemented", col.ti.TypeId) + } + return + +} + +func (b *Bulk) dlogf(format string, v ...interface{}) { + if b.Debug { + b.cn.sess.log.Printf(format, v...) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go new file mode 100644 index 0000000000..0af51df890 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go @@ -0,0 +1,93 @@ +package mssql + +import ( + "context" + "database/sql/driver" + "encoding/json" + "errors" +) + +type copyin struct { + cn *Conn + bulkcopy *Bulk + closed bool +} + +type serializableBulkConfig struct { + TableName string + ColumnsName []string + Options BulkOptions +} + +func (d *Driver) OpenConnection(dsn string) (*Conn, error) { + return d.open(context.Background(), dsn) +} + +func (c *Conn) prepareCopyIn(query string) (_ driver.Stmt, err error) { + config_json := query[11:] + + bulkconfig := serializableBulkConfig{} + err = json.Unmarshal([]byte(config_json), &bulkconfig) + if err != nil { + return + } + + bulkcopy := c.CreateBulk(bulkconfig.TableName, bulkconfig.ColumnsName) + bulkcopy.Options = bulkconfig.Options + + ci := ©in{ + cn: c, + bulkcopy: bulkcopy, + } + + return ci, nil +} + +func CopyIn(table string, options BulkOptions, columns ...string) string { + bulkconfig := &serializableBulkConfig{TableName: table, Options: options, ColumnsName: columns} + + config_json, err := json.Marshal(bulkconfig) + if err != nil { + panic(err) + } + + stmt := "INSERTBULK " + string(config_json) + + return stmt +} + +func (ci *copyin) NumInput() int { + return -1 +} + +func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { + return nil, errors.New("ErrNotSupported") +} + +func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { + if ci.closed { + return nil, errors.New("errCopyInClosed") + } + + if len(v) == 0 { + rowCount, err := ci.bulkcopy.Done() + ci.closed = true + return driver.RowsAffected(rowCount), err + } + + t := make([]interface{}, len(v)) + for i, val := range v { + t[i] = val + } + + err = ci.bulkcopy.AddRow(t) + if err != nil { + return + } + + return driver.RowsAffected(0), nil +} + +func (ci *copyin) Close() (err error) { + return nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/collation.go b/vendor/github.com/denisenkom/go-mssqldb/collation.go deleted file mode 100644 index ac9cf20b7b..0000000000 --- a/vendor/github.com/denisenkom/go-mssqldb/collation.go +++ /dev/null @@ -1,39 +0,0 @@ -package mssql - -import ( - "encoding/binary" - "io" -) - -// http://msdn.microsoft.com/en-us/library/dd340437.aspx - -type collation struct { - lcidAndFlags uint32 - sortId uint8 -} - -func (c collation) getLcid() uint32 { - return c.lcidAndFlags & 0x000fffff -} - -func (c collation) getFlags() uint32 { - return (c.lcidAndFlags & 0x0ff00000) >> 20 -} - -func (c collation) getVersion() uint32 { - return (c.lcidAndFlags & 0xf0000000) >> 28 -} - -func readCollation(r *tdsBuffer) (res collation) { - res.lcidAndFlags = r.uint32() - res.sortId = r.byte() - return -} - -func writeCollation(w io.Writer, col collation) (err error) { - if err = binary.Write(w, binary.LittleEndian, col.lcidAndFlags); err != nil { - return - } - err = binary.Write(w, binary.LittleEndian, col.sortId) - return -} diff --git a/vendor/github.com/denisenkom/go-mssqldb/decimal.go b/vendor/github.com/denisenkom/go-mssqldb/decimal.go index 76f3a6b5b4..372f64b4eb 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/decimal.go +++ b/vendor/github.com/denisenkom/go-mssqldb/decimal.go @@ -32,7 +32,13 @@ func (d Decimal) ToFloat64() float64 { return val } +const autoScale = 100 + func Float64ToDecimal(f float64) (Decimal, error) { + return Float64ToDecimalScale(f, autoScale) +} + +func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { var dec Decimal if math.IsNaN(f) { return dec, errors.New("NaN") @@ -49,10 +55,10 @@ func Float64ToDecimal(f float64) (Decimal, error) { } dec.prec = 20 var integer float64 - for dec.scale = 0; dec.scale <= 20; dec.scale++ { + for dec.scale = 0; dec.scale <= scale; dec.scale++ { integer = f * scaletblflt64[dec.scale] _, frac := math.Modf(integer) - if frac == 0 { + if frac == 0 && scale == autoScale { break } } @@ -73,7 +79,7 @@ func init() { } } -func (d Decimal) Bytes() []byte { +func (d Decimal) BigInt() big.Int { bytes := make([]byte, 16) binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) @@ -84,9 +90,19 @@ func (d Decimal) Bytes() []byte { if !d.positive { x.Neg(&x) } + return x +} + +func (d Decimal) Bytes() []byte { + x := d.BigInt() return scaleBytes(x.String(), d.scale) } +func (d Decimal) UnscaledBytes() []byte { + x := d.BigInt() + return x.Bytes() +} + func scaleBytes(s string, scale uint8) []byte { z := make([]byte, 0, len(s)+1) if s[0] == '-' || s[0] == '+' { diff --git a/vendor/github.com/denisenkom/go-mssqldb/doc.go b/vendor/github.com/denisenkom/go-mssqldb/doc.go new file mode 100644 index 0000000000..1bb80c442b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/doc.go @@ -0,0 +1,12 @@ +// package mssql implements the TDS protocol used to connect to MS SQL Server (sqlserver) +// database servers. +// +// This package registers two drivers: +// sqlserver: uses native "@" parameter placeholder names and does no pre-processing. +// mssql: expects identifiers to be prefixed with ":" and pre-processes queries. +// +// If the ordinal position is used for query parameters, identifiers will be named +// "@p1", "@p2", ... "@pN". +// +// Please refer to the README for the format of the DSN. +package mssql diff --git a/vendor/github.com/denisenkom/go-mssqldb/charset.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go similarity index 94% rename from vendor/github.com/denisenkom/go-mssqldb/charset.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go index f1cc247a9d..8dc2279ea4 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/charset.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go @@ -1,14 +1,14 @@ -package mssql +package cp type charsetMap struct { sb [256]rune // single byte runes, -1 for a double byte character lead byte db map[int]rune // double byte runes } -func collation2charset(col collation) *charsetMap { +func collation2charset(col Collation) *charsetMap { // http://msdn.microsoft.com/en-us/library/ms144250.aspx // http://msdn.microsoft.com/en-us/library/ms144250(v=sql.105).aspx - switch col.sortId { + switch col.SortId { case 30, 31, 32, 33, 34: return cp437 case 40, 41, 42, 44, 49, 55, 56, 57, 58, 59, 60, 61: @@ -86,7 +86,7 @@ func collation2charset(col collation) *charsetMap { return cp1252 } -func charset2utf8(col collation, s []byte) string { +func CharsetToUTF8(col Collation, s []byte) string { cm := collation2charset(col) if cm == nil { return string(s) diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go new file mode 100644 index 0000000000..ae7b03bf13 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go @@ -0,0 +1,20 @@ +package cp + +// http://msdn.microsoft.com/en-us/library/dd340437.aspx + +type Collation struct { + LcidAndFlags uint32 + SortId uint8 +} + +func (c Collation) getLcid() uint32 { + return c.LcidAndFlags & 0x000fffff +} + +func (c Collation) getFlags() uint32 { + return (c.LcidAndFlags & 0x0ff00000) >> 20 +} + +func (c Collation) getVersion() uint32 { + return (c.LcidAndFlags & 0xf0000000) >> 28 +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1250.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1250.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go index 8207366be7..5c8094ec3c 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1250.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1250 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1251.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1251.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go index f5b81c3934..dc5896770c 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1251.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1251 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1252.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1252.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go index ed705d35a7..5ae8703542 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1252.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1252 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1253.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1253.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go index cb1e1a7623..52c8e07aa6 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1253.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1253 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1254.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1254.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go index a4b09bb44f..5d8864a521 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1254.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1254 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1255.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1255.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go index 97f9ee9e91..60619895d9 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1255.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1255 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1256.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1256.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go index e91241b448..ffd04b3e5b 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1256.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1256 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1257.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1257.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go index bd93e6f891..492da72ea4 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1257.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1257 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1258.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1258.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go index 4e1f8ac943..80be52c596 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1258.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1258 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp437.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp437.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go index f47f8ecc77..76dedfb8ef 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp437.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp437 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp850.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp850.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go index e6b3d16904..927ab249ef 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp850.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp850 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp874.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp874.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go index 9d691a1a59..723bf6c392 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp874.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp874 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp932.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp932.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go index 980c55d815..5fc1377424 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp932.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp932 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp936.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp936.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go index fca5da76d4..d1fac12e26 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp936.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp936 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp949.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp949.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go index cddfcbc852..52c708dfa5 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp949.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp949 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp950.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp950.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go index cbf25cb91a..1301cd0f05 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp950.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp950 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/log.go b/vendor/github.com/denisenkom/go-mssqldb/log.go index f350aed099..9b8c551e88 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/log.go +++ b/vendor/github.com/denisenkom/go-mssqldb/log.go @@ -4,19 +4,26 @@ import ( "log" ) -type Logger log.Logger +type Logger interface { + Printf(format string, v ...interface{}) + Println(v ...interface{}) +} -func (logger *Logger) Printf(format string, v ...interface{}) { - if logger != nil { - (*log.Logger)(logger).Printf(format, v...) +type optionalLogger struct { + logger Logger +} + +func (o optionalLogger) Printf(format string, v ...interface{}) { + if o.logger != nil { + o.logger.Printf(format, v...) } else { log.Printf(format, v...) } } -func (logger *Logger) Println(v ...interface{}) { - if logger != nil { - (*log.Logger)(logger).Println(v...) +func (o optionalLogger) Println(v ...interface{}) { + if o.logger != nil { + o.logger.Println(v...) } else { log.Println(v...) } diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql.go b/vendor/github.com/denisenkom/go-mssqldb/mssql.go index 9663651e7c..8f5ff2d0ce 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/mssql.go +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql.go @@ -1,122 +1,269 @@ package mssql import ( + "context" "database/sql" "database/sql/driver" "encoding/binary" "errors" "fmt" "io" - "log" "math" "net" + "reflect" "strings" "time" ) +var driverInstance = &Driver{processQueryText: true} +var driverInstanceNoProcess = &Driver{processQueryText: false} + func init() { - sql.Register("mssql", &MssqlDriver{}) + sql.Register("mssql", driverInstance) + sql.Register("sqlserver", driverInstanceNoProcess) + createDialer = func(p *connectParams) dialer { + return tcpDialer{&net.Dialer{Timeout: p.dial_timeout, KeepAlive: p.keepAlive}} + } } -type MssqlDriver struct { - log *log.Logger +// Abstract the dialer for testing and for non-TCP based connections. +type dialer interface { + Dial(ctx context.Context, addr string) (net.Conn, error) } -func (d *MssqlDriver) SetLogger(logger *log.Logger) { - d.log = logger +var createDialer func(p *connectParams) dialer + +type tcpDialer struct { + nd *net.Dialer } -func CheckBadConn(err error) error { - if err == io.EOF { +func (d tcpDialer) Dial(ctx context.Context, addr string) (net.Conn, error) { + return d.nd.DialContext(ctx, "tcp", addr) +} + +type Driver struct { + log optionalLogger + + processQueryText bool +} + +// OpenConnector opens a new connector. Useful to dial with a context. +func (d *Driver) OpenConnector(dsn string) (*Connector, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + return &Connector{ + params: params, + driver: d, + }, nil +} + +func (d *Driver) Open(dsn string) (driver.Conn, error) { + return d.open(context.Background(), dsn) +} + +// Connector holds the parsed DSN and is ready to make a new connection +// at any time. +// +// In the future, settings that cannot be passed through a string DSN +// may be set directly on the connector. +type Connector struct { + params connectParams + driver *Driver +} + +// Connect to the server and return a TDS connection. +func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { + return c.driver.connect(ctx, c.params) +} + +// Driver underlying the Connector. +func (c *Connector) Driver() driver.Driver { + return c.driver +} + +func SetLogger(logger Logger) { + driverInstance.SetLogger(logger) + driverInstanceNoProcess.SetLogger(logger) +} + +func (d *Driver) SetLogger(logger Logger) { + d.log = optionalLogger{logger} +} + +type Conn struct { + sess *tdsSession + transactionCtx context.Context + + processQueryText bool + connectionGood bool + + outs map[string]interface{} +} + +func (c *Conn) checkBadConn(err error) error { + // this is a hack to address Issue #275 + // we set connectionGood flag to false if + // error indicates that connection is not usable + // but we return actual error instead of ErrBadConn + // this will cause connection to stay in a pool + // but next request to this connection will return ErrBadConn + + // it might be possible to revise this hack after + // https://github.com/golang/go/issues/20807 + // is implemented + switch err { + case nil: + return nil + case io.EOF: return driver.ErrBadConn + case driver.ErrBadConn: + // It is an internal programming error if driver.ErrBadConn + // is ever passed to this function. driver.ErrBadConn should + // only ever be returned in response to a *mssql.Conn.connectionGood == false + // check in the external facing API. + panic("driver.ErrBadConn in checkBadConn. This should not happen.") } - switch e := err.(type) { + switch err.(type) { case net.Error: - if e.Timeout() { - return e - } - return driver.ErrBadConn + c.connectionGood = false + return err + case StreamError: + c.connectionGood = false + return err default: return err } } -type MssqlConn struct { - sess *tdsSession +func (c *Conn) clearOuts() { + c.outs = nil } -func (c *MssqlConn) Commit() error { +func (c *Conn) simpleProcessResp(ctx context.Context) error { + tokchan := make(chan tokenStruct, 5) + go processResponse(ctx, c.sess, tokchan, c.outs) + c.clearOuts() + for tok := range tokchan { + switch token := tok.(type) { + case doneStruct: + if token.isError() { + return c.checkBadConn(token.getError()) + } + case error: + return c.checkBadConn(token) + } + } + return nil +} + +func (c *Conn) Commit() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendCommitRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendCommitRequest() error { headers := []headerStruct{ {hdrtype: dataStmHdrTransDescr, data: transDescrHdr{c.sess.tranid, 1}.pack()}, } if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, ""); err != nil { - return err - } - - tokchan := make(chan tokenStruct, 5) - go processResponse(c.sess, tokchan) - for tok := range tokchan { - switch token := tok.(type) { - case error: - return token + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send CommitXact with %v", err) } + c.connectionGood = false + return fmt.Errorf("Faild to send CommitXact: %v", err) } return nil } -func (c *MssqlConn) Rollback() error { +func (c *Conn) Rollback() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendRollbackRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendRollbackRequest() error { headers := []headerStruct{ {hdrtype: dataStmHdrTransDescr, data: transDescrHdr{c.sess.tranid, 1}.pack()}, } if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, ""); err != nil { - return err - } - - tokchan := make(chan tokenStruct, 5) - go processResponse(c.sess, tokchan) - for tok := range tokchan { - switch token := tok.(type) { - case error: - return token + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send RollbackXact with %v", err) } + c.connectionGood = false + return fmt.Errorf("Failed to send RollbackXact: %v", err) } return nil } -func (c *MssqlConn) Begin() (driver.Tx, error) { +func (c *Conn) Begin() (driver.Tx, error) { + return c.begin(context.Background(), isolationUseCurrent) +} + +func (c *Conn) begin(ctx context.Context, tdsIsolation isoLevel) (tx driver.Tx, err error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + err = c.sendBeginRequest(ctx, tdsIsolation) + if err != nil { + return nil, c.checkBadConn(err) + } + tx, err = c.processBeginResponse(ctx) + if err != nil { + return nil, c.checkBadConn(err) + } + return +} + +func (c *Conn) sendBeginRequest(ctx context.Context, tdsIsolation isoLevel) error { + c.transactionCtx = ctx headers := []headerStruct{ {hdrtype: dataStmHdrTransDescr, data: transDescrHdr{0, 1}.pack()}, } - if err := sendBeginXact(c.sess.buf, headers, 0, ""); err != nil { - return nil, CheckBadConn(err) - } - tokchan := make(chan tokenStruct, 5) - go processResponse(c.sess, tokchan) - for tok := range tokchan { - switch token := tok.(type) { - case error: - if c.sess.tranid != 0 { - return nil, token - } - return nil, CheckBadConn(token) + if err := sendBeginXact(c.sess.buf, headers, tdsIsolation, ""); err != nil { + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send BeginXact with %v", err) } + c.connectionGood = false + return fmt.Errorf("Failed to send BiginXant: %v", err) + } + return nil +} + +func (c *Conn) processBeginResponse(ctx context.Context) (driver.Tx, error) { + if err := c.simpleProcessResp(ctx); err != nil { + return nil, err } // successful BEGINXACT request will return sess.tranid // for started transaction return c, nil } -func (d *MssqlDriver) Open(dsn string) (driver.Conn, error) { +func (d *Driver) open(ctx context.Context, dsn string) (*Conn, error) { params, err := parseConnectParams(dsn) if err != nil { return nil, err } + return d.connect(ctx, params) +} - sess, err := connect(params) +// connect to the server, using the provided context for dialing only. +func (d *Driver) connect(ctx context.Context, params connectParams) (*Conn, error) { + sess, err := connect(ctx, d.log, params) if err != nil { // main server failed, try fail-over partner if params.failOverPartner == "" { @@ -128,24 +275,29 @@ func (d *MssqlDriver) Open(dsn string) (driver.Conn, error) { params.port = params.failOverPort } - sess, err = connect(params) + sess, err = connect(ctx, d.log, params) if err != nil { // fail-over partner also failed, now fail return nil, err } } - conn := &MssqlConn{sess} - conn.sess.log = (*Logger)(d.log) + conn := &Conn{ + sess: sess, + transactionCtx: context.Background(), + processQueryText: d.processQueryText, + connectionGood: true, + } + conn.sess.log = d.log return conn, nil } -func (c *MssqlConn) Close() error { +func (c *Conn) Close() error { return c.sess.buf.transport.Close() } -type MssqlStmt struct { - c *MssqlConn +type Stmt struct { + c *Conn query string paramCount int notifSub *queryNotifSub @@ -157,16 +309,30 @@ type queryNotifSub struct { timeout uint32 } -func (c *MssqlConn) Prepare(query string) (driver.Stmt, error) { - q, paramCount := parseParams(query) - return &MssqlStmt{c, q, paramCount, nil}, nil +func (c *Conn) Prepare(query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(query) + } + + return c.prepareContext(context.Background(), query) } -func (s *MssqlStmt) Close() error { +func (c *Conn) prepareContext(ctx context.Context, query string) (*Stmt, error) { + paramCount := -1 + if c.processQueryText { + query, paramCount = parseParams(query) + } + return &Stmt{c, query, paramCount, nil}, nil +} + +func (s *Stmt) Close() error { return nil } -func (s *MssqlStmt) SetQueryNotification(id, options string, timeout time.Duration) { +func (s *Stmt) SetQueryNotification(id, options string, timeout time.Duration) { to := uint32(timeout / time.Second) if to < 1 { to = 1 @@ -174,183 +340,273 @@ func (s *MssqlStmt) SetQueryNotification(id, options string, timeout time.Durati s.notifSub = &queryNotifSub{id, options, to} } -func (s *MssqlStmt) NumInput() int { +func (s *Stmt) NumInput() int { return s.paramCount } -func (s *MssqlStmt) sendQuery(args []driver.Value) (err error) { +func (s *Stmt) sendQuery(args []namedValue) (err error) { headers := []headerStruct{ {hdrtype: dataStmHdrTransDescr, data: transDescrHdr{s.c.sess.tranid, 1}.pack()}, } if s.notifSub != nil { - headers = append(headers, headerStruct{hdrtype: dataStmHdrQueryNotif, - data: queryNotifHdr{s.notifSub.msgText, s.notifSub.options, s.notifSub.timeout}.pack()}) + headers = append(headers, + headerStruct{ + hdrtype: dataStmHdrQueryNotif, + data: queryNotifHdr{ + s.notifSub.msgText, + s.notifSub.options, + s.notifSub.timeout, + }.pack(), + }) } - if len(args) != s.paramCount { - return errors.New(fmt.Sprintf("sql: expected %d parameters, got %d", s.paramCount, len(args))) - } + // no need to check number of parameters here, it is checked by database/sql if s.c.sess.logFlags&logSQL != 0 { s.c.sess.log.Println(s.query) } if s.c.sess.logFlags&logParams != 0 && len(args) > 0 { for i := 0; i < len(args); i++ { - s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i]) + if len(args[i].Name) > 0 { + s.c.sess.log.Printf("\t@%s\t%v\n", args[i].Name, args[i].Value) + } else { + s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i].Value) + } } } if len(args) == 0 { if err = sendSqlBatch72(s.c.sess.buf, s.query, headers); err != nil { - if s.c.sess.tranid != 0 { - return err + if s.c.sess.logFlags&logErrors != 0 { + s.c.sess.log.Printf("Failed to send SqlBatch with %v", err) } - return CheckBadConn(err) + s.c.connectionGood = false + return fmt.Errorf("failed to send SQL Batch: %v", err) } } else { - params := make([]Param, len(args)+2) - decls := make([]string, len(args)) - params[0], err = s.makeParam(s.query) - if err != nil { - return - } - for i, val := range args { - params[i+2], err = s.makeParam(val) + proc := Sp_ExecuteSql + var params []Param + if isProc(s.query) { + proc.name = s.query + params, _, err = s.makeRPCParams(args, 0) + } else { + var decls []string + params, decls, err = s.makeRPCParams(args, 2) if err != nil { return } - name := fmt.Sprintf("@p%d", i+1) - params[i+2].Name = name - decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+2].ti)) + params[0] = makeStrParam(s.query) + params[1] = makeStrParam(strings.Join(decls, ",")) } - params[1], err = s.makeParam(strings.Join(decls, ",")) - if err != nil { - return - } - if err = sendRpc(s.c.sess.buf, headers, Sp_ExecuteSql, 0, params); err != nil { - if s.c.sess.tranid != 0 { - return err + if err = sendRpc(s.c.sess.buf, headers, proc, 0, params); err != nil { + if s.c.sess.logFlags&logErrors != 0 { + s.c.sess.log.Printf("Failed to send Rpc with %v", err) } - return CheckBadConn(err) + s.c.connectionGood = false + return fmt.Errorf("Failed to send RPC: %v", err) } } return } -func (s *MssqlStmt) Query(args []driver.Value) (res driver.Rows, err error) { - if err = s.sendQuery(args); err != nil { - return +// isProc takes the query text in s and determines if it is a stored proc name +// or SQL text. +func isProc(s string) bool { + if len(s) == 0 { + return false } + if s[0] == '[' && s[len(s)-1] == ']' && strings.ContainsAny(s, "\n\r") == false { + return true + } + return !strings.ContainsAny(s, " \t\n\r;") +} + +func (s *Stmt) makeRPCParams(args []namedValue, offset int) ([]Param, []string, error) { + var err error + params := make([]Param, len(args)+offset) + decls := make([]string, len(args)) + for i, val := range args { + params[i+offset], err = s.makeParam(val.Value) + if err != nil { + return nil, nil, err + } + var name string + if len(val.Name) > 0 { + name = "@" + val.Name + } else { + name = fmt.Sprintf("@p%d", val.Ordinal) + } + params[i+offset].Name = name + decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti)) + } + return params, decls, nil +} + +type namedValue struct { + Name string + Ordinal int + Value driver.Value +} + +func convertOldArgs(args []driver.Value) []namedValue { + list := make([]namedValue, len(args)) + for i, v := range args { + list[i] = namedValue{ + Ordinal: i + 1, + Value: v, + } + } + return list +} + +func (s *Stmt) Query(args []driver.Value) (driver.Rows, error) { + return s.queryContext(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) queryContext(ctx context.Context, args []namedValue) (rows driver.Rows, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + if err = s.sendQuery(args); err != nil { + return nil, s.c.checkBadConn(err) + } + return s.processQueryResponse(ctx) +} + +func (s *Stmt) processQueryResponse(ctx context.Context) (res driver.Rows, err error) { tokchan := make(chan tokenStruct, 5) - go processResponse(s.c.sess, tokchan) + ctx, cancel := context.WithCancel(ctx) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() // process metadata - var cols []string + var cols []columnStruct loop: for tok := range tokchan { switch token := tok.(type) { - // by ignoring DONE token we effectively - // skip empty result-sets - // this improves results in queryes like that: + // By ignoring DONE token we effectively + // skip empty result-sets. + // This improves results in queries like that: // set nocount on; select 1 // see TestIgnoreEmptyResults test //case doneStruct: //break loop case []columnStruct: - cols = make([]string, len(token)) - for i, col := range token { - cols[i] = col.ColName - } + cols = token break loop - case error: - if s.c.sess.tranid != 0 { - return nil, token + case doneStruct: + if token.isError() { + return nil, s.c.checkBadConn(token.getError()) } - return nil, CheckBadConn(token) + case error: + return nil, s.c.checkBadConn(token) } } - return &MssqlRows{sess: s.c.sess, tokchan: tokchan, cols: cols}, nil + res = &Rows{stmt: s, tokchan: tokchan, cols: cols, cancel: cancel} + return } -func (s *MssqlStmt) Exec(args []driver.Value) (res driver.Result, err error) { - if err = s.sendQuery(args); err != nil { - return +func (s *Stmt) Exec(args []driver.Value) (driver.Result, error) { + return s.exec(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) exec(ctx context.Context, args []namedValue) (res driver.Result, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn } + if err = s.sendQuery(args); err != nil { + return nil, s.c.checkBadConn(err) + } + if res, err = s.processExec(ctx); err != nil { + return nil, s.c.checkBadConn(err) + } + return +} + +func (s *Stmt) processExec(ctx context.Context) (res driver.Result, err error) { tokchan := make(chan tokenStruct, 5) - go processResponse(s.c.sess, tokchan) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() var rowCount int64 for token := range tokchan { switch token := token.(type) { case doneInProcStruct: if token.Status&doneCount != 0 { - rowCount = int64(token.RowCount) + rowCount += int64(token.RowCount) } case doneStruct: if token.Status&doneCount != 0 { - rowCount = int64(token.RowCount) + rowCount += int64(token.RowCount) + } + if token.isError() { + return nil, token.getError() } case error: - if s.c.sess.logFlags&logErrors != 0 { - s.c.sess.log.Println("got error:", token) - } - if s.c.sess.tranid != 0 { - return nil, token - } - return nil, CheckBadConn(token) + return nil, token } } - return &MssqlResult{s.c, rowCount}, nil + return &Result{s.c, rowCount}, nil } -type MssqlRows struct { - sess *tdsSession - cols []string +type Rows struct { + stmt *Stmt + cols []columnStruct tokchan chan tokenStruct - nextCols []string + nextCols []columnStruct + + cancel func() } -func (rc *MssqlRows) Close() error { +func (rc *Rows) Close() error { + rc.cancel() for _ = range rc.tokchan { } rc.tokchan = nil return nil } -func (rc *MssqlRows) Columns() (res []string) { - return rc.cols +func (rc *Rows) Columns() (res []string) { + res = make([]string, len(rc.cols)) + for i, col := range rc.cols { + res[i] = col.ColName + } + return } -func (rc *MssqlRows) Next(dest []driver.Value) (err error) { +func (rc *Rows) Next(dest []driver.Value) error { + if !rc.stmt.c.connectionGood { + return driver.ErrBadConn + } if rc.nextCols != nil { return io.EOF } for tok := range rc.tokchan { switch tokdata := tok.(type) { case []columnStruct: - cols := make([]string, len(tokdata)) - for i, col := range tokdata { - cols[i] = col.ColName - } - rc.nextCols = cols + rc.nextCols = tokdata return io.EOF case []interface{}: for i := range dest { dest[i] = tokdata[i] } return nil + case doneStruct: + if tokdata.isError() { + return rc.stmt.c.checkBadConn(tokdata.getError()) + } case error: - return tokdata + return rc.stmt.c.checkBadConn(tokdata) } } return io.EOF } -func (rc *MssqlRows) HasNextResultSet() bool { +func (rc *Rows) HasNextResultSet() bool { return rc.nextCols != nil } -func (rc *MssqlRows) NextResultSet() error { +func (rc *Rows) NextResultSet() error { rc.cols = rc.nextCols rc.nextCols = nil if rc.cols == nil { @@ -359,11 +615,69 @@ func (rc *MssqlRows) NextResultSet() error { return nil } -func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) { +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func (r *Rows) ColumnTypeScanType(index int) reflect.Type { + return makeGoLangScanType(r.cols[index].ti) +} + +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func (r *Rows) ColumnTypeDatabaseTypeName(index int) string { + return makeGoLangTypeName(r.cols[index].ti) +} + +// RowsColumnTypeLength may be implemented by Rows. It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func (r *Rows) ColumnTypeLength(index int) (int64, bool) { + return makeGoLangTypeLength(r.cols[index].ti) +} + +// It should return +// the precision and scale for decimal types. If not applicable, ok should be false. +// The following are examples of returned values for various types: +// decimal(38, 4) (38, 4, true) +// int (0, 0, false) +// decimal (math.MaxInt64, math.MaxInt64, true) +func (r *Rows) ColumnTypePrecisionScale(index int) (int64, int64, bool) { + return makeGoLangTypePrecisionScale(r.cols[index].ti) +} + +// The nullable value should +// be true if it is known the column may be null, or false if the column is known +// to be not nullable. +// If the column nullability is unknown, ok should be false. +func (r *Rows) ColumnTypeNullable(index int) (nullable, ok bool) { + nullable = r.cols[index].Flags&colFlagNullable != 0 + ok = true + return +} + +func makeStrParam(val string) (res Param) { + res.ti.TypeId = typeNVarChar + res.buffer = str2ucs2(val) + res.ti.Size = len(res.buffer) + return +} + +func (s *Stmt) makeParam(val driver.Value) (res Param, err error) { if val == nil { - res.ti.TypeId = typeNVarChar + res.ti.TypeId = typeNull res.buffer = nil - res.ti.Size = 2 + res.ti.Size = 0 return } switch val := val.(type) { @@ -382,9 +696,7 @@ func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) { res.ti.Size = len(val) res.buffer = val case string: - res.ti.TypeId = typeNVarChar - res.buffer = str2ucs2(val) - res.ti.Size = len(res.buffer) + res = makeStrParam(val) case bool: res.ti.TypeId = typeBitN res.ti.Size = 1 @@ -425,22 +737,21 @@ func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) { binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm)) } default: - err = fmt.Errorf("mssql: unknown type for %T", val) - return + return s.makeParamExtra(val) } return } -type MssqlResult struct { - c *MssqlConn +type Result struct { + c *Conn rowsAffected int64 } -func (r *MssqlResult) RowsAffected() (int64, error) { +func (r *Result) RowsAffected() (int64, error) { return r.rowsAffected, nil } -func (r *MssqlResult) LastInsertId() (int64, error) { +func (r *Result) LastInsertId() (int64, error) { s, err := r.c.Prepare("select cast(@@identity as bigint)") if err != nil { return 0, err diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3.go deleted file mode 100644 index b8cffe9c01..0000000000 --- a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build go1.3 - -package mssql - -import ( - "net" -) - -func createDialer(p connectParams) *net.Dialer { - return &net.Dialer{Timeout: p.dial_timeout, KeepAlive: p.keepAlive} -} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3pre.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3pre.go deleted file mode 100644 index 3c7e72716d..0000000000 --- a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3pre.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !go1.3 - -package mssql - -import ( - "net" -) - -func createDialer(p *connectParams) *net.Dialer { - return &net.Dialer{Timeout: p.dial_timeout} -} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go18.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go18.go new file mode 100644 index 0000000000..74179c4720 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go18.go @@ -0,0 +1,91 @@ +// +build go1.8 + +package mssql + +import ( + "context" + "database/sql" + "database/sql/driver" + "errors" + "strings" +) + +var _ driver.Pinger = &Conn{} + +// Ping is used to check if the remote server is available and satisfies the Pinger interface. +func (c *Conn) Ping(ctx context.Context) error { + if !c.connectionGood { + return driver.ErrBadConn + } + stmt := &Stmt{c, `select 1;`, 0, nil} + _, err := stmt.ExecContext(ctx, nil) + return err +} + +var _ driver.ConnBeginTx = &Conn{} + +// BeginTx satisfies ConnBeginTx. +func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if opts.ReadOnly { + return nil, errors.New("Read-only transactions are not supported") + } + + var tdsIsolation isoLevel + switch sql.IsolationLevel(opts.Isolation) { + case sql.LevelDefault: + tdsIsolation = isolationUseCurrent + case sql.LevelReadUncommitted: + tdsIsolation = isolationReadUncommited + case sql.LevelReadCommitted: + tdsIsolation = isolationReadCommited + case sql.LevelWriteCommitted: + return nil, errors.New("LevelWriteCommitted isolation level is not supported") + case sql.LevelRepeatableRead: + tdsIsolation = isolationRepeatableRead + case sql.LevelSnapshot: + tdsIsolation = isolationSnapshot + case sql.LevelSerializable: + tdsIsolation = isolationSerializable + case sql.LevelLinearizable: + return nil, errors.New("LevelLinearizable isolation level is not supported") + default: + return nil, errors.New("Isolation level is not supported or unknown") + } + return c.begin(ctx, tdsIsolation) +} + +func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(query) + } + + return c.prepareContext(ctx, query) +} + +func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.queryContext(ctx, list) +} + +func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.exec(ctx, list) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go new file mode 100644 index 0000000000..250151abc3 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go @@ -0,0 +1,64 @@ +// +build go1.9 + +package mssql + +import ( + "database/sql" + "database/sql/driver" + "fmt" + // "github.com/cockroachdb/apd" +) + +// Type alias provided for compibility. +// +// Deprecated: users should transition to the new names when possible. +type MssqlDriver = Driver +type MssqlBulk = Bulk +type MssqlBulkOptions = BulkOptions +type MssqlConn = Conn +type MssqlResult = Result +type MssqlRows = Rows +type MssqlStmt = Stmt + +var _ driver.NamedValueChecker = &Conn{} + +func (c *Conn) CheckNamedValue(nv *driver.NamedValue) error { + switch v := nv.Value.(type) { + case sql.Out: + if c.outs == nil { + c.outs = make(map[string]interface{}) + } + c.outs[nv.Name] = v.Dest + + // Unwrap the Out value and check the inner value. + lnv := *nv + lnv.Value = v.Dest + err := c.CheckNamedValue(&lnv) + if err != nil { + if err != driver.ErrSkip { + return err + } + lnv.Value, err = driver.DefaultParameterConverter.ConvertValue(lnv.Value) + if err != nil { + return err + } + } + nv.Value = sql.Out{Dest: lnv.Value} + return nil + // case *apd.Decimal: + // return nil + default: + return driver.ErrSkip + } +} + +func (s *Stmt) makeParamExtra(val driver.Value) (res Param, err error) { + switch val := val.(type) { + case sql.Out: + res, err = s.makeParam(val.Dest) + res.Flags = fByRevValue + default: + err = fmt.Errorf("mssql: unknown type for %T", val) + } + return +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go new file mode 100644 index 0000000000..3bad7fb008 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go @@ -0,0 +1,12 @@ +// +build !go1.9 + +package mssql + +import ( + "database/sql/driver" + "fmt" +) + +func (s *Stmt) makeParamExtra(val driver.Value) (Param, error) { + return Param{}, fmt.Errorf("mssql: unknown type for %T", val) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/net.go b/vendor/github.com/denisenkom/go-mssqldb/net.go index 72a87340db..8c3c8ef8b1 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/net.go +++ b/vendor/github.com/denisenkom/go-mssqldb/net.go @@ -33,7 +33,7 @@ func (c *timeoutConn) Read(b []byte) (n int, err error) { c.continueRead = false } if !c.continueRead { - var packet uint8 + var packet packetType packet, err = c.buf.BeginRead() if err != nil { err = fmt.Errorf("Cannot read handshake packet: %s", err.Error()) diff --git a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go index f853435c6e..5bed668430 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go +++ b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go @@ -59,7 +59,7 @@ type NTLMAuth struct { Workstation string } -func getAuth(user, password, service, workstation string) (Auth, bool) { +func getAuth(user, password, service, workstation string) (auth, bool) { if !strings.ContainsRune(user, '\\') { return nil, false } diff --git a/vendor/github.com/denisenkom/go-mssqldb/parser.go b/vendor/github.com/denisenkom/go-mssqldb/parser.go index 9e37c16a65..8021ca603c 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/parser.go +++ b/vendor/github.com/denisenkom/go-mssqldb/parser.go @@ -11,6 +11,9 @@ type parser struct { w bytes.Buffer paramCount int paramMax int + + // using map as a set + namedParams map[string]bool } func (p *parser) next() (rune, bool) { @@ -39,13 +42,14 @@ type stateFunc func(*parser) stateFunc func parseParams(query string) (string, int) { p := &parser{ - r: bytes.NewReader([]byte(query)), + r: bytes.NewReader([]byte(query)), + namedParams: map[string]bool{}, } state := parseNormal for state != nil { state = state(p) } - return p.w.String(), p.paramMax + return p.w.String(), p.paramMax + len(p.namedParams) } func parseNormal(p *parser) stateFunc { @@ -55,7 +59,7 @@ func parseNormal(p *parser) stateFunc { return nil } if ch == '?' { - return parseParameter + return parseOrdinalParameter } else if ch == '$' || ch == ':' { ch2, ok := p.next() if !ok { @@ -64,7 +68,9 @@ func parseNormal(p *parser) stateFunc { } p.unread() if ch2 >= '0' && ch2 <= '9' { - return parseParameter + return parseOrdinalParameter + } else if 'a' <= ch2 && ch2 <= 'z' || 'A' <= ch2 && ch2 <= 'Z' { + return parseNamedParameter } } p.write(ch) @@ -83,7 +89,7 @@ func parseNormal(p *parser) stateFunc { } } -func parseParameter(p *parser) stateFunc { +func parseOrdinalParameter(p *parser) stateFunc { var paramN int var ok bool for { @@ -113,6 +119,30 @@ func parseParameter(p *parser) stateFunc { return parseNormal } +func parseNamedParameter(p *parser) stateFunc { + var paramName string + var ok bool + for { + var ch rune + ch, ok = p.next() + if ok && (ch >= '0' && ch <= '9' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') { + paramName = paramName + string(ch) + } else { + break + } + } + if ok { + p.unread() + } + p.namedParams[paramName] = true + p.w.WriteString("@") + p.w.WriteString(paramName) + if !ok { + return nil + } + return parseNormal +} + func parseQuote(p *parser) stateFunc { for { ch, ok := p.next() diff --git a/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go index a6e95051c9..9b5bc6893f 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go +++ b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go @@ -113,7 +113,7 @@ type SSPIAuth struct { ctxt SecHandle } -func getAuth(user, password, service, workstation string) (Auth, bool) { +func getAuth(user, password, service, workstation string) (auth, bool) { if user == "" { return &SSPIAuth{Service: service}, true } diff --git a/vendor/github.com/denisenkom/go-mssqldb/tds.go b/vendor/github.com/denisenkom/go-mssqldb/tds.go index fd42dba34a..54ac6dbad5 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/tds.go +++ b/vendor/github.com/denisenkom/go-mssqldb/tds.go @@ -1,6 +1,7 @@ package mssql import ( + "context" "crypto/tls" "crypto/x509" "encoding/binary" @@ -9,11 +10,13 @@ import ( "io" "io/ioutil" "net" + "net/url" "os" "sort" "strconv" "strings" "time" + "unicode" "unicode/utf16" "unicode/utf8" ) @@ -47,8 +50,11 @@ func parseInstances(msg []byte) map[string]map[string]string { return results } -func getInstances(address string) (map[string]map[string]string, error) { - conn, err := net.DialTimeout("udp", address+":1434", 5*time.Second) +func getInstances(ctx context.Context, address string) (map[string]map[string]string, error) { + dialer := &net.Dialer{ + Timeout: 5 * time.Second, + } + conn, err := dialer.DialContext(ctx, "udp", address+":1434") if err != nil { return nil, err } @@ -79,11 +85,16 @@ const ( ) // packet types +// https://msdn.microsoft.com/en-us/library/dd304214.aspx const ( - packSQLBatch = 1 - packRPCRequest = 3 - packReply = 4 - packCancel = 6 + packSQLBatch packetType = 1 + packRPCRequest = 3 + packReply = 4 + + // 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx + // 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx + packAttention = 6 + packBulkLoadBCP = 7 packTransMgrReq = 14 packNormal = 15 @@ -119,7 +130,7 @@ type tdsSession struct { columns []columnStruct tranid uint64 logFlags uint64 - log *Logger + log optionalLogger routedServer string routedPort uint16 } @@ -131,6 +142,7 @@ const ( logSQL = 8 logParams = 16 logTransaction = 32 + logDebug = 64 ) type columnStruct struct { @@ -490,6 +502,11 @@ func readBVarChar(r io.Reader) (res string, err error) { if err != nil { return "", err } + + // A zero length could be returned, return an empty string + if numchars == 0 { + return "", nil + } return readUcs2(r, int(numchars)) } @@ -588,7 +605,7 @@ func (hdr transDescrHdr) pack() (res []byte) { } func writeAllHeaders(w io.Writer, headers []headerStruct) (err error) { - // calculatint total length + // Calculating total length. var totallen uint32 = 4 for _, hdr := range headers { totallen += 4 + 2 + uint32(len(hdr.data)) @@ -616,9 +633,7 @@ func writeAllHeaders(w io.Writer, headers []headerStruct) (err error) { return nil } -func sendSqlBatch72(buf *tdsBuffer, - sqltext string, - headers []headerStruct) (err error) { +func sendSqlBatch72(buf *tdsBuffer, sqltext string, headers []headerStruct) (err error) { buf.BeginPacket(packSQLBatch) if err = writeAllHeaders(buf, headers); err != nil { @@ -632,6 +647,13 @@ func sendSqlBatch72(buf *tdsBuffer, return buf.FinishPacket() } +// 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx +// 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx +func sendAttention(buf *tdsBuffer) error { + buf.BeginPacket(packAttention) + return buf.FinishPacket() +} + type connectParams struct { logFlags uint64 port uint64 @@ -654,6 +676,7 @@ type connectParams struct { typeFlags uint8 failOverPartner string failOverPort uint64 + packetSize uint16 } func splitConnectionString(dsn string) (res map[string]string) { @@ -677,9 +700,241 @@ func splitConnectionString(dsn string) (res map[string]string) { return res } +// Splits a URL in the ODBC format +func splitConnectionStringOdbc(dsn string) (map[string]string, error) { + res := map[string]string{} + + type parserState int + const ( + // Before the start of a key + parserStateBeforeKey parserState = iota + + // Inside a key + parserStateKey + + // Beginning of a value. May be bare or braced + parserStateBeginValue + + // Inside a bare value + parserStateBareValue + + // Inside a braced value + parserStateBracedValue + + // A closing brace inside a braced value. + // May be the end of the value or an escaped closing brace, depending on the next character + parserStateBracedValueClosingBrace + + // After a value. Next character should be a semicolon or whitespace. + parserStateEndValue + ) + + var state = parserStateBeforeKey + + var key string + var value string + + for i, c := range dsn { + switch state { + case parserStateBeforeKey: + switch { + case c == '=': + return res, fmt.Errorf("Unexpected character = at index %d. Expected start of key or semi-colon or whitespace.", i) + case !unicode.IsSpace(c) && c != ';': + state = parserStateKey + key += string(c) + } + + case parserStateKey: + switch c { + case '=': + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + state = parserStateBeginValue + + case ';': + // Key without value + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + res[key] = value + key = "" + value = "" + state = parserStateBeforeKey + + default: + key += string(c) + } + + case parserStateBeginValue: + switch { + case c == '{': + state = parserStateBracedValue + case c == ';': + // Empty value + res[key] = value + key = "" + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + state = parserStateBareValue + value += string(c) + } + + case parserStateBareValue: + if c == ';' { + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + key = "" + value = "" + state = parserStateBeforeKey + } else { + value += string(c) + } + + case parserStateBracedValue: + if c == '}' { + state = parserStateBracedValueClosingBrace + } else { + value += string(c) + } + + case parserStateBracedValueClosingBrace: + if c == '}' { + // Escaped closing brace + value += string(c) + state = parserStateBracedValue + continue + } + + // End of braced value + res[key] = value + key = "" + value = "" + + // This character is the first character past the end, + // so it needs to be parsed like the parserStateEndValue state. + state = parserStateEndValue + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + + case parserStateEndValue: + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + } + } + + switch state { + case parserStateBeforeKey: // Okay + case parserStateKey: // Unfinished key. Treat as key without value. + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", len(dsn)) + } + res[key] = value + case parserStateBeginValue: // Empty value + res[key] = value + case parserStateBareValue: + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + case parserStateBracedValue: + return res, fmt.Errorf("Unexpected end of braced value at index %d.", len(dsn)) + case parserStateBracedValueClosingBrace: // End of braced value + res[key] = value + case parserStateEndValue: // Okay + } + + return res, nil +} + +// Normalizes the given string as an ODBC-format key +func normalizeOdbcKey(s string) string { + return strings.ToLower(strings.TrimRightFunc(s, unicode.IsSpace)) +} + +// Splits a URL of the form sqlserver://username:password@host/instance?param1=value¶m2=value +func splitConnectionStringURL(dsn string) (map[string]string, error) { + res := map[string]string{} + + u, err := url.Parse(dsn) + if err != nil { + return res, err + } + + if u.Scheme != "sqlserver" { + return res, fmt.Errorf("scheme %s is not recognized", u.Scheme) + } + + if u.User != nil { + res["user id"] = u.User.Username() + p, exists := u.User.Password() + if exists { + res["password"] = p + } + } + + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + host = u.Host + } + + if len(u.Path) > 0 { + res["server"] = host + "\\" + u.Path[1:] + } else { + res["server"] = host + } + + if len(port) > 0 { + res["port"] = port + } + + query := u.Query() + for k, v := range query { + if len(v) > 1 { + return res, fmt.Errorf("key %s provided more than once", k) + } + res[strings.ToLower(k)] = v[0] + } + + return res, nil +} + func parseConnectParams(dsn string) (connectParams, error) { - params := splitConnectionString(dsn) var p connectParams + + var params map[string]string + if strings.HasPrefix(dsn, "odbc:") { + parameters, err := splitConnectionStringOdbc(dsn[len("odbc:"):]) + if err != nil { + return p, err + } + params = parameters + } else if strings.HasPrefix(dsn, "sqlserver://") { + parameters, err := splitConnectionStringURL(dsn) + if err != nil { + return p, err + } + params = parameters + } else { + params = splitConnectionString(dsn) + } + strlog, ok := params["log"] if ok { var err error @@ -712,7 +967,32 @@ func parseConnectParams(dsn string) (connectParams, error) { } } - p.dial_timeout = 5 * time.Second + // https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option + // Default packet size remains at 4096 bytes + p.packetSize = 4096 + strpsize, ok := params["packet size"] + if ok { + var err error + psize, err := strconv.ParseUint(strpsize, 0, 16) + if err != nil { + f := "Invalid packet size '%v': %v" + return p, fmt.Errorf(f, strpsize, err.Error()) + } + + // Ensure packet size falls within the TDS protocol range of 512 to 32767 bytes + // NOTE: Encrypted connections have a maximum size of 16383 bytes. If you request + // a higher packet size, the server will respond with an ENVCHANGE request to + // alter the packet size to 16383 bytes. + p.packetSize = uint16(psize) + if p.packetSize < 512 { + p.packetSize = 512 + } else if p.packetSize > 32767 { + p.packetSize = 32767 + } + } + + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + p.dial_timeout = 15 * time.Second p.conn_timeout = 30 * time.Second strconntimeout, ok := params["connection timeout"] if ok { @@ -732,8 +1012,12 @@ func parseConnectParams(dsn string) (connectParams, error) { } p.dial_timeout = time.Duration(timeout) * time.Second } - keepAlive, ok := params["keepalive"] - if ok { + + // default keep alive should be 30 seconds according to spec: + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + p.keepAlive = 30 * time.Second + + if keepAlive, ok := params["keepalive"]; ok { timeout, err := strconv.ParseUint(keepAlive, 0, 16) if err != nil { f := "Invalid keepAlive value '%s': %s" @@ -743,7 +1027,7 @@ func parseConnectParams(dsn string) (connectParams, error) { } encrypt, ok := params["encrypt"] if ok { - if strings.ToUpper(encrypt) == "DISABLE" { + if strings.EqualFold(encrypt, "DISABLE") { p.disableEncryption = true } else { var err error @@ -819,7 +1103,7 @@ func parseConnectParams(dsn string) (connectParams, error) { return p, nil } -type Auth interface { +type auth interface { InitialBytes() ([]byte, error) NextBytes([]byte) ([]byte, error) Free() @@ -828,7 +1112,7 @@ type Auth interface { // SQL Server AlwaysOn Availability Group Listeners are bound by DNS to a // list of IP addresses. So if there is more than one, try them all and // use the first one that allows a connection. -func dialConnection(p connectParams) (conn net.Conn, err error) { +func dialConnection(ctx context.Context, p connectParams) (conn net.Conn, err error) { var ips []net.IP ips, err = net.LookupIP(p.host) if err != nil { @@ -839,9 +1123,9 @@ func dialConnection(p connectParams) (conn net.Conn, err error) { ips = []net.IP{ip} } if len(ips) == 1 { - d := createDialer(p) + d := createDialer(&p) addr := net.JoinHostPort(ips[0].String(), strconv.Itoa(int(p.port))) - conn, err = d.Dial("tcp", addr) + conn, err = d.Dial(ctx, addr) } else { //Try Dials in parallel to avoid waiting for timeouts. @@ -850,9 +1134,9 @@ func dialConnection(p connectParams) (conn net.Conn, err error) { portStr := strconv.Itoa(int(p.port)) for _, ip := range ips { go func(ip net.IP) { - d := createDialer(p) + d := createDialer(&p) addr := net.JoinHostPort(ip.String(), portStr) - conn, err := d.Dial("tcp", addr) + conn, err := d.Dial(ctx, addr) if err == nil { connChan <- conn } else { @@ -887,16 +1171,15 @@ func dialConnection(p connectParams) (conn net.Conn, err error) { f := "Unable to open tcp connection with host '%v:%v': %v" return nil, fmt.Errorf(f, p.host, p.port, err.Error()) } - return conn, err } -func connect(p connectParams) (res *tdsSession, err error) { +func connect(ctx context.Context, log optionalLogger, p connectParams) (res *tdsSession, err error) { res = nil // if instance is specified use instance resolution service if p.instance != "" { p.instance = strings.ToUpper(p.instance) - instances, err := getInstances(p.host) + instances, err := getInstances(ctx, p.host) if err != nil { f := "Unable to get instances from Sql Server Browser on host %v: %v" return nil, fmt.Errorf(f, p.host, err.Error()) @@ -914,16 +1197,17 @@ func connect(p connectParams) (res *tdsSession, err error) { } initiate_connection: - conn, err := dialConnection(p) + conn, err := dialConnection(ctx, p) if err != nil { return nil, err } toconn := NewTimeoutConn(conn, p.conn_timeout) - outbuf := newTdsBuffer(4096, toconn) + outbuf := newTdsBuffer(p.packetSize, toconn) sess := tdsSession{ buf: outbuf, + log: log, logFlags: p.logFlags, } @@ -969,8 +1253,7 @@ initiate_connection: if p.certificate != "" { pem, err := ioutil.ReadFile(p.certificate) if err != nil { - f := "Cannot read certificate '%s': %s" - return nil, fmt.Errorf(f, p.certificate, err.Error()) + return nil, fmt.Errorf("Cannot read certificate %q: %v", p.certificate, err) } certs := x509.NewCertPool() certs.AppendCertsFromPEM(pem) @@ -980,15 +1263,20 @@ initiate_connection: config.InsecureSkipVerify = true } config.ServerName = p.hostInCertificate + // fix for https://github.com/denisenkom/go-mssqldb/issues/166 + // Go implementation of TLS payload size heuristic algorithm splits single TDS package to multiple TCP segments, + // while SQL Server seems to expect one TCP segment per encrypted TDS package. + // Setting DynamicRecordSizingDisabled to true disables that algorithm and uses 16384 bytes per TLS package + config.DynamicRecordSizingDisabled = true outbuf.transport = conn toconn.buf = outbuf tlsConn := tls.Client(toconn, &config) err = tlsConn.Handshake() + toconn.buf = nil outbuf.transport = tlsConn if err != nil { - f := "TLS Handshake failed: %s" - return nil, fmt.Errorf(f, err.Error()) + return nil, fmt.Errorf("TLS Handshake failed: %v", err) } if encrypt == encryptOff { outbuf.afterFirst = func() { @@ -999,7 +1287,7 @@ initiate_connection: login := login{ TDSVersion: verTDS74, - PacketSize: uint32(len(outbuf.buf)), + PacketSize: uint32(outbuf.PackageSize()), Database: p.database, OptionFlags2: fODBC, // to get unlimited TEXTSIZE HostName: p.workstation, @@ -1028,7 +1316,7 @@ initiate_connection: var sspi_msg []byte continue_login: tokchan := make(chan tokenStruct, 5) - go processResponse(&sess, tokchan) + go processResponse(context.Background(), &sess, tokchan, nil) success := false for tok := range tokchan { switch token := tok.(type) { @@ -1042,6 +1330,10 @@ continue_login: sess.loginAck = token case error: return nil, fmt.Errorf("Login error: %s", token.Error()) + case doneStruct: + if token.isError() { + return nil, fmt.Errorf("Login error: %s", token.getError()) + } } } if sspi_msg != nil { diff --git a/vendor/github.com/denisenkom/go-mssqldb/token.go b/vendor/github.com/denisenkom/go-mssqldb/token.go index f20bd14cc9..5f2167eb86 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/token.go +++ b/vendor/github.com/denisenkom/go-mssqldb/token.go @@ -1,30 +1,40 @@ package mssql import ( + "context" "encoding/binary" + "errors" + "fmt" "io" + "net" "strconv" "strings" ) +//go:generate stringer -type token + +type token byte + // token ids const ( - tokenReturnStatus = 121 // 0x79 - tokenColMetadata = 129 // 0x81 - tokenOrder = 169 // 0xA9 - tokenError = 170 // 0xAA - tokenInfo = 171 // 0xAB - tokenLoginAck = 173 // 0xad - tokenRow = 209 // 0xd1 - tokenNbcRow = 210 // 0xd2 - tokenEnvChange = 227 // 0xE3 - tokenSSPI = 237 // 0xED - tokenDone = 253 // 0xFD - tokenDoneProc = 254 - tokenDoneInProc = 255 + tokenReturnStatus token = 121 // 0x79 + tokenColMetadata token = 129 // 0x81 + tokenOrder token = 169 // 0xA9 + tokenError token = 170 // 0xAA + tokenInfo token = 171 // 0xAB + tokenReturnValue token = 0xAC + tokenLoginAck token = 173 // 0xad + tokenRow token = 209 // 0xd1 + tokenNbcRow token = 210 // 0xd2 + tokenEnvChange token = 227 // 0xE3 + tokenSSPI token = 237 // 0xED + tokenDone token = 253 // 0xFD + tokenDoneProc token = 254 + tokenDoneInProc token = 255 ) // done flags +// https://msdn.microsoft.com/en-us/library/dd340421.aspx const ( doneFinal = 0 doneMore = 1 @@ -59,6 +69,13 @@ const ( envRouting = 20 ) +// COLMETADATA flags +// https://msdn.microsoft.com/en-us/library/dd357363.aspx +const ( + colFlagNullable = 1 + // TODO implement more flags +) + // interface for all tokens type tokenStruct interface{} @@ -70,6 +87,19 @@ type doneStruct struct { Status uint16 CurCmd uint16 RowCount uint64 + errors []Error +} + +func (d doneStruct) isError() bool { + return d.Status&doneError != 0 || len(d.errors) > 0 +} + +func (d doneStruct) getError() Error { + if len(d.errors) > 0 { + return d.errors[len(d.errors)-1] + } else { + return Error{Message: "Request failed but didn't provide reason"} + } } type doneInProcStruct doneStruct @@ -120,27 +150,23 @@ func processEnvChg(sess *tdsSession) { badStreamPanic(err) } case envTypLanguage: - //currently ignored - // old value - _, err = readBVarChar(r) - if err != nil { + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value - _, err = readBVarChar(r) - if err != nil { + // old value + if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envTypCharset: - //currently ignored - // old value - _, err = readBVarChar(r) - if err != nil { + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value - _, err = readBVarChar(r) - if err != nil { + // old value + if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envTypPacketSize: @@ -156,38 +182,55 @@ func processEnvChg(sess *tdsSession) { if err != nil { badStreamPanicf("Invalid Packet size value returned from server (%s): %s", packetsize, err.Error()) } - if len(sess.buf.buf) != packetsizei { - newbuf := make([]byte, packetsizei) - copy(newbuf, sess.buf.buf) - sess.buf.buf = newbuf - } + sess.buf.ResizeBuffer(packetsizei) case envSortId: // currently ignored - // old value, should be 0 + // new value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envSortFlags: // currently ignored - // old value, should be 0 + // new value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envSqlCollation: // currently ignored - // old value - if _, err = readBVarChar(r); err != nil { + var collationSize uint8 + err = binary.Read(r, binary.LittleEndian, &collationSize) + if err != nil { badStreamPanic(err) } - // new value + + // SQL Collation data should contain 5 bytes in length + if collationSize != 5 { + badStreamPanicf("Invalid SQL Collation size value returned from server: %s", collationSize) + } + + // 4 bytes, contains: LCID ColFlags Version + var info uint32 + err = binary.Read(r, binary.LittleEndian, &info) + if err != nil { + badStreamPanic(err) + } + + // 1 byte, contains: sortID + var sortID uint8 + err = binary.Read(r, binary.LittleEndian, &sortID) + if err != nil { + badStreamPanic(err) + } + + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } @@ -226,21 +269,21 @@ func processEnvChg(sess *tdsSession) { sess.tranid = 0 case envEnlistDTC: // currently ignored - // old value + // new value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value, should be 0 + // old value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envDefectTran: // currently ignored - // old value, should be 0 + // new value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } @@ -358,6 +401,7 @@ func parseOrder(r *tdsBuffer) (res orderStruct) { return res } +// https://msdn.microsoft.com/en-us/library/dd340421.aspx func parseDone(r *tdsBuffer) (res doneStruct) { res.Status = r.uint16() res.CurCmd = r.uint16() @@ -365,6 +409,7 @@ func parseDone(r *tdsBuffer) (res doneStruct) { return res } +// https://msdn.microsoft.com/en-us/library/dd340553.aspx func parseDoneInProc(r *tdsBuffer) (res doneInProcStruct) { res.Status = r.uint16() res.CurCmd = r.uint16() @@ -473,26 +518,57 @@ func parseInfo(r *tdsBuffer) (res Error) { return } -func processResponse(sess *tdsSession, ch chan tokenStruct) { +// https://msdn.microsoft.com/en-us/library/dd303881.aspx +func parseReturnValue(r *tdsBuffer) (nv namedValue) { + /* + ParamOrdinal + ParamName + Status + UserType + Flags + TypeInfo + CryptoMetadata + Value + */ + r.uint16() + nv.Name = r.BVarChar() + r.byte() + r.uint32() // UserType (uint16 prior to 7.2) + r.uint16() + ti := readTypeInfo(r) + nv.Value = ti.Reader(&ti, r) + return +} + +func processSingleResponse(sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { defer func() { if err := recover(); err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: Intercepted panic %v", err) + } ch <- err } close(ch) }() + packet_type, err := sess.buf.BeginRead() if err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: BeginRead failed %v", err) + } ch <- err return } if packet_type != packReply { - badStreamPanicf("invalid response packet type, expected REPLY, actual: %d", packet_type) + badStreamPanic(fmt.Errorf("unexpected packet type in reply: got %v, expected %v", packet_type, packReply)) } var columns []columnStruct - var lastError Error - var failed bool + errs := make([]Error, 0, 5) for { - token := sess.buf.byte() + token := token(sess.buf.byte()) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got token %v", token) + } switch token { case tokenSSPI: ch <- parseSSPIMsg(sess.buf) @@ -514,18 +590,17 @@ func processResponse(sess *tdsSession, ch chan tokenStruct) { ch <- done case tokenDone, tokenDoneProc: done := parseDone(sess.buf) - if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { - sess.log.Printf("(%d row(s) affected)\n", done.RowCount) - } - if done.Status&doneError != 0 || failed { - ch <- lastError - return + done.errors = errs + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got DONE or DONEPROC status=%d", done.Status) } if done.Status&doneSrvError != 0 { - lastError.Message = "Server Error" - ch <- lastError + ch <- errors.New("SQL Server had internal error") return } + if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { + sess.log.Printf("(%d row(s) affected)\n", done.RowCount) + } ch <- done if done.Status&doneMore == 0 { return @@ -544,18 +619,210 @@ func processResponse(sess *tdsSession, ch chan tokenStruct) { case tokenEnvChange: processEnvChg(sess) case tokenError: - lastError = parseError72(sess.buf) - failed = true + err := parseError72(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got ERROR %d %s", err.Number, err.Message) + } + errs = append(errs, err) if sess.logFlags&logErrors != 0 { - sess.log.Println(lastError.Message) + sess.log.Println(err.Message) } case tokenInfo: info := parseInfo(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got INFO %d %s", info.Number, info.Message) + } if sess.logFlags&logMessages != 0 { sess.log.Println(info.Message) } + case tokenReturnValue: + nv := parseReturnValue(sess.buf) + if len(nv.Name) > 0 { + name := nv.Name[1:] // Remove the leading "@". + if ov, has := outs[name]; has { + err = scanIntoOut(nv.Value, ov) + if err != nil { + fmt.Println("scan error", err) + ch <- err + } + } + } default: - badStreamPanicf("Unknown token type: %d", token) + badStreamPanic(fmt.Errorf("unknown token type returned: %v", token)) + } + } +} + +func scanIntoOut(fromServer, scanInto interface{}) error { + switch fs := fromServer.(type) { + case int64: + switch si := scanInto.(type) { + case *int64: + *si = fs + default: + return fmt.Errorf("unsupported scan into type %[1]T for server type %[2]T", scanInto, fromServer) + } + return nil + case string: + switch si := scanInto.(type) { + case *string: + *si = fs + default: + return fmt.Errorf("unsupported scan into type %[1]T for server type %[2]T", scanInto, fromServer) + } + return nil + } + return fmt.Errorf("unsupported type from server %[1]T=%[1]v", fromServer) +} + +type parseRespIter byte + +const ( + parseRespIterContinue parseRespIter = iota // Continue parsing current token. + parseRespIterNext // Fetch the next token. + parseRespIterDone // Done with parsing the response. +) + +type parseRespState byte + +const ( + parseRespStateNormal parseRespState = iota // Normal response state. + parseRespStateCancel // Query is canceled, wait for server to confirm. + parseRespStateClosing // Waiting for tokens to come through. +) + +type parseResp struct { + sess *tdsSession + ctxDone <-chan struct{} + state parseRespState + cancelError error +} + +func (ts *parseResp) sendAttention(ch chan tokenStruct) parseRespIter { + if err := sendAttention(ts.sess.buf); err != nil { + ts.dlogf("failed to send attention signal %v", err) + ch <- err + return parseRespIterDone + } + ts.state = parseRespStateCancel + return parseRespIterContinue +} + +func (ts *parseResp) dlog(msg string) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Println(msg) + } +} +func (ts *parseResp) dlogf(f string, v ...interface{}) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Printf(f, v...) + } +} + +func (ts *parseResp) iter(ctx context.Context, ch chan tokenStruct, tokChan chan tokenStruct) parseRespIter { + switch ts.state { + default: + panic("unknown state") + case parseRespStateNormal: + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished") + return parseRespIterDone + } + if err, ok := tok.(net.Error); ok && err.Timeout() { + ts.cancelError = err + ts.dlog("got timeout error, sending attention signal to server") + return ts.sendAttention(ch) + } + // Pass the token along. + ch <- tok + return parseRespIterContinue + + case <-ts.ctxDone: + ts.ctxDone = nil + ts.dlog("got cancel message, sending attention signal to server") + return ts.sendAttention(ch) + } + case parseRespStateCancel: // Read all responses until a DONE or error is received.Auth + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished but waiting for attention ack") + return parseRespIterNext + } + switch tok := tok.(type) { + default: + // Ignore all other tokens while waiting. + // The TDS spec says other tokens may arrive after an attention + // signal is sent. Ignore these tokens and continue looking for + // a DONE with attention confirm mark. + case doneStruct: + if tok.Status&doneAttn != 0 { + ts.dlog("got cancellation confirmation from server") + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } else { + ch <- ctx.Err() + } + return parseRespIterDone + } + + // If an error happens during cancel, pass it along and just stop. + // We are uncertain to receive more tokens. + case error: + ch <- tok + ts.state = parseRespStateClosing + } + return parseRespIterContinue + case <-ts.ctxDone: + ts.ctxDone = nil + ts.state = parseRespStateClosing + return parseRespIterContinue + } + case parseRespStateClosing: // Wait for current token chan to close. + if _, ok := <-tokChan; !ok { + ts.dlog("response finished") + return parseRespIterDone + } + return parseRespIterContinue + } +} + +func processResponse(ctx context.Context, sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { + ts := &parseResp{ + sess: sess, + ctxDone: ctx.Done(), + } + defer func() { + // Ensure any remaining error is piped through + // or the query may look like it executed when it actually failed. + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } + close(ch) + }() + + // Loop over multiple responses. + for { + ts.dlog("initiating response reading") + + tokChan := make(chan tokenStruct) + go processSingleResponse(sess, tokChan, outs) + + // Loop over multiple tokens in response. + tokensLoop: + for { + switch ts.iter(ctx, ch, tokChan) { + case parseRespIterContinue: + // Nothing, continue to next token. + case parseRespIterNext: + break tokensLoop + case parseRespIterDone: + return + } } } } diff --git a/vendor/github.com/denisenkom/go-mssqldb/token_string.go b/vendor/github.com/denisenkom/go-mssqldb/token_string.go new file mode 100644 index 0000000000..c075b23be0 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/token_string.go @@ -0,0 +1,53 @@ +// Code generated by "stringer -type token"; DO NOT EDIT + +package mssql + +import "fmt" + +const ( + _token_name_0 = "tokenReturnStatus" + _token_name_1 = "tokenColMetadata" + _token_name_2 = "tokenOrdertokenErrortokenInfo" + _token_name_3 = "tokenLoginAck" + _token_name_4 = "tokenRowtokenNbcRow" + _token_name_5 = "tokenEnvChange" + _token_name_6 = "tokenSSPI" + _token_name_7 = "tokenDonetokenDoneProctokenDoneInProc" +) + +var ( + _token_index_0 = [...]uint8{0, 17} + _token_index_1 = [...]uint8{0, 16} + _token_index_2 = [...]uint8{0, 10, 20, 29} + _token_index_3 = [...]uint8{0, 13} + _token_index_4 = [...]uint8{0, 8, 19} + _token_index_5 = [...]uint8{0, 14} + _token_index_6 = [...]uint8{0, 9} + _token_index_7 = [...]uint8{0, 9, 22, 37} +) + +func (i token) String() string { + switch { + case i == 121: + return _token_name_0 + case i == 129: + return _token_name_1 + case 169 <= i && i <= 171: + i -= 169 + return _token_name_2[_token_index_2[i]:_token_index_2[i+1]] + case i == 173: + return _token_name_3 + case 209 <= i && i <= 210: + i -= 209 + return _token_name_4[_token_index_4[i]:_token_index_4[i+1]] + case i == 227: + return _token_name_5 + case i == 237: + return _token_name_6 + case 253 <= i && i <= 255: + i -= 253 + return _token_name_7[_token_index_7[i]:_token_index_7[i+1]] + default: + return fmt.Sprintf("token(%d)", i) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tran.go b/vendor/github.com/denisenkom/go-mssqldb/tran.go index ae38107661..75e7a2ae65 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/tran.go +++ b/vendor/github.com/denisenkom/go-mssqldb/tran.go @@ -1,6 +1,7 @@ +package mssql + // Transaction Manager requests // http://msdn.microsoft.com/en-us/library/dd339887.aspx -package mssql import ( "encoding/binary" @@ -16,7 +17,18 @@ const ( tmSaveXact = 9 ) -func sendBeginXact(buf *tdsBuffer, headers []headerStruct, isolation uint8, +type isoLevel uint8 + +const ( + isolationUseCurrent isoLevel = 0 + isolationReadUncommited = 1 + isolationReadCommited = 2 + isolationRepeatableRead = 3 + isolationSerializable = 4 + isolationSnapshot = 5 +) + +func sendBeginXact(buf *tdsBuffer, headers []headerStruct, isolation isoLevel, name string) (err error) { buf.BeginPacket(packTransMgrReq) writeAllHeaders(buf, headers) diff --git a/vendor/github.com/denisenkom/go-mssqldb/types.go b/vendor/github.com/denisenkom/go-mssqldb/types.go index c38862e9eb..9ae5c5f761 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/types.go +++ b/vendor/github.com/denisenkom/go-mssqldb/types.go @@ -6,8 +6,11 @@ import ( "fmt" "io" "math" + "reflect" "strconv" "time" + + "github.com/denisenkom/go-mssqldb/internal/cp" ) // fixed-length data types @@ -66,6 +69,9 @@ const ( typeNText = 0x63 typeVariant = 0x62 ) +const PLP_NULL = 0xFFFFFFFFFFFFFFFF +const UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFE +const PLP_TERMINATOR = 0x00000000 // TYPE_INFO rule // http://msdn.microsoft.com/en-us/library/dd358284.aspx @@ -75,11 +81,32 @@ type typeInfo struct { Scale uint8 Prec uint8 Buffer []byte - Collation collation + Collation cp.Collation + UdtInfo udtInfo + XmlInfo xmlInfo Reader func(ti *typeInfo, r *tdsBuffer) (res interface{}) Writer func(w io.Writer, ti typeInfo, buf []byte) (err error) } +// Common Language Runtime (CLR) Instances +// http://msdn.microsoft.com/en-us/library/dd357962.aspx +type udtInfo struct { + //MaxByteSize uint32 + DBName string + SchemaName string + TypeName string + AssemblyQualifiedName string +} + +// XML Values +// http://msdn.microsoft.com/en-us/library/dd304764.aspx +type xmlInfo struct { + SchemaPresent uint8 + DBName string + OwningSchema string + XmlSchemaCollection string +} + func readTypeInfo(r *tdsBuffer) (res typeInfo) { res.TypeId = r.byte() switch res.TypeId { @@ -114,7 +141,8 @@ func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { switch ti.TypeId { case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: - // those are fixed length types + // those are fixed length + ti.Writer = writeFixedType default: // all others are VARLENTYPE err = writeVarLen(w, ti) if err != nil { @@ -124,19 +152,25 @@ func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { return } +func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) { + _, err = w.Write(buf) + return +} + func writeVarLen(w io.Writer, ti *typeInfo) (err error) { switch ti.TypeId { case typeDateN: - + ti.Writer = writeByteLenType case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: if err = binary.Write(w, binary.LittleEndian, ti.Scale); err != nil { return } ti.Writer = writeByteLenType - case typeGuid, typeIntN, typeDecimal, typeNumeric, + case typeIntN, typeDecimal, typeNumeric, typeBitN, typeDecimalN, typeNumericN, typeFltN, typeMoneyN, typeDateTimeN, typeChar, typeVarChar, typeBinary, typeVarBinary: + // byle len types if ti.Size > 0xff { panic("Invalid size for BYLELEN_TYPE") @@ -156,6 +190,14 @@ func writeVarLen(w io.Writer, ti *typeInfo) (err error) { } } ti.Writer = writeByteLenType + case typeGuid: + if !(ti.Size == 0x10 || ti.Size == 0x00) { + panic("Invalid size for BYLELEN_TYPE") + } + if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { + return + } + ti.Writer = writeByteLenType case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, typeNVarChar, typeNChar, typeXml, typeUdt: // short len types @@ -176,14 +218,19 @@ func writeVarLen(w io.Writer, ti *typeInfo) (err error) { return } case typeXml: - var schemapresent uint8 = 0 - if err = binary.Write(w, binary.LittleEndian, schemapresent); err != nil { + if err = binary.Write(w, binary.LittleEndian, ti.XmlInfo.SchemaPresent); err != nil { return } } case typeText, typeImage, typeNText, typeVariant: // LONGLEN_TYPE - panic("LONGLEN_TYPE not implemented") + if err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)); err != nil { + return + } + if err = writeCollation(w, ti.Collation); err != nil { + return + } + ti.Writer = writeLongLenType default: panic("Invalid type") } @@ -207,7 +254,7 @@ func decodeDateTime(buf []byte) time.Time { 0, 0, secs, ns, time.UTC) } -func readFixedType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readFixedType(ti *typeInfo, r *tdsBuffer) interface{} { r.ReadFull(ti.Buffer) buf := ti.Buffer switch ti.TypeId { @@ -241,12 +288,7 @@ func readFixedType(ti *typeInfo, r *tdsBuffer) (res interface{}) { panic("shoulnd't get here") } -func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) { - _, err = w.Write(buf) - return -} - -func readByteLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readByteLenType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.byte() if size == 0 { return nil @@ -305,6 +347,10 @@ func readByteLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { default: badStreamPanicf("Invalid size for MONEYNTYPE") } + case typeDateTim4: + return decodeDateTim4(buf) + case typeDateTime: + return decodeDateTime(buf) case typeDateTimeN: switch len(buf) { case 4: @@ -341,7 +387,7 @@ func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { return } -func readShortLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readShortLenType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.uint16() if size == 0xffff { return nil @@ -384,7 +430,7 @@ func writeShortLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { return } -func readLongLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readLongLenType(ti *typeInfo, r *tdsBuffer) interface{} { // information about this format can be found here: // http://msdn.microsoft.com/en-us/library/dd304783.aspx // and here: @@ -415,10 +461,51 @@ func readLongLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { } panic("shoulnd't get here") } +func writeLongLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + //textptr + err = binary.Write(w, binary.LittleEndian, byte(0x10)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + //timestamp? + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + + err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readCollation(r *tdsBuffer) (res cp.Collation) { + res.LcidAndFlags = r.uint32() + res.SortId = r.byte() + return +} + +func writeCollation(w io.Writer, col cp.Collation) (err error) { + if err = binary.Write(w, binary.LittleEndian, col.LcidAndFlags); err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, col.SortId) + return +} // reads variant value // http://msdn.microsoft.com/en-us/library/dd303302.aspx -func readVariantType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readVariantType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.int32() if size == 0 { return nil @@ -510,14 +597,14 @@ func readVariantType(ti *typeInfo, r *tdsBuffer) (res interface{}) { // partially length prefixed stream // http://msdn.microsoft.com/en-us/library/dd340469.aspx -func readPLPType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readPLPType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.uint64() var buf *bytes.Buffer switch size { - case 0xffffffffffffffff: + case PLP_NULL: // null return nil - case 0xfffffffffffffffe: + case UNKNOWN_PLP_LEN: // size unknown buf = bytes.NewBuffer(make([]byte, 0, 1000)) default: @@ -548,15 +635,16 @@ func readPLPType(ti *typeInfo, r *tdsBuffer) (res interface{}) { } func writePLPType(w io.Writer, ti typeInfo, buf []byte) (err error) { - if err = binary.Write(w, binary.LittleEndian, uint64(len(buf))); err != nil { + if err = binary.Write(w, binary.LittleEndian, uint64(UNKNOWN_PLP_LEN)); err != nil { return } for { chunksize := uint32(len(buf)) - if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil { + if chunksize == 0 { + err = binary.Write(w, binary.LittleEndian, uint32(PLP_TERMINATOR)) return } - if chunksize == 0 { + if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil { return } if _, err = w.Write(buf[:chunksize]); err != nil { @@ -606,19 +694,27 @@ func readVarLen(ti *typeInfo, r *tdsBuffer) { } ti.Reader = readByteLenType case typeXml: - schemapresent := r.byte() - if schemapresent != 0 { - // just ignore this for now + ti.XmlInfo.SchemaPresent = r.byte() + if ti.XmlInfo.SchemaPresent != 0 { // dbname - r.BVarChar() + ti.XmlInfo.DBName = r.BVarChar() // owning schema - r.BVarChar() + ti.XmlInfo.OwningSchema = r.BVarChar() // xml schema collection - r.UsVarChar() + ti.XmlInfo.XmlSchemaCollection = r.UsVarChar() } ti.Reader = readPLPType + case typeUdt: + ti.Size = int(r.uint16()) + ti.UdtInfo.DBName = r.BVarChar() + ti.UdtInfo.SchemaName = r.BVarChar() + ti.UdtInfo.TypeName = r.BVarChar() + ti.UdtInfo.AssemblyQualifiedName = r.UsVarChar() + + ti.Buffer = make([]byte, ti.Size) + ti.Reader = readPLPType case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, - typeNVarChar, typeNChar, typeUdt: + typeNVarChar, typeNChar: // short len types ti.Size = int(r.uint16()) switch ti.TypeId { @@ -701,7 +797,8 @@ func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte { // http://msdn.microsoft.com/en-us/library/ee780895.aspx func decodeDateInt(buf []byte) (days int) { - return int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256 + days = int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256 + return } func decodeDate(buf []byte) time.Time { @@ -767,8 +864,8 @@ func dateTime2(t time.Time) (days int32, ns int64) { return } -func decodeChar(col collation, buf []byte) string { - return charset2utf8(col, buf) +func decodeChar(col cp.Collation, buf []byte) string { + return cp.CharsetToUTF8(col, buf) } func decodeUcs2(buf []byte) string { @@ -787,12 +884,127 @@ func decodeXml(ti typeInfo, buf []byte) string { return decodeUcs2(buf) } -func decodeUdt(ti typeInfo, buf []byte) int { - panic("Not implemented") +func decodeUdt(ti typeInfo, buf []byte) []byte { + return buf +} + +// makes go/sql type instance as described below +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func makeGoLangScanType(ti typeInfo) reflect.Type { + switch ti.TypeId { + case typeInt1: + return reflect.TypeOf(int64(0)) + case typeInt2: + return reflect.TypeOf(int64(0)) + case typeInt4: + return reflect.TypeOf(int64(0)) + case typeInt8: + return reflect.TypeOf(int64(0)) + case typeFlt4: + return reflect.TypeOf(float64(0)) + case typeIntN: + switch ti.Size { + case 1: + return reflect.TypeOf(int64(0)) + case 2: + return reflect.TypeOf(int64(0)) + case 4: + return reflect.TypeOf(int64(0)) + case 8: + return reflect.TypeOf(int64(0)) + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return reflect.TypeOf(float64(0)) + case typeFltN: + switch ti.Size { + case 4: + return reflect.TypeOf(float64(0)) + case 8: + return reflect.TypeOf(float64(0)) + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return reflect.TypeOf([]byte{}) + case typeVarChar: + return reflect.TypeOf("") + case typeNVarChar: + return reflect.TypeOf("") + case typeBit, typeBitN: + return reflect.TypeOf(true) + case typeDecimalN, typeNumericN: + return reflect.TypeOf([]byte{}) + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return reflect.TypeOf([]byte{}) + case 8: + return reflect.TypeOf([]byte{}) + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return reflect.TypeOf(time.Time{}) + case typeDateTime: + return reflect.TypeOf(time.Time{}) + case typeDateTimeN: + switch ti.Size { + case 4: + return reflect.TypeOf(time.Time{}) + case 8: + return reflect.TypeOf(time.Time{}) + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return reflect.TypeOf(time.Time{}) + case typeDateN: + return reflect.TypeOf(time.Time{}) + case typeTimeN: + return reflect.TypeOf(time.Time{}) + case typeDateTimeOffsetN: + return reflect.TypeOf(time.Time{}) + case typeBigVarChar: + return reflect.TypeOf("") + case typeBigChar: + return reflect.TypeOf("") + case typeNChar: + return reflect.TypeOf("") + case typeGuid: + return reflect.TypeOf([]byte{}) + case typeXml: + return reflect.TypeOf("") + case typeText: + return reflect.TypeOf("") + case typeNText: + return reflect.TypeOf("") + case typeImage: + return reflect.TypeOf([]byte{}) + case typeBigBinary: + return reflect.TypeOf([]byte{}) + case typeVariant: + return reflect.TypeOf(nil) + default: + panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId)) + } } func makeDecl(ti typeInfo) string { switch ti.TypeId { + case typeNull: + // maybe we should use something else here + // this is tested in TestNull + return "nvarchar(1)" + case typeInt1: + return "tinyint" + case typeInt2: + return "smallint" + case typeInt4: + return "int" case typeInt8: return "bigint" case typeFlt4: @@ -821,24 +1033,415 @@ func makeDecl(ti typeInfo) string { default: panic("invalid size of FLNNTYPE") } + case typeDecimal, typeDecimalN: + return fmt.Sprintf("decimal(%d, %d)", ti.Prec, ti.Scale) + case typeNumeric, typeNumericN: + return fmt.Sprintf("numeric(%d, %d)", ti.Prec, ti.Scale) + case typeMoney4: + return "smallmoney" + case typeMoney: + return "money" + case typeMoneyN: + switch ti.Size { + case 4: + return "smallmoney" + case 8: + return "money" + default: + panic("invalid size of MONEYNTYPE") + } case typeBigVarBin: if ti.Size > 8000 || ti.Size == 0 { - return fmt.Sprintf("varbinary(max)") + return "varbinary(max)" } else { return fmt.Sprintf("varbinary(%d)", ti.Size) } + case typeNChar: + return fmt.Sprintf("nchar(%d)", ti.Size/2) + case typeBigChar, typeChar: + return fmt.Sprintf("char(%d)", ti.Size) + case typeBigVarChar, typeVarChar: + if ti.Size > 4000 || ti.Size == 0 { + return fmt.Sprintf("varchar(max)") + } else { + return fmt.Sprintf("varchar(%d)", ti.Size) + } case typeNVarChar: if ti.Size > 8000 || ti.Size == 0 { - return fmt.Sprintf("nvarchar(max)") + return "nvarchar(max)" } else { return fmt.Sprintf("nvarchar(%d)", ti.Size/2) } case typeBit, typeBitN: return "bit" - case typeDateTimeN: + case typeDateN: + return "date" + case typeDateTim4: + return "smalldatetime" + case typeDateTime: return "datetime" + case typeDateTimeN: + switch ti.Size { + case 4: + return "smalldatetime" + case 8: + return "datetime" + default: + panic("invalid size of DATETIMNTYPE") + } + case typeDateTime2N: + return fmt.Sprintf("datetime2(%d)", ti.Scale) case typeDateTimeOffsetN: return fmt.Sprintf("datetimeoffset(%d)", ti.Scale) + case typeText: + return "text" + case typeNText: + return "ntext" + case typeUdt: + return ti.UdtInfo.TypeName + case typeGuid: + return "uniqueidentifier" + default: + panic(fmt.Sprintf("not implemented makeDecl for type %#x", ti.TypeId)) + } +} + +// makes go/sql type name as described below +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func makeGoLangTypeName(ti typeInfo) string { + switch ti.TypeId { + case typeInt1: + return "TINYINT" + case typeInt2: + return "SMALLINT" + case typeInt4: + return "INT" + case typeInt8: + return "BIGINT" + case typeFlt4: + return "REAL" + case typeIntN: + switch ti.Size { + case 1: + return "TINYINT" + case 2: + return "SMALLINT" + case 4: + return "INT" + case 8: + return "BIGINT" + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return "FLOAT" + case typeFltN: + switch ti.Size { + case 4: + return "REAL" + case 8: + return "FLOAT" + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return "VARBINARY" + case typeVarChar: + return "VARCHAR" + case typeNVarChar: + return "NVARCHAR" + case typeBit, typeBitN: + return "BIT" + case typeDecimalN, typeNumericN: + return "DECIMAL" + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return "SMALLMONEY" + case 8: + return "MONEY" + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return "SMALLDATETIME" + case typeDateTime: + return "DATETIME" + case typeDateTimeN: + switch ti.Size { + case 4: + return "SMALLDATETIME" + case 8: + return "DATETIME" + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return "DATETIME2" + case typeDateN: + return "DATE" + case typeTimeN: + return "TIME" + case typeDateTimeOffsetN: + return "DATETIMEOFFSET" + case typeBigVarChar: + return "VARCHAR" + case typeBigChar: + return "CHAR" + case typeNChar: + return "NCHAR" + case typeGuid: + return "UNIQUEIDENTIFIER" + case typeXml: + return "XML" + case typeText: + return "TEXT" + case typeNText: + return "NTEXT" + case typeImage: + return "IMAGE" + case typeVariant: + return "SQL_VARIANT" + case typeBigBinary: + return "BINARY" + default: + panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId)) + } +} + +// makes go/sql type length as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypeLength(ti typeInfo) (int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, false + case typeInt2: + return 0, false + case typeInt4: + return 0, false + case typeInt8: + return 0, false + case typeFlt4: + return 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, false + case 2: + return 0, false + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, false + case typeDecimalN, typeNumericN: + return 0, false + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, false + case typeDateN: + return 0, false + case typeTimeN: + return 0, false + case typeDateTimeOffsetN: + return 0, false + case typeBigVarBin: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeVarChar: + return int64(ti.Size), true + case typeBigVarChar: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeBigChar: + return int64(ti.Size), true + case typeNVarChar: + if ti.Size == 0xffff { + return 2147483645 / 2, true + } else { + return int64(ti.Size) / 2, true + } + case typeNChar: + return int64(ti.Size) / 2, true + case typeGuid: + return 0, false + case typeXml: + return 1073741822, true + case typeText: + return 2147483647, true + case typeNText: + return 1073741823, true + case typeImage: + return 2147483647, true + case typeVariant: + return 0, false + case typeBigBinary: + return 0, false + default: + panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId)) + } +} + +// makes go/sql type precision and scale as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, 0, false + case typeInt2: + return 0, 0, false + case typeInt4: + return 0, 0, false + case typeInt8: + return 0, 0, false + case typeFlt4: + return 0, 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, 0, false + case 2: + return 0, 0, false + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, 0, false + case typeDecimalN, typeNumericN: + return int64(ti.Prec), int64(ti.Scale), true + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, 0, false + case typeDateN: + return 0, 0, false + case typeTimeN: + return 0, 0, false + case typeDateTimeOffsetN: + return 0, 0, false + case typeBigVarBin: + return 0, 0, false + case typeVarChar: + return 0, 0, false + case typeBigVarChar: + return 0, 0, false + case typeBigChar: + return 0, 0, false + case typeNVarChar: + return 0, 0, false + case typeNChar: + return 0, 0, false + case typeGuid: + return 0, 0, false + case typeXml: + return 0, 0, false + case typeText: + return 0, 0, false + case typeNText: + return 0, 0, false + case typeImage: + return 0, 0, false + case typeVariant: + return 0, 0, false + case typeBigBinary: + return 0, 0, false default: panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId)) } diff --git a/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go new file mode 100644 index 0000000000..c8ef3149b1 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go @@ -0,0 +1,74 @@ +package mssql + +import ( + "database/sql/driver" + "encoding/hex" + "errors" + "fmt" +) + +type UniqueIdentifier [16]byte + +func (u *UniqueIdentifier) Scan(v interface{}) error { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + switch vt := v.(type) { + case []byte: + if len(vt) != 16 { + return errors.New("mssql: invalid UniqueIdentifier length") + } + + var raw UniqueIdentifier + + copy(raw[:], vt) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + *u = raw + + return nil + case string: + if len(vt) != 36 { + return errors.New("mssql: invalid UniqueIdentifier string length") + } + + b := []byte(vt) + for i, c := range b { + switch c { + case '-': + b = append(b[:i], b[i+1:]...) + } + } + + _, err := hex.Decode(u[:], []byte(b)) + return err + default: + return fmt.Errorf("mssql: cannot convert %T to UniqueIdentifier", v) + } +} + +func (u UniqueIdentifier) Value() (driver.Value, error) { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + raw := make([]byte, len(u)) + copy(raw, u[:]) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + + return raw, nil +} + +func (u UniqueIdentifier) String() string { + return fmt.Sprintf("%X-%X-%X-%X-%X", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index ef253f5194..fe21d938d3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -85,8 +85,9 @@ github.com/couchbase/vellum/utf8 github.com/couchbaselabs/go-couchbase # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 +# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 github.com/denisenkom/go-mssqldb +github.com/denisenkom/go-mssqldb/internal/cp # github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac github.com/dgrijalva/jwt-go # github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 From ff85dd3e12c05be98d9132de2e629523d096f712 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 30 Jun 2019 15:57:59 +0800 Subject: [PATCH 164/220] Add commit statuses reports on pull request view (#6845) * Add commit statuses reports on pull view * Add some translations * improve the UI * fix fmt * fix tests * add a new test git repo to fix tests * fix bug when headRepo or headBranch missing * fix tests * fix tests * fix consistency * fix tests * fix tests * change the test repo * fix tests * fix tests * fix migration * keep db size consistency * fix translation * change commit hash status table unique index * remove unused table * use char instead varchar * make hashCommitStatusContext private * split merge section with status check on pull view ui * fix tests; fix arc-green theme on pull ui --- .../0a/bcb056019adb8336cf9db3ad9d9cf80cd4b141 | Bin 0 -> 818 bytes .../75/d1afd00e111c8dbd9e3d96a27b431ac5ae6d74 | Bin 0 -> 44 bytes .../ed/447543e0c85d628b91f7f466f4921908f4c5ea | Bin 0 -> 54 bytes .../user13/repo11.git/refs/heads/branch2 | 1 + integrations/pull_merge_test.go | 2 +- models/{status.go => commit_status.go} | 106 ++++++------------ .../{status_test.go => commit_status_test.go} | 0 models/fixtures/issue.yml | 11 ++ models/fixtures/pull_request.yml | 14 +++ models/fixtures/repository.yml | 4 +- models/migrations/migrations.go | 2 + models/migrations/v87.go | 2 +- models/migrations/v88.go | 66 +++++++++++ modules/repofiles/commit_status.go | 39 +++++++ options/locale/locale_en-US.ini | 3 + public/css/index.css | 1 + public/css/theme-arc-green.css | 1 + public/less/_repository.less | 5 + public/less/themes/arc-green.less | 5 + routers/api/v1/repo/status.go | 13 +-- routers/repo/pull.go | 24 +++- templates/repo/issue/view_content/pull.tmpl | 3 +- templates/repo/pulls/status.tmpl | 21 ++++ 23 files changed, 237 insertions(+), 86 deletions(-) create mode 100644 integrations/gitea-repositories-meta/user13/repo11.git/objects/0a/bcb056019adb8336cf9db3ad9d9cf80cd4b141 create mode 100644 integrations/gitea-repositories-meta/user13/repo11.git/objects/75/d1afd00e111c8dbd9e3d96a27b431ac5ae6d74 create mode 100644 integrations/gitea-repositories-meta/user13/repo11.git/objects/ed/447543e0c85d628b91f7f466f4921908f4c5ea create mode 100644 integrations/gitea-repositories-meta/user13/repo11.git/refs/heads/branch2 rename models/{status.go => commit_status.go} (75%) rename models/{status_test.go => commit_status_test.go} (100%) create mode 100644 models/migrations/v88.go create mode 100644 modules/repofiles/commit_status.go create mode 100644 templates/repo/pulls/status.tmpl diff --git a/integrations/gitea-repositories-meta/user13/repo11.git/objects/0a/bcb056019adb8336cf9db3ad9d9cf80cd4b141 b/integrations/gitea-repositories-meta/user13/repo11.git/objects/0a/bcb056019adb8336cf9db3ad9d9cf80cd4b141 new file mode 100644 index 0000000000000000000000000000000000000000..63ba4ed8eecb9c72734fd6ab9bbe01180c82960b GIT binary patch literal 818 zcmV-21I_$+0iBb{4y#rWM6>2A?j9vvFkC>&i^4qG1~VAEV+Nban8En#pOYxNtkR2K z9H~pCE>$*kT{8m`vh*+WR1~1dX_{r|Ljg06$q~h+JXx|OjZjJR6v;!bq%)>SurZm6 zeg=ps$+V={G&`gv3rj>JhD8jA4ora%0`}7PJBXTO0KdP#yIuON z=>M#`q-lT4hVBnQG6<3f5+NGkkb@BW(yzz4_+Q7>SiPDG{QB33ie{XEqdCAcw3FZm z7v*n`0Sq**@eu_})~?7ow`it;Yug>kHY$ zKz&#aXUL2x?>Kug?S6q9w|Y7*j65YOeQ{&?rq~5ECW=~Sax-S@HsM}+_$qLH|9X;+ z7tchn505C3{Vl?P(hE&Ty$$0m<8AD< ztW`p|)f=knMDwMu!VtncA>YSS#>m9;RoAkbKzT9wf{q>;1_<-!!eG3r{P&w7eCIiJ z-Ywl7Z?$DQ;VSj+EkAJ7W4xXXZ%(xEWN-1~YUH<_$ZiD&yeDZr@8dVkHIj}GeTS5| z+C}ckkR0F3$( ANdN!< literal 0 HcmV?d00001 diff --git a/integrations/gitea-repositories-meta/user13/repo11.git/objects/ed/447543e0c85d628b91f7f466f4921908f4c5ea b/integrations/gitea-repositories-meta/user13/repo11.git/objects/ed/447543e0c85d628b91f7f466f4921908f4c5ea new file mode 100644 index 0000000000000000000000000000000000000000..b3a1046feeb8d44c745f3dc828cbfe46e01632c5 GIT binary patch literal 54 zcmb .text.grey").Text()) + text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section.segment > .text.grey").Text()) assert.NotEmpty(t, text, "Can't find WIP text") // remove from lang diff --git a/models/status.go b/models/commit_status.go similarity index 75% rename from models/status.go rename to models/commit_status.go index 384f5693dc..74a2756303 100644 --- a/models/status.go +++ b/models/commit_status.go @@ -6,16 +6,14 @@ package models import ( "container/list" + "crypto/sha1" "fmt" "strings" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - - "github.com/go-xorm/xorm" ) // CommitStatusState holds the state of a Status @@ -61,6 +59,7 @@ type CommitStatus struct { SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` TargetURL string `xorm:"TEXT"` Description string `xorm:"TEXT"` + ContextHash string `xorm:"char(40) index"` Context string `xorm:"TEXT"` Creator *User `xorm:"-"` CreatorID int64 @@ -146,7 +145,7 @@ func GetLatestCommitStatus(repo *Repository, sha string, page int) ([]*CommitSta Table(&CommitStatus{}). Where("repo_id = ?", repo.ID).And("sha = ?", sha). Select("max( id ) as id"). - GroupBy("context").OrderBy("max( id ) desc").Find(&ids) + GroupBy("context_hash").OrderBy("max( id ) desc").Find(&ids) if err != nil { return nil, err } @@ -157,27 +156,6 @@ func GetLatestCommitStatus(repo *Repository, sha string, page int) ([]*CommitSta return statuses, x.In("id", ids).Find(&statuses) } -// GetCommitStatus populates a given status for a given commit. -// NOTE: If ID or Index isn't given, and only Context, TargetURL and/or Description -// is given, the CommitStatus created _last_ will be returned. -func GetCommitStatus(repo *Repository, sha string, status *CommitStatus) (*CommitStatus, error) { - conds := &CommitStatus{ - Context: status.Context, - State: status.State, - TargetURL: status.TargetURL, - Description: status.Description, - } - has, err := x.Where("repo_id = ?", repo.ID).And("sha = ?", sha).Desc("created_unix").Get(conds) - if err != nil { - return nil, fmt.Errorf("GetCommitStatus[%s, %s]: %v", repo.RepoPath(), sha, err) - } - if !has { - return nil, fmt.Errorf("GetCommitStatus[%s, %s]: not found", repo.RepoPath(), sha) - } - - return conds, nil -} - // NewCommitStatusOptions holds options for creating a CommitStatus type NewCommitStatusOptions struct { Repo *Repository @@ -186,30 +164,30 @@ type NewCommitStatusOptions struct { CommitStatus *CommitStatus } -func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error { +// NewCommitStatus save commit statuses into database +func NewCommitStatus(opts NewCommitStatusOptions) error { + if opts.Repo == nil { + return fmt.Errorf("NewCommitStatus[nil, %s]: no repository specified", opts.SHA) + } + + repoPath := opts.Repo.RepoPath() + if opts.Creator == nil { + return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA) + } + + sess := x.NewSession() + defer sess.Close() + + if err := sess.Begin(); err != nil { + return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", opts.Repo.ID, opts.Creator.ID, opts.SHA, err) + } + opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description) opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context) opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL) opts.CommitStatus.SHA = opts.SHA opts.CommitStatus.CreatorID = opts.Creator.ID - - if opts.Repo == nil { - return fmt.Errorf("newCommitStatus[nil, %s]: no repository specified", opts.SHA) - } opts.CommitStatus.RepoID = opts.Repo.ID - repoPath := opts.Repo.repoPath(sess) - - if opts.Creator == nil { - return fmt.Errorf("newCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA) - } - - gitRepo, err := git.OpenRepository(repoPath) - if err != nil { - return fmt.Errorf("OpenRepository[%s]: %v", repoPath, err) - } - if _, err := gitRepo.GetCommit(opts.SHA); err != nil { - return fmt.Errorf("GetCommit[%s]: %v", opts.SHA, err) - } // Get the next Status Index var nextIndex int64 @@ -220,46 +198,25 @@ func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error { has, err := sess.Desc("index").Limit(1).Get(lastCommitStatus) if err != nil { if err := sess.Rollback(); err != nil { - log.Error("newCommitStatus: sess.Rollback: %v", err) + log.Error("NewCommitStatus: sess.Rollback: %v", err) } - return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) + return fmt.Errorf("NewCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) } if has { - log.Debug("newCommitStatus[%s, %s]: found", repoPath, opts.SHA) + log.Debug("NewCommitStatus[%s, %s]: found", repoPath, opts.SHA) nextIndex = lastCommitStatus.Index } opts.CommitStatus.Index = nextIndex + 1 - log.Debug("newCommitStatus[%s, %s]: %d", repoPath, opts.SHA, opts.CommitStatus.Index) + log.Debug("NewCommitStatus[%s, %s]: %d", repoPath, opts.SHA, opts.CommitStatus.Index) + + opts.CommitStatus.ContextHash = hashCommitStatusContext(opts.CommitStatus.Context) // Insert new CommitStatus if _, err = sess.Insert(opts.CommitStatus); err != nil { if err := sess.Rollback(); err != nil { - log.Error("newCommitStatus: sess.Rollback: %v", err) + log.Error("Insert CommitStatus: sess.Rollback: %v", err) } - return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) - } - - return nil -} - -// NewCommitStatus creates a new CommitStatus given a bunch of parameters -// NOTE: All text-values will be trimmed from whitespaces. -// Requires: Repo, Creator, SHA -func NewCommitStatus(repo *Repository, creator *User, sha string, status *CommitStatus) error { - sess := x.NewSession() - defer sess.Close() - - if err := sess.Begin(); err != nil { - return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", repo.ID, creator.ID, sha, err) - } - - if err := newCommitStatus(sess, NewCommitStatusOptions{ - Repo: repo, - Creator: creator, - SHA: sha, - CommitStatus: status, - }); err != nil { - return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", repo.ID, creator.ID, sha, err) + return fmt.Errorf("Insert CommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) } return sess.Commit() @@ -295,3 +252,8 @@ func ParseCommitsWithStatus(oldCommits *list.List, repo *Repository) *list.List } return newCommits } + +// hashCommitStatusContext hash context +func hashCommitStatusContext(context string) string { + return fmt.Sprintf("%x", sha1.Sum([]byte(context))) +} diff --git a/models/status_test.go b/models/commit_status_test.go similarity index 100% rename from models/status_test.go rename to models/commit_status_test.go diff --git a/models/fixtures/issue.yml b/models/fixtures/issue.yml index 01bd8b86f6..585242a14d 100644 --- a/models/fixtures/issue.yml +++ b/models/fixtures/issue.yml @@ -86,3 +86,14 @@ created_unix: 946684830 updated_unix: 978307200 +- + id: 8 + repo_id: 10 + index: 1 + poster_id: 11 + name: pr2 + content: a pull request + is_closed: false + is_pull: true + created_unix: 946684820 + updated_unix: 978307180 \ No newline at end of file diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index d8313f9f90..baaaf6bb8a 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -26,3 +26,17 @@ base_branch: master merge_base: fedcba9876543210 has_merged: false + +- + id: 3 + type: 0 # gitea pull request + status: 2 # mergable + issue_id: 8 + index: 1 + head_repo_id: 11 + base_repo_id: 10 + head_user_name: user13 + head_branch: branch2 + base_branch: master + merge_base: 0abcb056019adb83 + has_merged: false \ No newline at end of file diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 609f421a90..f43fae3d67 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -118,7 +118,7 @@ is_private: false num_issues: 0 num_closed_issues: 0 - num_pulls: 0 + num_pulls: 1 num_closed_pulls: 0 is_mirror: false num_forks: 1 @@ -496,4 +496,4 @@ num_stars: 0 num_forks: 0 num_issues: 0 - is_mirror: false + is_mirror: false \ No newline at end of file diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index e8fb42c492..7a5b0c4184 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -229,6 +229,8 @@ var migrations = []Migration{ NewMigration("add http method to webhook", addHTTPMethodToWebhook), // v87 -> v88 NewMigration("add avatar field to repository", addAvatarFieldToRepository), + // v88 -> v89 + NewMigration("add commit status context field to commit_status", addCommitStatusContext), } // Migrate database to current version diff --git a/models/migrations/v87.go b/models/migrations/v87.go index 94711ac669..c8c7011a08 100644 --- a/models/migrations/v87.go +++ b/models/migrations/v87.go @@ -1,4 +1,4 @@ -// Copyright 2019 Gitea. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. diff --git a/models/migrations/v88.go b/models/migrations/v88.go new file mode 100644 index 0000000000..fef425db0a --- /dev/null +++ b/models/migrations/v88.go @@ -0,0 +1,66 @@ +// Copyright 2019 The Gitea 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 migrations + +import ( + "crypto/sha1" + "fmt" + + "github.com/go-xorm/xorm" +) + +func hashContext(context string) string { + return fmt.Sprintf("%x", sha1.Sum([]byte(context))) +} + +func addCommitStatusContext(x *xorm.Engine) error { + type CommitStatus struct { + ID int64 `xorm:"pk autoincr"` + ContextHash string `xorm:"char(40) index"` + Context string `xorm:"TEXT"` + } + + if err := x.Sync2(new(CommitStatus)); err != nil { + return err + } + + sess := x.NewSession() + defer sess.Close() + + var start = 0 + for { + var statuses = make([]*CommitStatus, 0, 100) + err := sess.OrderBy("id").Limit(100, start).Find(&statuses) + if err != nil { + return err + } + if len(statuses) == 0 { + break + } + + if err = sess.Begin(); err != nil { + return err + } + + for _, status := range statuses { + status.ContextHash = hashContext(status.Context) + if _, err := sess.ID(status.ID).Cols("context_hash").Update(status); err != nil { + return err + } + } + + if err := sess.Commit(); err != nil { + return err + } + + if len(statuses) < 100 { + break + } + + start += len(statuses) + } + + return nil +} diff --git a/modules/repofiles/commit_status.go b/modules/repofiles/commit_status.go new file mode 100644 index 0000000000..f3dfbf209f --- /dev/null +++ b/modules/repofiles/commit_status.go @@ -0,0 +1,39 @@ +// Copyright 2019 The Gitea 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 repofiles + +import ( + "fmt" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" +) + +// CreateCommitStatus creates a new CommitStatus given a bunch of parameters +// NOTE: All text-values will be trimmed from whitespaces. +// Requires: Repo, Creator, SHA +func CreateCommitStatus(repo *models.Repository, creator *models.User, sha string, status *models.CommitStatus) error { + repoPath := repo.RepoPath() + + // confirm that commit is exist + gitRepo, err := git.OpenRepository(repoPath) + if err != nil { + return fmt.Errorf("OpenRepository[%s]: %v", repoPath, err) + } + if _, err := gitRepo.GetCommit(sha); err != nil { + return fmt.Errorf("GetCommit[%s]: %v", sha, err) + } + + if err := models.NewCommitStatus(models.NewCommitStatusOptions{ + Repo: repo, + Creator: creator, + SHA: sha, + CommitStatus: status, + }); err != nil { + return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", repo.ID, creator.ID, sha, err) + } + + return nil +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index acaa98c3a2..223df91fda 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -981,6 +981,9 @@ pulls.rebase_merge_commit_pull_request = Rebase and Merge (--no-ff) pulls.squash_merge_pull_request = Squash and Merge pulls.invalid_merge_option = You cannot use this merge option for this pull request. pulls.open_unmerged_pull_exists = `You cannot perform a reopen operation because there is a pending pull request (#%d) with identical properties.` +pulls.status_checking = Some checks are pending +pulls.status_checks_success = All checks were successful +pulls.status_checks_error = Some checks failed milestones.new = New Milestone milestones.open_tab = %d Open diff --git a/public/css/index.css b/public/css/index.css index 2bf2f96181..3418847a4f 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -535,6 +535,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} .repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} .repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px} +.repository.view.issue .comment-list .comment .content>.merge-section{border-top:1px solid #d4d4d5;background-color:#f7f7f7} .repository.view.issue .comment-list .comment .content .markdown{font-size:14px} .repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic} .repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5} diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index e94b150cdc..a93404cad0 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -111,6 +111,7 @@ footer{background:#2e323e;border-top:1px solid #313131} .ui.attached.segment{border:1px solid #404552} .repository.view.issue .comment-list .comment .content>.bottom.segment{background:#353945} .repository.view.issue .comment-list .comment .content .header{color:#dbdbdb;background-color:#404552;border-bottom:1px solid #353944} +.repository.view.issue .comment-list .comment .content .merge-section{background-color:#404552;border-top:1px solid #353944} .ui .text.grey a{color:#dbdbdb!important} .ui.comments .comment .actions a{color:#dbdbdb} .repository.view.issue .comment-list .comment .content .header:after{border-right-color:#404552} diff --git a/public/less/_repository.less b/public/less/_repository.less index a8b2e22569..5a57f5db71 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -813,6 +813,11 @@ } } + > .merge-section { + border-top: 1px solid #d4d4d5; + background-color: #f7f7f7; + } + .markdown { font-size: 14px; } diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index 4fd98280ef..4780756bce 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -590,6 +590,11 @@ a.ui.basic.green.label:hover { border-bottom: 1px solid #353944; } +.repository.view.issue .comment-list .comment .content .merge-section { + background-color: #404552; + border-top: 1px solid #353944; +} + .ui .text.grey a { color: #dbdbdb !important; } diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index 487e62c91d..1aa4f4e1a1 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/repofiles" api "code.gitea.io/gitea/modules/structs" ) @@ -57,17 +58,12 @@ func NewCommitStatus(ctx *context.APIContext, form api.CreateStatusOption) { Description: form.Description, Context: form.Context, } - if err := models.NewCommitStatus(ctx.Repo.Repository, ctx.User, sha, status); err != nil { - ctx.Error(500, "NewCommitStatus", err) + if err := repofiles.CreateCommitStatus(ctx.Repo.Repository, ctx.User, sha, status); err != nil { + ctx.Error(500, "CreateCommitStatus", err) return } - newStatus, err := models.GetCommitStatus(ctx.Repo.Repository, sha, status) - if err != nil { - ctx.Error(500, "GetCommitStatus", err) - return - } - ctx.JSON(201, newStatus.APIFormat()) + ctx.JSON(201, status.APIFormat()) } // GetCommitStatuses returns all statuses for any given commit hash @@ -140,6 +136,7 @@ func getCommitStatuses(ctx *context.APIContext, sha string) { statuses, err := models.GetCommitStatuses(repo, sha, page) if err != nil { ctx.Error(500, "GetCommitStatuses", fmt.Errorf("GetCommitStatuses[%s, %s, %d]: %v", repo.FullName(), sha, page, err)) + return } apiStatuses := make([]*api.Status, 0, len(statuses)) diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 36b0d047b1..4c377bb364 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -321,15 +321,37 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare setMergeTarget(ctx, pull) var headGitRepo *git.Repository + var headBranchExist bool + // HeadRepo may be missing if pull.HeadRepo != nil { headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath()) if err != nil { ctx.ServerError("OpenRepository", err) return nil } + + headBranchExist = headGitRepo.IsBranchExist(pull.HeadBranch) + + if headBranchExist { + sha, err := headGitRepo.GetBranchCommitID(pull.HeadBranch) + if err != nil { + ctx.ServerError("GetBranchCommitID", err) + return nil + } + + commitStatuses, err := models.GetLatestCommitStatus(repo, sha, 0) + if err != nil { + ctx.ServerError("GetLatestCommitStatus", err) + return nil + } + if len(commitStatuses) > 0 { + ctx.Data["LatestCommitStatuses"] = commitStatuses + ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(commitStatuses) + } + } } - if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) { + if pull.HeadRepo == nil || !headBranchExist { ctx.Data["IsPullRequestBroken"] = true ctx.Data["HeadTarget"] = "deleted" ctx.Data["NumCommits"] = 0 diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 73c4179080..caadba41c7 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -45,7 +45,8 @@ {{else if .Issue.PullRequest.CanAutoMerge}}green {{else}}red{{end}}">
    -
    + {{template "repo/pulls/status" .}} +
    {{if .Issue.PullRequest.HasMerged}}
    {{$.i18n.Tr "repo.pulls.has_merged"}} diff --git a/templates/repo/pulls/status.tmpl b/templates/repo/pulls/status.tmpl new file mode 100644 index 0000000000..e1401aa8bb --- /dev/null +++ b/templates/repo/pulls/status.tmpl @@ -0,0 +1,21 @@ +{{if $.LatestCommitStatus}} +
    + {{if eq .LatestCommitStatus.State "pending"}} + {{$.i18n.Tr "repo.pulls.status_checking"}} + {{else if eq .LatestCommitStatus.State "success"}} + {{$.i18n.Tr "repo.pulls.status_checks_success"}} + {{else if eq .LatestCommitStatus.State "error"}} + {{$.i18n.Tr "repo.pulls.status_checks_error"}} + {{else}} + {{$.i18n.Tr "repo.pulls.status_checking"}} + {{end}} +
    + + {{range $.LatestCommitStatuses}} +
    + {{template "repo/commit_status" .}} + {{.Context}} {{.Description}} +
    {{if .TargetURL}}Details{{end}}
    +
    + {{end}} +{{end}} \ No newline at end of file From 8ab2d31bfe3540f510a6f2e48c7ffdfdee066cac Mon Sep 17 00:00:00 2001 From: Cherrg Date: Sun, 30 Jun 2019 13:55:48 +0200 Subject: [PATCH 165/220] fix topic bar to allow prefixes (#7325) * - do not select if escape is pressed - allow prefixes by adding current request content to result list - remove html-tags before insert on page fix #7126 Signed-off-by: Michael Gnehr * sort current query to top Signed-off-by: Michael Gnehr * remove already added topics from dropdown list Signed-off-by: Michael Gnehr * protoct against xss thanks to @silverwind Signed-off-by: Michael Gnehr --- public/js/index.js | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index 53fcaa8ba1..b932ef9590 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2847,6 +2847,7 @@ function initTopicbar() { topicDropdown.dropdown({ allowAdditions: true, + forceSelection: false, fields: { name: "description", value: "data-value" }, saveRemoteData: false, label: { @@ -2864,18 +2865,50 @@ function initTopicbar() { throttle: 500, cache: false, onResponse: function(res) { - var formattedResponse = { + let formattedResponse = { success: false, results: [], }; + const stripTags = function (text) { + return text.replace(/<[^>]*>?/gm, ""); + }; + + let query = stripTags(this.urlData.query.trim()); + let found_query = false; + let current_topics = []; + topicDropdown.find('div.label.visible.topic,a.label.visible').each(function(_,e){ current_topics.push(e.dataset.value); }); if (res.topics) { - formattedResponse.success = true; - for (var i=0;i < res.topics.length;i++) { - formattedResponse.results.push({"description": res.topics[i].Name, "data-value": res.topics[i].Name}) + let found = false; + for (let i=0;i < res.topics.length;i++) { + // skip currently added tags + if (current_topics.indexOf(res.topics[i].Name) != -1){ + continue; + } + + if (res.topics[i].Name.toLowerCase() === query.toLowerCase()){ + found_query = true; + } + formattedResponse.results.push({"description": res.topics[i].Name, "data-value": res.topics[i].Name}); + found = true; } + formattedResponse.success = found; } + if (query.length > 0 && !found_query){ + formattedResponse.success = true; + formattedResponse.results.unshift({"description": query, "data-value": query}); + } else if (query.length > 0 && found_query) { + formattedResponse.results.sort(function(a, b){ + if (a.description.toLowerCase() === query.toLowerCase()) return -1; + if (b.description.toLowerCase() === query.toLowerCase()) return 1; + if (a.description > b.description) return -1; + if (a.description < b.description) return 1; + return 0; + }); + } + + return formattedResponse; }, }, From 17fa227f372c47d6ba6f0c42104ca731db108d88 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 30 Jun 2019 11:57:58 +0000 Subject: [PATCH 166/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 20 ++++++++++++++++++++ options/locale/locale_zh-CN.ini | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 4f07874cfc..fe250a42f0 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -259,6 +259,7 @@ authorization_failed=Autorización fallida [mail] activate_account=Por favor, active su cuenta activate_email=Verifique su correo electrónico +reset_password=Recupere su cuenta register_success=Registro completado register_notify=¡Bienvenido a Gitea @@ -289,6 +290,8 @@ Content=Contenido require_error=` no puede estar vacío.` alpha_dash_error=` solo debe contener caracteres alfanuméricos, guiones medios ('-') y guiones bajos ('_').` +alpha_dash_dot_error=` solo debe contener caracteres alfanuméricos, guiones, ('-'), subrayados ('_'), y puntos ('.').` +git_ref_name_error=` debe ser un nombre de referencia de Git bien formado.` size_error=` debe ser de tamaño %s.` min_size_error=` debe contener al menos %s caracteres.` max_size_error=` debe contener como máximo %s caracteres.` @@ -300,6 +303,12 @@ captcha_incorrect=El código CAPTCHA no es correcto. password_not_match=Las contraseñas no coinciden. username_been_taken=El nombre de usuario ya está en uso. +repo_name_been_taken=El nombre del repositorio ya está usado. +org_name_been_taken=Ya existe una organización con este nombre. +team_name_been_taken=Ya existe un equipo con este nombre. +team_no_units_error=Permitir el acceso a por lo menos una sección del repositorio. +email_been_used=La dirección de correo electrónico ya está usada. +openid_been_used=La dirección OpenID '%s' ya está usada. user_not_exist=Este usuario no existe. last_org_owner=No puedes eliminar al último usuario del equipo de 'propietarios'. Debe haber al menos un propietario en ningún equipo dado. cannot_add_org_to_team=Una organización no puede ser añadida como miembro de un equipo. @@ -472,6 +481,7 @@ file_history=Histórico file_view_raw=Ver original file_permalink=Enlace permanente stored_lfs=Almacenados con Git LFS +blame=Blame editor.preview_changes=Vista previa de los cambios editor.or=o @@ -600,6 +610,9 @@ pulls.reopen_to_merge=Vuelva a abrir la solicitud de "pull" para realizar una fu pulls.merged=Fusionado pulls.can_auto_merge_desc=Este Pull Request puede ser fusionado automáticamente. pulls.merge_pull_request=Fusionar Pull Request +pulls.status_checking=Algunas comprobaciones están pendientes +pulls.status_checks_success=Todas las comprobaciones han sido exitosas +pulls.status_checks_error=Algunas comprobaciones han fallado milestones.new=Nuevo hito milestones.open_tab=%d abiertas @@ -652,6 +665,13 @@ activity.closed_issue_label=Cerrada activity.new_issues_count_1=Nueva incidencia activity.new_issues_count_n=Nuevas incidencias activity.new_issue_label=Abierta +activity.no_git_activity=No ha habido ningún commit en este período. +activity.git_stats_author_1=%d autor +activity.git_stats_author_n=%d autores +activity.git_stats_commit_1=%d commit +activity.git_stats_on_default_branch=En %s, +activity.git_stats_file_1=%d archivo +activity.git_stats_file_n=%d archivos search=Buscar search.search_repo=Buscar repositorio diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index f99ae4bda5..aee909e059 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -980,6 +980,9 @@ pulls.rebase_merge_commit_pull_request=变基合并 (--no-ff) pulls.squash_merge_pull_request=压缩提交并合并 pulls.invalid_merge_option=你可以在此合并请求中使用合并选项。 pulls.open_unmerged_pull_exists=`您不能执行重新打开操作, 因为已经存在相同的合并请求 (#%d)。` +pulls.status_checking=一些检测仍在等待运行 +pulls.status_checks_success=所有检测均成功 +pulls.status_checks_error=一些检测失败 milestones.new=新的里程碑 milestones.open_tab=%d 开启中 @@ -1865,6 +1868,7 @@ push_tag=推送了标签 %[2]s% delete_tag=从%[3]s 删除了标签 %[2]s delete_branch=从 %[3]s 删除分支 %[2]s compare_commits=比较 %d 提交 +compare_commits_general=比较提交 mirror_sync_push=从镜像同步了 %[3]s 分支的代码到 %[4]s mirror_sync_create=从镜像同步了新的引用 %[2]s%[3]s mirror_sync_delete=从镜像同步并从 %[3]s 删除了引用 %[2]s From 36448bc923a2d7a7f2f2ae99453a6f1549b52841 Mon Sep 17 00:00:00 2001 From: Alexandru Bucur Date: Mon, 1 Jul 2019 00:17:43 +0300 Subject: [PATCH 167/220] 1.8.3 release (#7332) --- docs/content/doc/installation/from-binary.en-us.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/doc/installation/from-binary.en-us.md b/docs/content/doc/installation/from-binary.en-us.md index 12e38e8096..e41028eeb2 100644 --- a/docs/content/doc/installation/from-binary.en-us.md +++ b/docs/content/doc/installation/from-binary.en-us.md @@ -21,7 +21,7 @@ the destination platform from the [downloads page](https://dl.gitea.io/gitea/), the URL and replace the URL within the commands below: ```sh -wget -O gitea https://dl.gitea.io/gitea/1.7.0/gitea-1.7.0-linux-amd64 +wget -O gitea https://dl.gitea.io/gitea/1.8.3/gitea-1.8.3-linux-amd64 chmod +x gitea ``` @@ -30,7 +30,7 @@ Gitea signs all binaries with a [GPG key](https://pgp.mit.edu/pks/lookup?op=vind ```sh gpg --keyserver pgp.mit.edu --recv 7C9E68152594688862D62AF62D9AE806EC1592E2 -gpg --verify gitea-1.7.0-linux-amd64.asc gitea-1.7.0-linux-amd64 +gpg --verify gitea-1.8.3-linux-amd64.asc gitea-1.8.3-linux-amd64 ``` ## Test From 0dca17b760fc9a0a655588f472ec31d3d05f2269 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 30 Jun 2019 21:20:34 +0000 Subject: [PATCH 168/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 39 ++++++++++++++++++++++++++++++--- options/locale/locale_ja-JP.ini | 4 ++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index fe250a42f0..f8eba821d9 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -255,6 +255,7 @@ authorize_application_created_by=Esta aplicación fue creada por %s. authorize_application_description=Si concede el acceso, podrá acceder y escribir a toda la información de su cuenta, incluyendo repositorios privado y organizaciones. authorize_title=¿Autorizar a "%s" a acceder a su cuenta? authorization_failed=Autorización fallida +authorization_failed_desc=La autorización ha fallado porque hemos detectado una solicitud no válida. Por favor, póngase en contacto con el mantenedor de la aplicación que ha intentado autorizar. [mail] activate_account=Por favor, active su cuenta @@ -309,6 +310,8 @@ team_name_been_taken=Ya existe un equipo con este nombre. team_no_units_error=Permitir el acceso a por lo menos una sección del repositorio. email_been_used=La dirección de correo electrónico ya está usada. openid_been_used=La dirección OpenID '%s' ya está usada. +username_password_incorrect=El nombre de usuario o la contraseña son incorrectos. +enterred_invalid_repo_name=El nombre de repositorio que ha entrado es incorrecto. user_not_exist=Este usuario no existe. last_org_owner=No puedes eliminar al último usuario del equipo de 'propietarios'. Debe haber al menos un propietario en ningún equipo dado. cannot_add_org_to_team=Una organización no puede ser añadida como miembro de un equipo. @@ -324,6 +327,7 @@ still_has_org=Su cuenta es miembro de una o más organizaciones; déjalas primer target_branch_not_exist=La rama de destino no existe [user] +change_avatar=Cambiar su avatar… join_on=Registrado el repositories=Repositorios activity=Actividad pública @@ -350,6 +354,7 @@ public_profile=Perfil público full_name=Nombre completo website=Página web location=Localización +update_theme=Actualizar tema update_profile=Actualizar perfil update_profile_success=Tu perfil ha sido actualizado. continue=Continuar @@ -358,14 +363,20 @@ cancel=Cancelar federated_avatar_lookup=Búsqueda de Avatar Federado enable_custom_avatar=Activar avatar personalizado choose_new_avatar=Selecciona nuevo avatar +update_avatar=Actualizar Avatar delete_current_avatar=Eliminar avatar +update_avatar_success=Su avatar ha sido actualizado. +change_password=Actualizar contraseña old_password=Contraseña actual new_password=Nueva contraseña +password_incorrect=Contraseña actual incorrecta. +password_change_disabled=Los usuarios no locales no pueden actualizar su contraseña a través de la interfaz web de Gitea. emails=Direcciones de correo electrónico email_desc=Tu dirección de correo principal se utilizará para las notificaciones y otras operaciones. primary=Principal +theme_update_success=Su tema fue actualizado. add_openid=Añadir nuevo OpenID URI manage_ssh_keys=Gestionar Claves SSH @@ -379,6 +390,7 @@ subkeys=Subclaves key_id=ID de clave key_name=Nombre de la Clave key_content=Contenido +ssh_key_deletion_desc=Eliminando una clave SSH se revoca su acceso a su cuenta. ¿Continuar? add_on=Añadido en valid_until=Válido hasta valid_forever=Válido para siempre @@ -398,7 +410,11 @@ token_name=Nombre del Token generate_token=Generar Token delete_token=Eliminar +update_oauth2_application_success=Ha actualizado correctamente la aplicación OAuth2. +oauth2_regenerate_secret_hint=¿Ha perdido su secreto? +oauth2_client_secret_hint=El secreto no será visible si revisa esta página. Por favor, guarda su secreto. +authorized_oauth2_applications_description=Ha concedido acceso a su cuenta personal de Gitea a estas aplicaciones de terceros. Por favor, revoque el acceso a los aplicaciones que ya no son necesarias. twofa_is_enrolled=Su cuenta actualmente está registrada en la autenticación de doble factor. twofa_not_enrolled=Tu cuenta no está actualmente inscrita en la autenticación de doble factor. @@ -412,7 +428,9 @@ then_enter_passcode=E introduzca el código de acceso mostrado en la aplicación passcode_invalid=El código de acceso es incorrecto. Vuelva a intentarlo. twofa_enrolled=Su cuenta ha sido inscrita en la autenticación de doble factor. ¡Guarde su código de respaldo (%s) en un lugar seguro, ya que sólo se muestra una vez! +u2f_require_twofa=Su cuenta debe tener activada la autenticación de doble factor para utilizar claves de seguridad. +account_links_not_available=Actualmente no hay cuentas externas vinculadas a su cuenta de Gitea. orgs_none=No eres miembro de ninguna organización. repos_none=No posees ningún repositorio @@ -424,8 +442,9 @@ confirm_delete_account=Confirmar Eliminación owner=Propietario repo_name=Nombre del repositorio visibility=Visibilidad -fork_repo=Hacer Fork del repositorio -fork_from=Crear un Fork desde +visibility_fork_helper=(Cambiar esto afectará a todos los forks) +fork_repo=Hacer fork del repositorio +fork_from=Crear un fork desde repo_desc=Descripción repo_lang=Idioma license=Licencia @@ -450,7 +469,9 @@ migrate.permission_denied=No te está permitido importar repositorios locales. migrate.failed=Migración fallida: %v mirror_from=espejo de -forked_from=forked de +forked_from=forkeado de +fork_from_self=No puede hacer fork a un repositorio que ya es suyo. +fork_guest_user=Regístrate para forkear este repositorio. copy_link=Copiar copied=Copiado OK unwatch=Dejar de seguir @@ -484,6 +505,7 @@ stored_lfs=Almacenados con Git LFS blame=Blame editor.preview_changes=Vista previa de los cambios +editor.fork_before_edit=Debes hacer fork a este repositorio para hacer o proponer cambios a este archivo. editor.or=o editor.commit_changes=Crear commit de los cambios editor.add=Añadir '%s' @@ -591,6 +613,8 @@ issues.attachment.open_tab='Haga clic para ver "%s" en una pestaña nueva' issues.attachment.download=`Haga clic para descargar "%s"` issues.subscribe=Suscribir issues.unsubscribe=Desuscribirse +issues.lock.notice_3=- Siempre puede desbloquear esta incidencia de nuevo en el futuro. +issues.unlock.notice_2=- Siempre puede bloquear esta incidencia de nuevo en el futuro. issues.start_tracking_short=Iniciar issues.start_tracking_history=`ha empezado a trabajar %s` issues.tracking_already_started='Ya has comenzado el tiempo de seguimiento en este tema!' @@ -608,6 +632,7 @@ pulls.tab_conversation=Conversación pulls.tab_commits=Commits pulls.reopen_to_merge=Vuelva a abrir la solicitud de "pull" para realizar una fusión. pulls.merged=Fusionado +pulls.data_broken=Este pull request está rota debido a que falta información del fork. pulls.can_auto_merge_desc=Este Pull Request puede ser fusionado automáticamente. pulls.merge_pull_request=Fusionar Pull Request pulls.status_checking=Algunas comprobaciones están pendientes @@ -628,6 +653,8 @@ milestones.due_date=Fecha límite (opcional) milestones.clear=Limpiar milestones.edit=Editar Milestone milestones.cancel=Cancelar +milestones.modify=Actualizar hito +milestones.edit_success=El hito '%s' ha sido actualizado. milestones.filter_sort.most_complete=Más completa milestones.filter_sort.most_issues=Mayoría de los problemas milestones.filter_sort.least_issues=Menos problemas @@ -716,6 +743,7 @@ settings.discord_username=Usuario settings.discord_icon_url=URL de icono settings.slack_color=Color settings.event_create=Crear +settings.event_fork_desc=Repositorio forkeado settings.update_webhook=Actualizar Webhook settings.recent_deliveries=Envíos Recientes settings.hook_type=Tipo de Hook @@ -831,6 +859,7 @@ monitor=Monitorización first_page=Primera last_page=Última +dashboard.system_status=Estado del sistema dashboard.operation_name=Nombre de la operación dashboard.operation_switch=Interruptor dashboard.operation_run=Ejecutar @@ -882,6 +911,7 @@ repos.name=Nombre repos.private=Privado repos.watches=Vigilantes repos.stars=Estrellas +repos.forks=Forks repos.issues=Incidencias @@ -972,6 +1002,7 @@ config.session_life_time=Tiempo de Vida de la Sesión config.https_only=Sólo HTTPS config.cookie_life_time=Tiempo de Vida de la Cookie +config.picture_config=Configuración de imagen y avatar config.picture_service=Servicio de Imágen config.disable_gravatar=Desactivar Gravatar config.enable_federated_avatar=Habilitar Avatares Federados @@ -1033,6 +1064,7 @@ delete_branch=rama %[2]s eliminada, de %[3]s ago=hace %s from_now=desde ahora %s now=ahora +future=futuro 1s=1 segundo 1m=1 minuto 1h=1 hora @@ -1062,6 +1094,7 @@ mark_as_read=Marcar como leído mark_as_unread=Marcar como no leído [gpg] +error.extract_sign=Error al extraer la firma error.no_gpg_keys_found=No se encontró ninguna clave conocida en la base de datos para esta firma [units] diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 131a59da5e..79ddc673c2 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -980,6 +980,9 @@ pulls.rebase_merge_commit_pull_request=リベースしてマージ(--no-ff) pulls.squash_merge_pull_request=スカッシュしてマージ pulls.invalid_merge_option=このプルリクエストでは、指定したマージ方法は使えません。 pulls.open_unmerged_pull_exists=`同じ条件のプルリクエスト (#%d) が未処理のため、再オープンはできません。` +pulls.status_checking=いくつかの検証が待機中です +pulls.status_checks_success=検証はすべて成功しました +pulls.status_checks_error=検証がいくつか失敗しました milestones.new=新しいマイルストーン milestones.open_tab=%d件 オープン中 @@ -1865,6 +1868,7 @@ push_tag=がタグ %[2]s%[3]s%[3]s から削除しました delete_branch=がブランチ %[2]s を %[3]s から削除しました compare_commits=%d件のコミットを比較 +compare_commits_general=コミットを比較 mirror_sync_push=が %[4]s%[3]s へのコミットをミラーから反映しました mirror_sync_create=が %[3]s の新しい参照 %[2]s をミラーから反映しました mirror_sync_delete=が %[3]s の参照 %[2]s をミラーから反映し、削除しました From e5a4d784e8dda105832a28ccee0d593bf9dd6348 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Mon, 1 Jul 2019 07:53:41 +0800 Subject: [PATCH 169/220] chore: update drone format to 1.0 (#6602) * chore: update drone format to 1.0 * Converted old drone config Signed-off-by: konrad * Moved translations to seperate pipeline Signed-off-by: konrad * Split the steps in multiple pipelines and add dependencies Signed-off-by: konrad * format Signed-off-by: konrad * Fixed step depenednecies Signed-off-by: konrad * Fixed discord notify Signed-off-by: konrad * Exclude translations and docs pipelines from prs Signed-off-by: konrad * Fixed exclude prs Signed-off-by: konrad * Fixed exclude prs Signed-off-by: konrad * Moved releases to seperate pipeline Signed-off-by: konrad * Re-trigger drone Signed-off-by: konrad * Disable release step Signed-off-by: konrad * Fixed depending step Signed-off-by: konrad * Adopted dependencies Signed-off-by: konrad * Changed pipeline conditions Signed-off-by: konrad * Replaced pipeline conditions with triggers Signed-off-by: konrad * Fixed coverage step Signed-off-by: konrad * Import changes from #7331 Signed-off-by: konrad * Add comment for lowest go version Signed-off-by: konrad * Exclude fetch-tags from prs Signed-off-by: konrad * Re-added comment about no tags Signed-off-by: konrad * Removed unneeded conditions Signed-off-by: konrad * Moved release version and release latest to different pipelines Signed-off-by: konrad * Fixed depending pipeline Signed-off-by: konrad * Removed the conditions for all services Signed-off-by: konrad --- .drone.yml | 882 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 543 insertions(+), 339 deletions(-) diff --git a/.drone.yml b/.drone.yml index fca798d288..0e2d9845db 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,75 +1,75 @@ +--- +kind: pipeline +name: testing + +platform: + os: linux + arch: amd64 + workspace: base: /go path: src/code.gitea.io/gitea -pipeline: - fetch-tags: +services: + - name: mysql + pull: default + image: mysql:5.7 + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_DATABASE: test + + - name: mysql8 + pull: default + image: mysql:8.0 + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_DATABASE: testgitea + + - name: pgsql + pull: default + image: postgres:9.5 + environment: + POSTGRES_DB: test + + - name: mssql + pull: default + image: microsoft/mssql-server-linux:latest + environment: + ACCEPT_EULA: Y + MSSQL_PID: Standard + SA_PASSWORD: MwantsaSecurePassword1 + + - name: ldap + pull: default + image: gitea/test-openldap:latest + +steps: + - name: fetch-tags + pull: default image: docker:git commands: - git fetch --tags --force when: event: - exclude: [ pull_request ] + exclude: + - pull_request - download_translations: - image: jonasfranz/crowdin - pull: true - secrets: [ crowdin_key ] - project_identifier: gitea - ignore_branch: true - download: true - export_dir: options/locale/ - when: - event: [ push ] - branch: [ master ] - - update-translations: - image: alpine:3.10 - commands: - - mv ./options/locale/locale_en-US.ini ./options/ - - sed -i -e 's/="/=/g' -e 's/"$$//g' ./options/locale/*.ini - - sed -i -e 's/\\\\"/"/g' ./options/locale/*.ini - - mv ./options/locale_en-US.ini ./options/locale/ - when: - event: [ push ] - branch: [ master ] - - git_push: - image: appleboy/drone-git-push - pull: true - secrets: [ git_push_ssh_key ] - remote: git@github.com:go-gitea/gitea.git - force: false - commit: true - commit_message: "[skip ci] Updated translations via Crowdin" - author_name: GiteaBot - author_email: teabot@gitea.io - when: - event: [ push ] - branch: [ master ] - - pre-build: + - name: pre-build + pull: always image: webhippie/nodejs:latest - pull: true commands: - make css - make js - when: - event: [ push, tag, pull_request ] - build-without-gcc: + - name: build-without-gcc + pull: always image: golang:1.10 # this step is kept as the lowest version of golang that we support - pull: true commands: - go build -o gitea_no_gcc # test if build succeeds without the sqlite tag - when: - event: [ push, tag, pull_request ] - build: + - name: build + pull: always image: golang:1.12 - pull: true - environment: - TAGS: bindata sqlite sqlite_unlock_notify commands: - make clean - make generate @@ -79,371 +79,575 @@ pipeline: - make swagger-validate - make test-vendor - make build - when: - event: [ push, tag, pull_request ] - - unit-test: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata sqlite sqlite_unlock_notify + + - name: unit-test + pull: always + image: golang:1.12 commands: - make unit-test-coverage - when: - event: [ push, pull_request ] - branch: [ master ] - - release-test: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata sqlite sqlite_unlock_notify + depends_on: + - build + when: + branch: + - master + event: + - push + - pull_request + + - name: release-test + pull: always + image: golang:1.12 commands: - make test - when: - event: [ push, pull_request ] - branch: [ release/* ] - - tag-test: - image: golang:1.12 - pull: true - group: test environment: - TAGS: bindata + TAGS: bindata sqlite sqlite_unlock_notify + depends_on: + - build + when: + branch: + - "release/*" + event: + - push + - pull_request + + - name: tag-test + pull: always + image: golang:1.12 commands: - make test - when: - event: [ tag ] - - test-sqlite: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata + depends_on: + - build + when: + event: + - tag + + - name: test-sqlite + pull: always + image: golang:1.12 commands: - - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - timeout -s ABRT 20m make test-sqlite-migration - timeout -s ABRT 20m make test-sqlite - when: - event: [ push, tag, pull_request ] - - test-mysql: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata - TEST_LDAP: "1" + depends_on: + - build + + - name: test-mysql + pull: always + image: golang:1.12 commands: - - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - make test-mysql-migration - make integration-test-coverage - when: - event: [ push, pull_request ] - branch: [ master ] - - tag-test-mysql: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata - TEST_LDAP: "1" + TEST_LDAP: 1 + depends_on: + - build + when: + branch: + - master + event: + - push + - pull_request + + - name: tag-test-mysql + pull: always + image: golang:1.12 commands: - - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - timeout -s ABRT 20m make test-mysql-migration - timeout -s ABRT 20m make test-mysql - when: - event: [ tag ] - - test-mysql8: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata - TEST_LDAP: "1" + TEST_LDAP: 1 + depends_on: + - build + when: + event: + - tag + + - name: test-mysql8 + pull: always + image: golang:1.12 commands: - - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - timeout -s ABRT 20m make test-mysql8-migration - timeout -s ABRT 20m make test-mysql8 - when: - event: [ push, tag, pull_request ] - - test-pgsql: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata - TEST_LDAP: "1" + TEST_LDAP: 1 + depends_on: + - build + + - name: test-pgsql + pull: always + image: golang:1.12 commands: - - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - timeout -s ABRT 20m make test-pgsql-migration - timeout -s ABRT 20m make test-pgsql - when: - event: [ push, tag, pull_request ] - - test-mssql: - image: golang:1.12 - pull: true - group: test environment: TAGS: bindata - TEST_LDAP: "1" + TEST_LDAP: 1 + depends_on: + - build + + - name: test-mssql + pull: always + image: golang:1.12 commands: - - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - make test-mssql-migration - make test-mssql - when: - event: [ push, tag, pull_request ] - -# bench-sqlite: -# image: golang:1.12 -# pull: true -# group: bench -# commands: -# - make bench-sqlite -# when: -# event: [ tag ] - -# bench-mysql: -# image: golang:1.12 -# pull: true -# group: bench -# commands: -# - make bench-mysql -# when: -# event: [ tag ] - -# bench-mssql: -# image: golang:1.12 -# pull: true -# group: bench -# commands: -# - make bench-mssql -# when: -# event: [ tag ] - -# bench-pgsql: -# image: golang:1.12 -# pull: true -# group: bench -# commands: -# - make bench-pgsql -# when: -# event: [ tag ] - - generate-coverage: - image: golang:1.12 - pull: true environment: TAGS: bindata + TEST_LDAP: 1 + depends_on: + - build + + - name: generate-coverage + pull: always + image: golang:1.12 commands: - make coverage - when: - event: [ push, pull_request ] - branch: [ master ] - - coverage: - image: robertstettner/drone-codecov - secrets: [ codecov_token ] - files: - - coverage.all - when: - event: [ push, pull_request ] - branch: [ master ] - - static: - image: techknowlogick/xgo:latest - pull: true environment: - TAGS: bindata sqlite sqlite_unlock_notify + TAGS: bindata + depends_on: + - unit-test + - test-mysql + when: + branch: + - master + event: + - push + - pull_request + + - name: coverage + pull: always + image: robertstettner/drone-codecov + settings: + files: + - coverage.all + environment: + CODECOV_TOKEN: + from_secret: codecov_token + depends_on: + - generate-coverage + when: + branch: + - master + event: + - push + - pull_request + +--- +kind: pipeline +name: translations + +platform: + os: linux + arch: amd64 + +workspace: + base: /go + path: src/code.gitea.io/gitea + +trigger: + branch: + - master + event: + - push + +steps: + - name: download + pull: always + image: jonasfranz/crowdin + settings: + download: true + export_dir: options/locale/ + ignore_branch: true + project_identifier: gitea + environment: + CROWDIN_KEY: + from_secret: crowdin_key + + - name: update + pull: default + image: alpine:3.10 + commands: + - mv ./options/locale/locale_en-US.ini ./options/ + - "sed -i -e 's/=\"/=/g' -e 's/\"$$//g' ./options/locale/*.ini" + - "sed -i -e 's/\\\\\\\\\"/\"/g' ./options/locale/*.ini" + - mv ./options/locale_en-US.ini ./options/locale/ + + - name: push + pull: always + image: appleboy/drone-git-push + settings: + author_email: "teabot@gitea.io" + author_name: GiteaBot + commit: true + commit_message: "[skip ci] Updated translations via Crowdin" + remote: "git@github.com:go-gitea/gitea.git" + environment: + GIT_PUSH_SSH_KEY: + from_secret: git_push_ssh_key + + - name: upload_translations + pull: always + image: jonasfranz/crowdin + settings: + files: + locale_en-US.ini: options/locale/locale_en-US.ini + ignore_branch: true + project_identifier: gitea + environment: + CROWDIN_KEY: + from_secret: crowdin_key + +--- +kind: pipeline +name: release-master + +platform: + os: linux + arch: amd64 + +workspace: + base: /go + path: src/code.gitea.io/gitea + +trigger: + branch: + - master + - "release/*" + event: + - push + +depends_on: + - testing + - translations + +steps: + - name: fetch-tags + pull: default + image: docker:git + commands: + - git fetch --tags --force + + - name: static + pull: always + image: techknowlogick/xgo:latest commands: - export PATH=$PATH:$GOPATH/bin - make release - when: - event: [ push, tag ] + environment: + TAGS: bindata sqlite sqlite_unlock_notify - build-docs: + - name: gpg-sign + pull: always + image: plugins/gpgsign:1 + settings: + detach_sign: true + excludes: + - "dist/release/*.sha256" + files: + - "dist/release/*" + environment: + GPGSIGN_KEY: + from_secret: gpgsign_key + GPGSIGN_PASSPHRASE: + from_secret: gpgsign_passphrase + depends_on: + - static + + - name: release-branch-release + pull: always + image: plugins/s3:1 + settings: + acl: public-read + bucket: releases + endpoint: https://storage.gitea.io + path_style: true + source: "dist/release/*" + strip_prefix: dist/release/ + target: "/gitea/${DRONE_BRANCH##release/v}" + environment: + AWS_ACCESS_KEY_ID: + from_secret: aws_access_key_id + AWS_SECRET_ACCESS_KEY: + from_secret: aws_secret_access_key + depends_on: + - gpg-sign + when: + branch: + - "release/*" + event: + - push + + - name: release + pull: always + image: plugins/s3:1 + settings: + acl: public-read + bucket: releases + endpoint: https://storage.gitea.io + path_style: true + source: "dist/release/*" + strip_prefix: dist/release/ + target: /gitea/master + environment: + AWS_ACCESS_KEY_ID: + from_secret: aws_access_key_id + AWS_SECRET_ACCESS_KEY: + from_secret: aws_secret_access_key + depends_on: + - gpg-sign + when: + branch: + - master + event: + - push + +--- +kind: pipeline +name: release-version + +platform: + os: linux + arch: amd64 + +workspace: + base: /go + path: src/code.gitea.io/gitea + +trigger: + event: + - tag + +depends_on: + - testing + - translations + +steps: + - name: fetch-tags + pull: default + image: docker:git + commands: + - git fetch --tags --force + + - name: static + pull: always + image: techknowlogick/xgo:latest + commands: + - export PATH=$PATH:$GOPATH/bin + - make release + environment: + TAGS: bindata sqlite sqlite_unlock_notify + + - name: gpg-sign + pull: always + image: plugins/gpgsign:1 + settings: + detach_sign: true + excludes: + - "dist/release/*.sha256" + files: + - "dist/release/*" + environment: + GPGSIGN_KEY: + from_secret: gpgsign_key + GPGSIGN_PASSPHRASE: + from_secret: gpgsign_passphrase + depends_on: + - static + + - name: release + pull: always + image: plugins/s3:1 + settings: + acl: public-read + bucket: releases + endpoint: https://storage.gitea.io + path_style: true + source: "dist/release/*" + strip_prefix: dist/release/ + target: "/gitea/${DRONE_TAG##v}" + environment: + AWS_ACCESS_KEY_ID: + from_secret: aws_access_key_id + AWS_SECRET_ACCESS_KEY: + from_secret: aws_secret_access_key + depends_on: + - gpg-sign + + - name: github + pull: always + image: plugins/github-release:1 + settings: + files: + - "dist/release/*" + environment: + GITHUB_TOKEN: + from_secret: github_token + depends_on: + - gpg-sign + +--- +kind: pipeline +name: docs + +platform: + os: linux + arch: amd64 + +workspace: + base: /go + path: src/code.gitea.io/gitea + +trigger: + branch: + - master + event: + - push + +steps: + - name: build-docs + pull: always image: webhippie/hugo:latest - pull: true commands: - cd docs - make trans-copy - make clean - make build - publish-docs: + - name: publish-docs + pull: always image: lucap/drone-netlify:latest - pull: true - secrets: [ netlify_token ] - site_id: d2260bae-7861-4c02-8646-8f6440b12672 - path: docs/public/ - when: - event: [ push ] - branch: [ master ] + settings: + path: docs/public/ + site_id: d2260bae-7861-4c02-8646-8f6440b12672 + environment: + NETLIFY_TOKEN: + from_secret: netlify_token - docker-dryrun: +--- +kind: pipeline +name: docker + +platform: + os: linux + arch: amd64 + +workspace: + base: /go + path: src/code.gitea.io/gitea + +steps: + - name: fetch-tags + pull: default + image: docker:git + commands: + - git fetch --tags --force + + - name: dryrun + pull: always image: plugins/docker:18.09 - pull: true - repo: gitea/gitea - cache_from: gitea/gitea - dry_run: true + settings: + cache_from: gitea/gitea + dry_run: true + repo: gitea/gitea when: - event: [ pull_request ] + event: + - pull_request - release-docker: + - name: release + pull: always image: plugins/docker:18.09 - pull: true - secrets: [ docker_username, docker_password ] - repo: gitea/gitea - tags: [ '${DRONE_BRANCH##release/v}' ] - cache_from: gitea/gitea + settings: + cache_from: gitea/gitea + repo: gitea/gitea + tags: + - "${DRONE_BRANCH##release/v}" + environment: + DOCKER_PASSWORD: + from_secret: docker_password + DOCKER_USERNAME: + from_secret: docker_username + depends_on: + - dryrun when: - event: [ push ] - branch: [ release/* ] + branch: + - "release/*" + event: + - push - docker: + - name: latest + pull: always image: plugins/docker:18.09 - secrets: [ docker_username, docker_password ] - pull: true - repo: gitea/gitea - cache_from: gitea/gitea - default_tags: true + settings: + cache_from: gitea/gitea + default_tags: true + repo: gitea/gitea + environment: + DOCKER_PASSWORD: + from_secret: docker_password + DOCKER_USERNAME: + from_secret: docker_username + depends_on: + - dryrun when: - event: [ push, tag ] + branch: + - master + event: + - push + - tag - gpg-sign: - image: plugins/gpgsign:1 - pull: true - secrets: [ gpgsign_key, gpgsign_passphrase ] - detach_sign: true - files: - - dist/release/* - excludes: - - dist/release/*.sha256 - when: - event: [ push, tag ] +--- +kind: pipeline +name: notify - tag-release: - image: plugins/s3:1 - pull: true - secrets: [ aws_access_key_id, aws_secret_access_key ] - bucket: releases - acl: public-read - endpoint: https://storage.gitea.io - path_style: true - strip_prefix: dist/release/ - source: dist/release/* - target: /gitea/${DRONE_TAG##v} - when: - event: [ tag ] +platform: + os: linux + arch: amd64 - release-branch-release: - image: plugins/s3:1 - pull: true - secrets: [ aws_access_key_id, aws_secret_access_key ] - bucket: releases - acl: public-read - endpoint: https://storage.gitea.io - path_style: true - strip_prefix: dist/release/ - source: dist/release/* - target: /gitea/${DRONE_BRANCH##release/v} - when: - event: [ push ] - branch: [ release/* ] +workspace: + base: /go + path: src/code.gitea.io/gitea - release: - image: plugins/s3:1 - pull: true - secrets: [ aws_access_key_id, aws_secret_access_key ] - bucket: releases - acl: public-read - endpoint: https://storage.gitea.io - path_style: true - strip_prefix: dist/release/ - source: dist/release/* - target: /gitea/master - when: - event: [ push ] - branch: [ master ] +when: + status: + - success + - failure - github: - image: plugins/github-release:1 - pull: true - secrets: [ github_token ] - files: - - dist/release/* - when: - event: [ tag ] +depends_on: + - testing + - translations + - release-version + - release-master + - docker + - docs - upload_translations: - image: jonasfranz/crowdin - pull: true - secrets: [ crowdin_key ] - project_identifier: gitea - ignore_branch: true - download: false - files: - locale_en-US.ini: options/locale/locale_en-US.ini - when: - event: [ push ] - branch: [ master ] - - discord: +steps: + - name: discord + pull: always image: appleboy/drone-discord:1.0.0 - pull: true - secrets: [ discord_webhook_id, discord_webhook_token ] - when: - event: [ push, tag, pull_request ] - status: [ changed, failure ] - -services: - mysql: - image: mysql:5.7 environment: - - MYSQL_DATABASE=test - - MYSQL_ALLOW_EMPTY_PASSWORD=yes - when: - event: [ push, tag, pull_request ] - - mysql8: - image: mysql:8.0 - environment: - - MYSQL_DATABASE=test - - MYSQL_ALLOW_EMPTY_PASSWORD=yes - - MYSQL_DATABASE=testgitea - when: - event: [ push, tag, pull_request ] - - pgsql: - image: postgres:9.5 - environment: - - POSTGRES_DB=test - when: - event: [ push, tag, pull_request ] - - mssql: - image: microsoft/mssql-server-linux:latest - environment: - - ACCEPT_EULA=Y - - SA_PASSWORD=MwantsaSecurePassword1 - - MSSQL_PID=Standard - when: - event: [ push, tag, pull_request ] - - ldap: - image: gitea/test-openldap:latest - when: - event: [ push, tag, pull_request ] + DISCORD_WEBHOOK_ID: + from_secret: discord_webhook_id + DISCORD_WEBHOOK_TOKEN: + from_secret: discord_webhook_token From 3563650bdb273045c55400ee9520a0f78fc90e76 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 1 Jul 2019 02:18:13 +0100 Subject: [PATCH 170/220] #6946 Run hooks on merge/edit and cope with protected branches (#6961) * Fix #6946 by checking PullRequest ID on pushing * Ensure we have the owner name, the pr attributes and the the issue * Fix TestSearchRepo by waiting till indexing is done * Update integrations/repo_search_test.go * changes as per @mrsdizzie * missing comma * Spelling mistake * Fix full pushing environment --- cmd/hook.go | 2 ++ cmd/serv.go | 3 +-- models/branches.go | 2 ++ models/helper_environment.go | 22 +++++++++++++++------- models/pull.go | 2 +- modules/private/hook.go | 4 +++- modules/pull/merge.go | 12 +++++++++++- routers/private/hook.go | 20 +++++++++++++++++++- 8 files changed, 54 insertions(+), 13 deletions(-) diff --git a/cmd/hook.go b/cmd/hook.go index b3e900afee..ca876f02a3 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -65,6 +65,7 @@ func runHookPreReceive(c *cli.Context) error { username := os.Getenv(models.EnvRepoUsername) reponame := os.Getenv(models.EnvRepoName) userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64) + prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64) buf := bytes.NewBuffer(nil) scanner := bufio.NewScanner(os.Stdin) @@ -95,6 +96,7 @@ func runHookPreReceive(c *cli.Context) error { UserID: userID, GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories), GitObjectDirectory: os.Getenv(private.GitObjectDirectory), + ProtectedBranchID: prID, }) switch statusCode { case http.StatusInternalServerError: diff --git a/cmd/serv.go b/cmd/serv.go index 2ea89757db..32dd8cbd3e 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -191,6 +191,7 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvPusherName, results.UserName) os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10)) + os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) //LFS token authentication if verb == lfsAuthenticateVerb { @@ -239,8 +240,6 @@ func runServ(c *cli.Context) error { gitcmd = exec.Command(verb, repoPath) } - os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", results.RepoID)) - gitcmd.Dir = setting.RepoRootPath gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin diff --git a/models/branches.go b/models/branches.go index df3b69aa21..fa4215d6a0 100644 --- a/models/branches.go +++ b/models/branches.go @@ -19,6 +19,8 @@ import ( const ( // ProtectedBranchRepoID protected Repo ID ProtectedBranchRepoID = "GITEA_REPO_ID" + // ProtectedBranchPRID protected Repo PR ID + ProtectedBranchPRID = "GITEA_PR_ID" ) // ProtectedBranch struct diff --git a/models/helper_environment.go b/models/helper_environment.go index 199eb6062d..0460fc3df5 100644 --- a/models/helper_environment.go +++ b/models/helper_environment.go @@ -12,26 +12,34 @@ import ( // PushingEnvironment returns an os environment to allow hooks to work on push func PushingEnvironment(doer *User, repo *Repository) []string { + return FullPushingEnvironment(doer, doer, repo, 0) +} + +// FullPushingEnvironment returns an os environment to allow hooks to work on push +func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string { isWiki := "false" if strings.HasSuffix(repo.Name, ".wiki") { isWiki = "true" } - sig := doer.NewGitSig() + authorSig := author.NewGitSig() + committerSig := committer.NewGitSig() // We should add "SSH_ORIGINAL_COMMAND=gitea-internal", // once we have hook and pushing infrastructure working correctly return append(os.Environ(), - "GIT_AUTHOR_NAME="+sig.Name, - "GIT_AUTHOR_EMAIL="+sig.Email, - "GIT_COMMITTER_NAME="+sig.Name, - "GIT_COMMITTER_EMAIL="+sig.Email, + "GIT_AUTHOR_NAME="+authorSig.Name, + "GIT_AUTHOR_EMAIL="+authorSig.Email, + "GIT_COMMITTER_NAME="+committerSig.Name, + "GIT_COMMITTER_EMAIL="+committerSig.Email, EnvRepoName+"="+repo.Name, EnvRepoUsername+"="+repo.MustOwnerName(), EnvRepoIsWiki+"="+isWiki, - EnvPusherName+"="+doer.Name, - EnvPusherID+"="+fmt.Sprintf("%d", doer.ID), + EnvPusherName+"="+committer.Name, + EnvPusherID+"="+fmt.Sprintf("%d", committer.ID), ProtectedBranchRepoID+"="+fmt.Sprintf("%d", repo.ID), + ProtectedBranchPRID+"="+fmt.Sprintf("%d", prID), + "SSH_ORIGINAL_COMMAND=gitea-internal", ) } diff --git a/models/pull.go b/models/pull.go index eac36235bb..6ee2ec555d 100644 --- a/models/pull.go +++ b/models/pull.go @@ -876,7 +876,7 @@ func (pr *PullRequest) UpdatePatch() (err error) { if err = pr.GetHeadRepo(); err != nil { return fmt.Errorf("GetHeadRepo: %v", err) } else if pr.HeadRepo == nil { - log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID) + log.Trace("PullRequest[%d].UpdatePatch: ignored corrupted data", pr.ID) return nil } diff --git a/modules/private/hook.go b/modules/private/hook.go index 7e2a475d4b..caa3819555 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -29,11 +29,12 @@ type HookOptions struct { UserName string GitObjectDirectory string GitAlternativeObjectDirectories string + ProtectedBranchID int64 } // HookPreReceive check whether the provided commits are allowed func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s", + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&prID=%d", url.PathEscape(ownerName), url.PathEscape(repoName), url.QueryEscape(opts.OldCommitID), @@ -42,6 +43,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) opts.UserID, url.QueryEscape(opts.GitObjectDirectory), url.QueryEscape(opts.GitAlternativeObjectDirectories), + opts.ProtectedBranchID, ) resp, err := newInternalRequest(reqURL, "GET").Response() diff --git a/modules/pull/merge.go b/modules/pull/merge.go index e12ede81d6..5685336a2b 100644 --- a/modules/pull/merge.go +++ b/modules/pull/merge.go @@ -231,7 +231,17 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor } } - env := models.PushingEnvironment(doer, pr.BaseRepo) + headUser, err := models.GetUserByName(pr.HeadUserName) + if err != nil { + if !models.IsErrUserNotExist(err) { + log.Error("Can't find user: %s for head repository - %v", pr.HeadUserName, err) + return err + } + log.Error("Can't find user: %s for head repository - defaulting to doer: %s - %v", pr.HeadUserName, doer.Name, err) + headUser = doer + } + + env := models.FullPushingEnvironment(headUser, doer, pr.BaseRepo, pr.ID) // Push back to upstream. if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { diff --git a/routers/private/hook.go b/routers/private/hook.go index 3da5e38edb..1071c57bc0 100644 --- a/routers/private/hook.go +++ b/routers/private/hook.go @@ -31,6 +31,7 @@ func HookPreReceive(ctx *macaron.Context) { userID := ctx.QueryInt64("userID") gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory") gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories") + prID := ctx.QueryInt64("prID") branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) @@ -85,7 +86,24 @@ func HookPreReceive(ctx *macaron.Context) { } } - if !protectBranch.CanUserPush(userID) { + canPush := protectBranch.CanUserPush(userID) + if !canPush && prID > 0 { + pr, err := models.GetPullRequestByID(prID) + if err != nil { + log.Error("Unable to get PullRequest %d Error: %v", prID, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Unable to get PullRequest %d Error: %v", prID, err), + }) + return + } + if !protectBranch.HasEnoughApprovals(pr) { + log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v and pr #%d does not have enough approvals", userID, branchName, repo, pr.Index) + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": fmt.Sprintf("protected branch %s can not be pushed to and pr #%d does not have enough approvals", branchName, prID), + }) + return + } + } else if !canPush { log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v", userID, branchName, repo) ctx.JSON(http.StatusForbidden, map[string]interface{}{ "err": fmt.Sprintf("protected branch %s can not be pushed to", branchName), From 9c6af9d2bb6a173fac51a58415e69665c550d7fa Mon Sep 17 00:00:00 2001 From: Cherrg Date: Mon, 1 Jul 2019 03:56:26 +0200 Subject: [PATCH 171/220] wrap long texts on user profile info (#7333) fix #7255 discussed in PR #7254 Signed-off-by: Michael Gnehr --- public/css/index.css | 1 + public/less/_base.less | 5 +++++ templates/user/profile.tmpl | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 3418847a4f..303cbc4ef6 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -47,6 +47,7 @@ img{border-radius:3px} table{border-collapse:collapse} a{cursor:pointer} .rounded{border-radius:.28571429rem!important} +.wrap{word-wrap:break-word;word-break:break-all} .mono,code,pre{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} .mono.raw,code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto} .mono.wrap,code.wrap,pre.wrap{white-space:pre-wrap;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word} diff --git a/public/less/_base.less b/public/less/_base.less index 213ae2d2e6..4ce1b8eff9 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -159,6 +159,11 @@ a { border-radius: 0.28571429rem !important; } +.wrap { + word-wrap: break-word; + word-break: break-all; +} + pre, code, .mono { diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 833de90b8c..52c6e3ec3f 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -13,11 +13,11 @@ {{end}} -
    +
    {{if .Owner.FullName}}{{.Owner.FullName}}{{end}} {{.Owner.Name}}
    -
    +
      {{if .Owner.Location}}
    • {{.Owner.Location}}
    • From 1772c6b94d8e1a574d29643a33f1c0dbc0fdbe6f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 1 Jul 2019 12:08:43 +0800 Subject: [PATCH 172/220] fix pull view ui merge section (#7335) * fix pull view ui merge section * fix tests * fix tests --- integrations/pull_merge_test.go | 2 +- templates/repo/issue/view_content/pull.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go index 4266a194eb..f3efa63b07 100644 --- a/integrations/pull_merge_test.go +++ b/integrations/pull_merge_test.go @@ -159,7 +159,7 @@ func TestCantMergeWorkInProgress(t *testing.T) { req := NewRequest(t, "GET", resp.Header().Get("Location")) resp = session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section.segment > .text.grey").Text()) + text := strings.TrimSpace(htmlDoc.doc.Find(".attached.header > .text.grey").Last().Text()) assert.NotEmpty(t, text, "Can't find WIP text") // remove from lang diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index caadba41c7..7bb3c91275 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -46,7 +46,7 @@ {{else}}red{{end}}">
      {{template "repo/pulls/status" .}} -
      +
      {{if .Issue.PullRequest.HasMerged}}
      {{$.i18n.Tr "repo.pulls.has_merged"}} From 5f25558ac2225ef444d8987c61e0337d44a020ef Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Mon, 1 Jul 2019 03:32:50 -0400 Subject: [PATCH 173/220] fix updated drone file (#7336) --- .drone.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 0e2d9845db..9c07599940 100644 --- a/.drone.yml +++ b/.drone.yml @@ -354,6 +354,7 @@ steps: image: techknowlogick/xgo:latest commands: - export PATH=$PATH:$GOPATH/bin + - make generate - make release environment: TAGS: bindata sqlite sqlite_unlock_notify @@ -455,6 +456,7 @@ steps: image: techknowlogick/xgo:latest commands: - export PATH=$PATH:$GOPATH/bin + - make generate - make release environment: TAGS: bindata sqlite sqlite_unlock_notify @@ -519,12 +521,6 @@ workspace: base: /go path: src/code.gitea.io/gitea -trigger: - branch: - - master - event: - - push - steps: - name: build-docs pull: always @@ -544,6 +540,11 @@ steps: environment: NETLIFY_TOKEN: from_secret: netlify_token + when: + branch: + - master + event: + - push --- kind: pipeline @@ -563,6 +564,10 @@ steps: image: docker:git commands: - git fetch --tags --force + when: + event: + exclude: + - pull_request - name: dryrun pull: always From 9fdd199cca780a13b44a667ee862b1ec3ff37958 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 1 Jul 2019 20:26:59 +0100 Subject: [PATCH 174/220] make dropTableColumns drop columns on sqlite and constraints on all (#6849) --- models/migrations/migrations.go | 92 ++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 7a5b0c4184..ef43b0453b 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -13,6 +13,7 @@ import ( "os" "path" "path/filepath" + "regexp" "strings" "time" @@ -284,11 +285,98 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin if tableName == "" || len(columnNames) == 0 { return nil } + // TODO: This will not work if there are foreign keys switch { case setting.UseSQLite3: - log.Warn("Unable to drop columns in SQLite") - case setting.UseMySQL, setting.UseTiDB, setting.UsePostgreSQL: + // First drop the indexes on the columns + res, errIndex := sess.Query(fmt.Sprintf("PRAGMA index_list(`%s`)", tableName)) + if errIndex != nil { + return errIndex + } + for _, row := range res { + indexName := row["name"] + indexRes, err := sess.Query(fmt.Sprintf("PRAGMA index_info(`%s`)", indexName)) + if err != nil { + return err + } + if len(indexRes) != 1 { + continue + } + indexColumn := string(indexRes[0]["name"]) + for _, name := range columnNames { + if name == indexColumn { + _, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s`", indexName)) + if err != nil { + return err + } + } + } + } + + // Here we need to get the columns from the original table + sql := fmt.Sprintf("SELECT sql FROM sqlite_master WHERE tbl_name='%s' and type='table'", tableName) + res, err := sess.Query(sql) + if err != nil { + return err + } + tableSQL := string(res[0]["sql"]) + tableSQL = tableSQL[strings.Index(tableSQL, "("):] + for _, name := range columnNames { + tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*[,)]").ReplaceAllString(tableSQL, "") + } + + columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1) + + tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL + if _, err := sess.Exec(tableSQL); err != nil { + return err + } + + // Now restore the data + columnsSeparated := strings.Join(columns, ",") + insertSQL := fmt.Sprintf("INSERT INTO `new_%s_new` (%s) SELECT %s FROM %s", tableName, columnsSeparated, columnsSeparated, tableName) + if _, err := sess.Exec(insertSQL); err != nil { + return err + } + + // Now drop the old table + if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil { + return err + } + + // Rename the table + if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `new_%s_new` RENAME TO `%s`", tableName, tableName)); err != nil { + return err + } + + case setting.UsePostgreSQL: + cols := "" + for _, col := range columnNames { + if cols != "" { + cols += ", " + } + cols += "DROP COLUMN `" + col + "` CASCADE" + } + if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil { + return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err) + } + case setting.UseMySQL, setting.UseTiDB: + // Drop indexes on columns first + sql := fmt.Sprintf("SHOW INDEX FROM %s WHERE column_name IN ('%s')", tableName, strings.Join(columnNames, "','")) + res, err := sess.Query(sql) + if err != nil { + return err + } + for _, index := range res { + indexName := index["column_name"] + _, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s` ON `%s`", indexName, tableName)) + if err != nil { + return err + } + } + + // Now drop the columns cols := "" for _, col := range columnNames { if cols != "" { From e728b5581291d6d9a62fcd8ab2c3b2e6c89b7138 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 2 Jul 2019 05:17:16 +0800 Subject: [PATCH 175/220] Fix bug conflict between SyncReleasesWithTags and InsertReleases (#7337) * fix bug conflict between SyncReleasesWithTags and InsertReleases * fix tests * fix fmt --- models/release_test.go | 13 +++++++------ models/repo.go | 15 ++++++++------- modules/migrations/base/uploader.go | 2 +- modules/migrations/gitea.go | 22 ++++++++++++++-------- modules/migrations/migrate.go | 2 +- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/models/release_test.go b/models/release_test.go index f3f61240ea..83c3fe2f77 100644 --- a/models/release_test.go +++ b/models/release_test.go @@ -102,12 +102,13 @@ func TestRelease_MirrorDelete(t *testing.T) { repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) repoPath := RepoPath(user.Name, repo.Name) migrationOptions := MigrateRepoOptions{ - Name: "test_mirror", - Description: "Test mirror", - IsPrivate: false, - IsMirror: true, - RemoteAddr: repoPath, - Wiki: true, + Name: "test_mirror", + Description: "Test mirror", + IsPrivate: false, + IsMirror: true, + RemoteAddr: repoPath, + Wiki: true, + SyncReleasesWithTags: true, } mirror, err := MigrateRepository(user, user, migrationOptions) assert.NoError(t, err) diff --git a/models/repo.go b/models/repo.go index 1b4ff1f186..59ce18fa88 100644 --- a/models/repo.go +++ b/models/repo.go @@ -845,12 +845,13 @@ func (repo *Repository) CloneLink() (cl *CloneLink) { // MigrateRepoOptions contains the repository migrate options type MigrateRepoOptions struct { - Name string - Description string - IsPrivate bool - IsMirror bool - RemoteAddr string - Wiki bool // include wiki repository + Name string + Description string + IsPrivate bool + IsMirror bool + RemoteAddr string + Wiki bool // include wiki repository + SyncReleasesWithTags bool // sync releases from tags } /* @@ -942,7 +943,7 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err return repo, fmt.Errorf("git.IsEmpty: %v", err) } - if !repo.IsEmpty { + if opts.SyncReleasesWithTags && !repo.IsEmpty { // Try to get HEAD branch and set it as default branch. headBranch, err := gitRepo.GetHEADBranch() if err != nil { diff --git a/modules/migrations/base/uploader.go b/modules/migrations/base/uploader.go index 096a8ab8f0..9d2fd2af6a 100644 --- a/modules/migrations/base/uploader.go +++ b/modules/migrations/base/uploader.go @@ -7,7 +7,7 @@ package base // Uploader uploads all the informations of one repository type Uploader interface { - CreateRepo(repo *Repository, includeWiki bool) error + CreateRepo(repo *Repository, opts MigrateOptions) error CreateMilestones(milestones ...*Milestone) error CreateReleases(releases ...*Release) error CreateLabels(labels ...*Label) error diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 7d5a50d307..bfc5e49033 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -54,19 +54,20 @@ func NewGiteaLocalUploader(doer *models.User, repoOwner, repoName string) *Gitea } // CreateRepo creates a repository -func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, includeWiki bool) error { +func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.MigrateOptions) error { owner, err := models.GetUserByName(g.repoOwner) if err != nil { return err } r, err := models.MigrateRepository(g.doer, owner, models.MigrateRepoOptions{ - Name: g.repoName, - Description: repo.Description, - IsMirror: repo.IsMirror, - RemoteAddr: repo.CloneURL, - IsPrivate: repo.IsPrivate, - Wiki: includeWiki, + Name: g.repoName, + Description: repo.Description, + IsMirror: repo.IsMirror, + RemoteAddr: repo.CloneURL, + IsPrivate: repo.IsPrivate, + Wiki: opts.Wiki, + SyncReleasesWithTags: !opts.Releases, // if didn't get releases, then sync them from tags }) g.repo = r if err != nil { @@ -198,7 +199,12 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { rels = append(rels, &rel) } - return models.InsertReleases(rels...) + if err := models.InsertReleases(rels...); err != nil { + return err + } + + // sync tags to releases in database + return models.SyncReleasesWithTags(g.repo, g.gitRepo) } // CreateIssues creates issues diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 3a4e6b2dbe..ce8f9b8022 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -80,7 +80,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts repo.Description = opts.Description } log.Trace("migrating git data") - if err := uploader.CreateRepo(repo, opts.Wiki); err != nil { + if err := uploader.CreateRepo(repo, opts); err != nil { return err } From 6e2a59e4ceb89c4e369a5ff1cac95c31f7e7ecd6 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Tue, 2 Jul 2019 04:15:14 +0200 Subject: [PATCH 176/220] Use commit graph files for listing pages (#7314) * Experimental support for git commit graph files and bloom filter index Signed-off-by: Filip Navara * Force vendor of commitgraph Signed-off-by: Filip Navara * Remove bloom filter experiment and debug prints * Remove old code for building commit graphs * Remove unused function * Remove mmap usage * gofmt * sort vendor/modules.txt * Add copyright header and log commit-graph error --- modules/git/commit_info.go | 38 ++- modules/git/notes.go | 12 +- modules/git/repo_commitgraph.go | 35 +++ .../format/commitgraph/commitgraph.go | 35 +++ .../plumbing/format/commitgraph/doc.go | 103 +++++++ .../plumbing/format/commitgraph/encoder.go | 190 +++++++++++++ .../plumbing/format/commitgraph/file.go | 259 ++++++++++++++++++ .../plumbing/format/commitgraph/memory.go | 72 +++++ .../plumbing/object/commitgraph/commitnode.go | 98 +++++++ .../object/commitgraph/commitnode_graph.go | 131 +++++++++ .../object/commitgraph/commitnode_object.go | 90 ++++++ .../commitgraph/commitnode_walker_ctime.go | 105 +++++++ .../plumbing/object/commitgraph/doc.go | 7 + vendor/modules.txt | 4 +- 14 files changed, 1166 insertions(+), 13 deletions(-) create mode 100644 modules/git/repo_commitgraph.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/commitgraph.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/doc.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/encoder.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/file.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/memory.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_graph.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_object.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_walker_ctime.go create mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/doc.go diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go index 9270878c7f..8417226f8b 100644 --- a/modules/git/commit_info.go +++ b/modules/git/commit_info.go @@ -8,6 +8,7 @@ import ( "github.com/emirpasic/gods/trees/binaryheap" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/object" + cgobject "gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph" ) // GetCommitsInfo gets information of all commits that are corresponding to these entries @@ -19,7 +20,12 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCom entryPaths[i+1] = entry.Name() } - c, err := commit.repo.gogitRepo.CommitObject(plumbing.Hash(commit.ID)) + commitNodeIndex, commitGraphFile := commit.repo.CommitNodeIndex() + if commitGraphFile != nil { + defer commitGraphFile.Close() + } + + c, err := commitNodeIndex.Get(plumbing.Hash(commit.ID)) if err != nil { return nil, nil, err } @@ -69,14 +75,14 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCom } type commitAndPaths struct { - commit *object.Commit + commit cgobject.CommitNode // Paths that are still on the branch represented by commit paths []string // Set of hashes for the paths hashes map[string]plumbing.Hash } -func getCommitTree(c *object.Commit, treePath string) (*object.Tree, error) { +func getCommitTree(c cgobject.CommitNode, treePath string) (*object.Tree, error) { tree, err := c.Tree() if err != nil { return nil, err @@ -93,7 +99,7 @@ func getCommitTree(c *object.Commit, treePath string) (*object.Tree, error) { return tree, nil } -func getFileHashes(c *object.Commit, treePath string, paths []string) (map[string]plumbing.Hash, error) { +func getFileHashes(c cgobject.CommitNode, treePath string, paths []string) (map[string]plumbing.Hash, error) { tree, err := getCommitTree(c, treePath) if err == object.ErrDirectoryNotFound { // The whole tree didn't exist, so return empty map @@ -118,16 +124,16 @@ func getFileHashes(c *object.Commit, treePath string, paths []string) (map[strin return hashes, nil } -func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (map[string]*object.Commit, error) { +func getLastCommitForPaths(c cgobject.CommitNode, treePath string, paths []string) (map[string]*object.Commit, error) { // We do a tree traversal with nodes sorted by commit time heap := binaryheap.NewWith(func(a, b interface{}) int { - if a.(*commitAndPaths).commit.Committer.When.Before(b.(*commitAndPaths).commit.Committer.When) { + if a.(*commitAndPaths).commit.CommitTime().Before(b.(*commitAndPaths).commit.CommitTime()) { return 1 } return -1 }) - result := make(map[string]*object.Commit) + resultNodes := make(map[string]cgobject.CommitNode) initialHashes, err := getFileHashes(c, treePath, paths) if err != nil { return nil, err @@ -145,9 +151,9 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m // Load the parent commits for the one we are currently examining numParents := current.commit.NumParents() - var parents []*object.Commit + var parents []cgobject.CommitNode for i := 0; i < numParents; i++ { - parent, err := current.commit.Parent(i) + parent, err := current.commit.ParentNode(i) if err != nil { break } @@ -174,7 +180,7 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m for i, path := range current.paths { // The results could already contain some newer change for the same path, // so don't override that and bail out on the file early. - if result[path] == nil { + if resultNodes[path] == nil { if pathUnchanged[i] { // The path existed with the same hash in at least one parent so it could // not have been changed in this commit directly. @@ -188,7 +194,7 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m // - We are looking at a merge commit and the hash of the file doesn't // match any of the hashes being merged. This is more common for directories, // but it can also happen if a file is changed through conflict resolution. - result[path] = current.commit + resultNodes[path] = current.commit } } } @@ -222,5 +228,15 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m } } + // Post-processing + result := make(map[string]*object.Commit) + for path, commitNode := range resultNodes { + var err error + result[path], err = commitNode.Commit() + if err != nil { + return nil, err + } + } + return result, nil } diff --git a/modules/git/notes.go b/modules/git/notes.go index 7aa5d89a79..a62c558787 100644 --- a/modules/git/notes.go +++ b/modules/git/notes.go @@ -50,7 +50,17 @@ func GetNote(repo *Repository, commitID string, note *Note) error { return err } - lastCommits, err := getLastCommitForPaths(commit, "", []string{commitID}) + commitNodeIndex, commitGraphFile := repo.CommitNodeIndex() + if commitGraphFile != nil { + defer commitGraphFile.Close() + } + + commitNode, err := commitNodeIndex.Get(commit.Hash) + if err != nil { + return nil + } + + lastCommits, err := getLastCommitForPaths(commitNode, "", []string{commitID}) if err != nil { return err } diff --git a/modules/git/repo_commitgraph.go b/modules/git/repo_commitgraph.go new file mode 100644 index 0000000000..52263852dc --- /dev/null +++ b/modules/git/repo_commitgraph.go @@ -0,0 +1,35 @@ +// Copyright 2019 The Gitea 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 ( + "os" + "path" + + gitealog "code.gitea.io/gitea/modules/log" + "gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph" + cgobject "gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph" +) + +// CommitNodeIndex returns the index for walking commit graph +func (r *Repository) CommitNodeIndex() (cgobject.CommitNodeIndex, *os.File) { + indexPath := path.Join(r.Path, "objects", "info", "commit-graph") + + file, err := os.Open(indexPath) + if err == nil { + var index commitgraph.Index + index, err = commitgraph.OpenFileIndex(file) + if err == nil { + return cgobject.NewGraphCommitNodeIndex(index, r.gogitRepo.Storer), file + } + } + + if !os.IsNotExist(err) { + gitealog.Warn("Unable to read commit-graph for %s: %v", r.Path, err) + } + + return cgobject.NewObjectCommitNodeIndex(r.gogitRepo.Storer), nil +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/commitgraph.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/commitgraph.go new file mode 100644 index 0000000000..e43cd8978a --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/commitgraph.go @@ -0,0 +1,35 @@ +package commitgraph + +import ( + "time" + + "gopkg.in/src-d/go-git.v4/plumbing" +) + +// CommitData is a reduced representation of Commit as presented in the commit graph +// file. It is merely useful as an optimization for walking the commit graphs. +type CommitData struct { + // TreeHash is the hash of the root tree of the commit. + TreeHash plumbing.Hash + // ParentIndexes are the indexes of the parent commits of the commit. + ParentIndexes []int + // ParentHashes are the hashes of the parent commits of the commit. + ParentHashes []plumbing.Hash + // Generation number is the pre-computed generation in the commit graph + // or zero if not available + Generation int + // When is the timestamp of the commit. + When time.Time +} + +// Index represents a representation of commit graph that allows indexed +// access to the nodes using commit object hash +type Index interface { + // GetIndexByHash gets the index in the commit graph from commit hash, if available + GetIndexByHash(h plumbing.Hash) (int, error) + // GetNodeByIndex gets the commit node from the commit graph using index + // obtained from child node, if available + GetCommitDataByIndex(i int) (*CommitData, error) + // Hashes returns all the hashes that are available in the index + Hashes() []plumbing.Hash +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/doc.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/doc.go new file mode 100644 index 0000000000..41cd8b1e31 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/doc.go @@ -0,0 +1,103 @@ +// Package commitgraph implements encoding and decoding of commit-graph files. +// +// Git commit graph format +// ======================= +// +// The Git commit graph stores a list of commit OIDs and some associated +// metadata, including: +// +// - The generation number of the commit. Commits with no parents have +// generation number 1; commits with parents have generation number +// one more than the maximum generation number of its parents. We +// reserve zero as special, and can be used to mark a generation +// number invalid or as "not computed". +// +// - The root tree OID. +// +// - The commit date. +// +// - The parents of the commit, stored using positional references within +// the graph file. +// +// These positional references are stored as unsigned 32-bit integers +// corresponding to the array position within the list of commit OIDs. Due +// to some special constants we use to track parents, we can store at most +// (1 << 30) + (1 << 29) + (1 << 28) - 1 (around 1.8 billion) commits. +// +// == Commit graph files have the following format: +// +// In order to allow extensions that add extra data to the graph, we organize +// the body into "chunks" and provide a binary lookup table at the beginning +// of the body. The header includes certain values, such as number of chunks +// and hash type. +// +// All 4-byte numbers are in network order. +// +// HEADER: +// +// 4-byte signature: +// The signature is: {'C', 'G', 'P', 'H'} +// +// 1-byte version number: +// Currently, the only valid version is 1. +// +// 1-byte Hash Version (1 = SHA-1) +// We infer the hash length (H) from this value. +// +// 1-byte number (C) of "chunks" +// +// 1-byte (reserved for later use) +// Current clients should ignore this value. +// +// CHUNK LOOKUP: +// +// (C + 1) * 12 bytes listing the table of contents for the chunks: +// First 4 bytes describe the chunk id. Value 0 is a terminating label. +// Other 8 bytes provide the byte-offset in current file for chunk to +// start. (Chunks are ordered contiguously in the file, so you can infer +// the length using the next chunk position if necessary.) Each chunk +// ID appears at most once. +// +// The remaining data in the body is described one chunk at a time, and +// these chunks may be given in any order. Chunks are required unless +// otherwise specified. +// +// CHUNK DATA: +// +// OID Fanout (ID: {'O', 'I', 'D', 'F'}) (256 * 4 bytes) +// The ith entry, F[i], stores the number of OIDs with first +// byte at most i. Thus F[255] stores the total +// number of commits (N). +// +// OID Lookup (ID: {'O', 'I', 'D', 'L'}) (N * H bytes) +// The OIDs for all commits in the graph, sorted in ascending order. +// +// Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes) +// * The first H bytes are for the OID of the root tree. +// * The next 8 bytes are for the positions of the first two parents +// of the ith commit. Stores value 0x7000000 if no parent in that +// position. If there are more than two parents, the second value +// has its most-significant bit on and the other bits store an array +// position into the Extra Edge List chunk. +// * The next 8 bytes store the generation number of the commit and +// the commit time in seconds since EPOCH. The generation number +// uses the higher 30 bits of the first 4 bytes, while the commit +// time uses the 32 bits of the second 4 bytes, along with the lowest +// 2 bits of the lowest byte, storing the 33rd and 34th bit of the +// commit time. +// +// Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional] +// This list of 4-byte values store the second through nth parents for +// all octopus merges. The second parent value in the commit data stores +// an array position within this list along with the most-significant bit +// on. Starting at that array position, iterate through this list of commit +// positions for the parents until reaching a value with the most-significant +// bit on. The other bits correspond to the position of the last parent. +// +// TRAILER: +// +// H-byte HASH-checksum of all of the above. +// +// Source: +// https://raw.githubusercontent.com/git/git/master/Documentation/technical/commit-graph-format.txt +package commitgraph diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/encoder.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/encoder.go new file mode 100644 index 0000000000..a06871cb7c --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/encoder.go @@ -0,0 +1,190 @@ +package commitgraph + +import ( + "crypto/sha1" + "hash" + "io" + + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/utils/binary" +) + +// Encoder writes MemoryIndex structs to an output stream. +type Encoder struct { + io.Writer + hash hash.Hash +} + +// NewEncoder returns a new stream encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { + h := sha1.New() + mw := io.MultiWriter(w, h) + return &Encoder{mw, h} +} + +// Encode writes an index into the commit-graph file +func (e *Encoder) Encode(idx Index) error { + var err error + + // Get all the hashes in the input index + hashes := idx.Hashes() + + // Sort the inout and prepare helper structures we'll need for encoding + hashToIndex, fanout, extraEdgesCount := e.prepare(idx, hashes) + + chunkSignatures := [][]byte{oidFanoutSignature, oidLookupSignature, commitDataSignature} + chunkSizes := []uint64{4 * 256, uint64(len(hashes)) * 20, uint64(len(hashes)) * 36} + if extraEdgesCount > 0 { + chunkSignatures = append(chunkSignatures, extraEdgeListSignature) + chunkSizes = append(chunkSizes, uint64(extraEdgesCount)*4) + } + + if err = e.encodeFileHeader(len(chunkSignatures)); err != nil { + return err + } + if err = e.encodeChunkHeaders(chunkSignatures, chunkSizes); err != nil { + return err + } + if err = e.encodeFanout(fanout); err != nil { + return err + } + if err = e.encodeOidLookup(hashes); err != nil { + return err + } + if extraEdges, err := e.encodeCommitData(hashes, hashToIndex, idx); err == nil { + if err = e.encodeExtraEdges(extraEdges); err != nil { + return err + } + } + if err != nil { + return err + } + return e.encodeChecksum() +} + +func (e *Encoder) prepare(idx Index, hashes []plumbing.Hash) (hashToIndex map[plumbing.Hash]uint32, fanout []uint32, extraEdgesCount uint32) { + // Sort the hashes and build our index + plumbing.HashesSort(hashes) + hashToIndex = make(map[plumbing.Hash]uint32) + fanout = make([]uint32, 256) + for i, hash := range hashes { + hashToIndex[hash] = uint32(i) + fanout[hash[0]]++ + } + + // Convert the fanout to cumulative values + for i := 1; i <= 0xff; i++ { + fanout[i] += fanout[i-1] + } + + // Find out if we will need extra edge table + for i := 0; i < len(hashes); i++ { + v, _ := idx.GetCommitDataByIndex(i) + if len(v.ParentHashes) > 2 { + extraEdgesCount += uint32(len(v.ParentHashes) - 1) + break + } + } + + return +} + +func (e *Encoder) encodeFileHeader(chunkCount int) (err error) { + if _, err = e.Write(commitFileSignature); err == nil { + _, err = e.Write([]byte{1, 1, byte(chunkCount), 0}) + } + return +} + +func (e *Encoder) encodeChunkHeaders(chunkSignatures [][]byte, chunkSizes []uint64) (err error) { + // 8 bytes of file header, 12 bytes for each chunk header and 12 byte for terminator + offset := uint64(8 + len(chunkSignatures)*12 + 12) + for i, signature := range chunkSignatures { + if _, err = e.Write(signature); err == nil { + err = binary.WriteUint64(e, offset) + } + if err != nil { + return + } + offset += chunkSizes[i] + } + if _, err = e.Write(lastSignature); err == nil { + err = binary.WriteUint64(e, offset) + } + return +} + +func (e *Encoder) encodeFanout(fanout []uint32) (err error) { + for i := 0; i <= 0xff; i++ { + if err = binary.WriteUint32(e, fanout[i]); err != nil { + return + } + } + return +} + +func (e *Encoder) encodeOidLookup(hashes []plumbing.Hash) (err error) { + for _, hash := range hashes { + if _, err = e.Write(hash[:]); err != nil { + return err + } + } + return +} + +func (e *Encoder) encodeCommitData(hashes []plumbing.Hash, hashToIndex map[plumbing.Hash]uint32, idx Index) (extraEdges []uint32, err error) { + for _, hash := range hashes { + origIndex, _ := idx.GetIndexByHash(hash) + commitData, _ := idx.GetCommitDataByIndex(origIndex) + if _, err = e.Write(commitData.TreeHash[:]); err != nil { + return + } + + var parent1, parent2 uint32 + if len(commitData.ParentHashes) == 0 { + parent1 = parentNone + parent2 = parentNone + } else if len(commitData.ParentHashes) == 1 { + parent1 = hashToIndex[commitData.ParentHashes[0]] + parent2 = parentNone + } else if len(commitData.ParentHashes) == 2 { + parent1 = hashToIndex[commitData.ParentHashes[0]] + parent2 = hashToIndex[commitData.ParentHashes[1]] + } else if len(commitData.ParentHashes) > 2 { + parent1 = hashToIndex[commitData.ParentHashes[0]] + parent2 = uint32(len(extraEdges)) | parentOctopusUsed + for _, parentHash := range commitData.ParentHashes[1:] { + extraEdges = append(extraEdges, hashToIndex[parentHash]) + } + extraEdges[len(extraEdges)-1] |= parentLast + } + + if err = binary.WriteUint32(e, parent1); err == nil { + err = binary.WriteUint32(e, parent2) + } + if err != nil { + return + } + + unixTime := uint64(commitData.When.Unix()) + unixTime |= uint64(commitData.Generation) << 34 + if err = binary.WriteUint64(e, unixTime); err != nil { + return + } + } + return +} + +func (e *Encoder) encodeExtraEdges(extraEdges []uint32) (err error) { + for _, parent := range extraEdges { + if err = binary.WriteUint32(e, parent); err != nil { + return + } + } + return +} + +func (e *Encoder) encodeChecksum() error { + _, err := e.Write(e.hash.Sum(nil)[:20]) + return err +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/file.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/file.go new file mode 100644 index 0000000000..175d279333 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/file.go @@ -0,0 +1,259 @@ +package commitgraph + +import ( + "bytes" + encbin "encoding/binary" + "errors" + "io" + "time" + + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/utils/binary" +) + +var ( + // ErrUnsupportedVersion is returned by OpenFileIndex when the commit graph + // file version is not supported. + ErrUnsupportedVersion = errors.New("Unsupported version") + // ErrUnsupportedHash is returned by OpenFileIndex when the commit graph + // hash function is not supported. Currently only SHA-1 is defined and + // supported + ErrUnsupportedHash = errors.New("Unsupported hash algorithm") + // ErrMalformedCommitGraphFile is returned by OpenFileIndex when the commit + // graph file is corrupted. + ErrMalformedCommitGraphFile = errors.New("Malformed commit graph file") + + commitFileSignature = []byte{'C', 'G', 'P', 'H'} + oidFanoutSignature = []byte{'O', 'I', 'D', 'F'} + oidLookupSignature = []byte{'O', 'I', 'D', 'L'} + commitDataSignature = []byte{'C', 'D', 'A', 'T'} + extraEdgeListSignature = []byte{'E', 'D', 'G', 'E'} + lastSignature = []byte{0, 0, 0, 0} + + parentNone = uint32(0x70000000) + parentOctopusUsed = uint32(0x80000000) + parentOctopusMask = uint32(0x7fffffff) + parentLast = uint32(0x80000000) +) + +type fileIndex struct { + reader io.ReaderAt + fanout [256]int + oidFanoutOffset int64 + oidLookupOffset int64 + commitDataOffset int64 + extraEdgeListOffset int64 +} + +// OpenFileIndex opens a serialized commit graph file in the format described at +// https://github.com/git/git/blob/master/Documentation/technical/commit-graph-format.txt +func OpenFileIndex(reader io.ReaderAt) (Index, error) { + fi := &fileIndex{reader: reader} + + if err := fi.verifyFileHeader(); err != nil { + return nil, err + } + if err := fi.readChunkHeaders(); err != nil { + return nil, err + } + if err := fi.readFanout(); err != nil { + return nil, err + } + + return fi, nil +} + +func (fi *fileIndex) verifyFileHeader() error { + // Verify file signature + var signature = make([]byte, 4) + if _, err := fi.reader.ReadAt(signature, 0); err != nil { + return err + } + if !bytes.Equal(signature, commitFileSignature) { + return ErrMalformedCommitGraphFile + } + + // Read and verify the file header + var header = make([]byte, 4) + if _, err := fi.reader.ReadAt(header, 4); err != nil { + return err + } + if header[0] != 1 { + return ErrUnsupportedVersion + } + if header[1] != 1 { + return ErrUnsupportedHash + } + + return nil +} + +func (fi *fileIndex) readChunkHeaders() error { + var chunkID = make([]byte, 4) + for i := 0; ; i++ { + chunkHeader := io.NewSectionReader(fi.reader, 8+(int64(i)*12), 12) + if _, err := io.ReadAtLeast(chunkHeader, chunkID, 4); err != nil { + return err + } + chunkOffset, err := binary.ReadUint64(chunkHeader) + if err != nil { + return err + } + + if bytes.Equal(chunkID, oidFanoutSignature) { + fi.oidFanoutOffset = int64(chunkOffset) + } else if bytes.Equal(chunkID, oidLookupSignature) { + fi.oidLookupOffset = int64(chunkOffset) + } else if bytes.Equal(chunkID, commitDataSignature) { + fi.commitDataOffset = int64(chunkOffset) + } else if bytes.Equal(chunkID, extraEdgeListSignature) { + fi.extraEdgeListOffset = int64(chunkOffset) + } else if bytes.Equal(chunkID, lastSignature) { + break + } + } + + if fi.oidFanoutOffset <= 0 || fi.oidLookupOffset <= 0 || fi.commitDataOffset <= 0 { + return ErrMalformedCommitGraphFile + } + + return nil +} + +func (fi *fileIndex) readFanout() error { + fanoutReader := io.NewSectionReader(fi.reader, fi.oidFanoutOffset, 256*4) + for i := 0; i < 256; i++ { + fanoutValue, err := binary.ReadUint32(fanoutReader) + if err != nil { + return err + } + if fanoutValue > 0x7fffffff { + return ErrMalformedCommitGraphFile + } + fi.fanout[i] = int(fanoutValue) + } + return nil +} + +func (fi *fileIndex) GetIndexByHash(h plumbing.Hash) (int, error) { + var oid plumbing.Hash + + // Find the hash in the oid lookup table + var low int + if h[0] == 0 { + low = 0 + } else { + low = fi.fanout[h[0]-1] + } + high := fi.fanout[h[0]] + for low < high { + mid := (low + high) >> 1 + offset := fi.oidLookupOffset + int64(mid)*20 + if _, err := fi.reader.ReadAt(oid[:], offset); err != nil { + return 0, err + } + cmp := bytes.Compare(h[:], oid[:]) + if cmp < 0 { + high = mid + } else if cmp == 0 { + return mid, nil + } else { + low = mid + 1 + } + } + + return 0, plumbing.ErrObjectNotFound +} + +func (fi *fileIndex) GetCommitDataByIndex(idx int) (*CommitData, error) { + if idx >= fi.fanout[0xff] { + return nil, plumbing.ErrObjectNotFound + } + + offset := fi.commitDataOffset + int64(idx)*36 + commitDataReader := io.NewSectionReader(fi.reader, offset, 36) + + treeHash, err := binary.ReadHash(commitDataReader) + if err != nil { + return nil, err + } + parent1, err := binary.ReadUint32(commitDataReader) + if err != nil { + return nil, err + } + parent2, err := binary.ReadUint32(commitDataReader) + if err != nil { + return nil, err + } + genAndTime, err := binary.ReadUint64(commitDataReader) + if err != nil { + return nil, err + } + + var parentIndexes []int + if parent2&parentOctopusUsed == parentOctopusUsed { + // Octopus merge + parentIndexes = []int{int(parent1 & parentOctopusMask)} + offset := fi.extraEdgeListOffset + 4*int64(parent2&parentOctopusMask) + buf := make([]byte, 4) + for { + _, err := fi.reader.ReadAt(buf, offset) + if err != nil { + return nil, err + } + + parent := encbin.BigEndian.Uint32(buf) + offset += 4 + parentIndexes = append(parentIndexes, int(parent&parentOctopusMask)) + if parent&parentLast == parentLast { + break + } + } + } else if parent2 != parentNone { + parentIndexes = []int{int(parent1 & parentOctopusMask), int(parent2 & parentOctopusMask)} + } else if parent1 != parentNone { + parentIndexes = []int{int(parent1 & parentOctopusMask)} + } + + parentHashes, err := fi.getHashesFromIndexes(parentIndexes) + if err != nil { + return nil, err + } + + return &CommitData{ + TreeHash: treeHash, + ParentIndexes: parentIndexes, + ParentHashes: parentHashes, + Generation: int(genAndTime >> 34), + When: time.Unix(int64(genAndTime&0x3FFFFFFFF), 0), + }, nil +} + +func (fi *fileIndex) getHashesFromIndexes(indexes []int) ([]plumbing.Hash, error) { + hashes := make([]plumbing.Hash, len(indexes)) + + for i, idx := range indexes { + if idx >= fi.fanout[0xff] { + return nil, ErrMalformedCommitGraphFile + } + + offset := fi.oidLookupOffset + int64(idx)*20 + if _, err := fi.reader.ReadAt(hashes[i][:], offset); err != nil { + return nil, err + } + } + + return hashes, nil +} + +// Hashes returns all the hashes that are available in the index +func (fi *fileIndex) Hashes() []plumbing.Hash { + hashes := make([]plumbing.Hash, fi.fanout[0xff]) + for i := 0; i < int(fi.fanout[0xff]); i++ { + offset := fi.oidLookupOffset + int64(i)*20 + if n, err := fi.reader.ReadAt(hashes[i][:], offset); err != nil || n < 20 { + return nil + } + } + return hashes +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/memory.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/memory.go new file mode 100644 index 0000000000..a4a96e9612 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph/memory.go @@ -0,0 +1,72 @@ +package commitgraph + +import ( + "gopkg.in/src-d/go-git.v4/plumbing" +) + +// MemoryIndex provides a way to build the commit-graph in memory +// for later encoding to file. +type MemoryIndex struct { + commitData []*CommitData + indexMap map[plumbing.Hash]int +} + +// NewMemoryIndex creates in-memory commit graph representation +func NewMemoryIndex() *MemoryIndex { + return &MemoryIndex{ + indexMap: make(map[plumbing.Hash]int), + } +} + +// GetIndexByHash gets the index in the commit graph from commit hash, if available +func (mi *MemoryIndex) GetIndexByHash(h plumbing.Hash) (int, error) { + i, ok := mi.indexMap[h] + if ok { + return i, nil + } + + return 0, plumbing.ErrObjectNotFound +} + +// GetCommitDataByIndex gets the commit node from the commit graph using index +// obtained from child node, if available +func (mi *MemoryIndex) GetCommitDataByIndex(i int) (*CommitData, error) { + if int(i) >= len(mi.commitData) { + return nil, plumbing.ErrObjectNotFound + } + + commitData := mi.commitData[i] + + // Map parent hashes to parent indexes + if commitData.ParentIndexes == nil { + parentIndexes := make([]int, len(commitData.ParentHashes)) + for i, parentHash := range commitData.ParentHashes { + var err error + if parentIndexes[i], err = mi.GetIndexByHash(parentHash); err != nil { + return nil, err + } + } + commitData.ParentIndexes = parentIndexes + } + + return commitData, nil +} + +// Hashes returns all the hashes that are available in the index +func (mi *MemoryIndex) Hashes() []plumbing.Hash { + hashes := make([]plumbing.Hash, 0, len(mi.indexMap)) + for k := range mi.indexMap { + hashes = append(hashes, k) + } + return hashes +} + +// Add adds new node to the memory index +func (mi *MemoryIndex) Add(hash plumbing.Hash, commitData *CommitData) { + // The parent indexes are calculated lazily in GetNodeByIndex + // which allows adding nodes out of order as long as all parents + // are eventually resolved + commitData.ParentIndexes = nil + mi.indexMap[hash] = len(mi.commitData) + mi.commitData = append(mi.commitData, commitData) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode.go new file mode 100644 index 0000000000..e218d3210b --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode.go @@ -0,0 +1,98 @@ +package commitgraph + +import ( + "io" + "time" + + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/object" + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +// CommitNode is generic interface encapsulating a lightweight commit object retrieved +// from CommitNodeIndex +type CommitNode interface { + // ID returns the Commit object id referenced by the commit graph node. + ID() plumbing.Hash + // Tree returns the Tree referenced by the commit graph node. + Tree() (*object.Tree, error) + // CommitTime returns the Commiter.When time of the Commit referenced by the commit graph node. + CommitTime() time.Time + // NumParents returns the number of parents in a commit. + NumParents() int + // ParentNodes return a CommitNodeIter for parents of specified node. + ParentNodes() CommitNodeIter + // ParentNode returns the ith parent of a commit. + ParentNode(i int) (CommitNode, error) + // ParentHashes returns hashes of the parent commits for a specified node + ParentHashes() []plumbing.Hash + // Generation returns the generation of the commit for reachability analysis. + // Objects with newer generation are not reachable from objects of older generation. + Generation() uint64 + // Commit returns the full commit object from the node + Commit() (*object.Commit, error) +} + +// CommitNodeIndex is generic interface encapsulating an index of CommitNode objects +type CommitNodeIndex interface { + // Get returns a commit node from a commit hash + Get(hash plumbing.Hash) (CommitNode, error) +} + +// CommitNodeIter is a generic closable interface for iterating over commit nodes. +type CommitNodeIter interface { + Next() (CommitNode, error) + ForEach(func(CommitNode) error) error + Close() +} + +// parentCommitNodeIter provides an iterator for parent commits from associated CommitNodeIndex. +type parentCommitNodeIter struct { + node CommitNode + i int +} + +func newParentgraphCommitNodeIter(node CommitNode) CommitNodeIter { + return &parentCommitNodeIter{node, 0} +} + +// Next moves the iterator to the next commit and returns a pointer to it. If +// there are no more commits, it returns io.EOF. +func (iter *parentCommitNodeIter) Next() (CommitNode, error) { + obj, err := iter.node.ParentNode(iter.i) + if err == object.ErrParentNotFound { + return nil, io.EOF + } + if err == nil { + iter.i++ + } + + return obj, err +} + +// ForEach call the cb function for each commit contained on this iter until +// an error appends or the end of the iter is reached. If ErrStop is sent +// the iteration is stopped but no error is returned. The iterator is closed. +func (iter *parentCommitNodeIter) ForEach(cb func(CommitNode) error) error { + for { + obj, err := iter.Next() + if err != nil { + if err == io.EOF { + return nil + } + + return err + } + + if err := cb(obj); err != nil { + if err == storer.ErrStop { + return nil + } + + return err + } + } +} + +func (iter *parentCommitNodeIter) Close() { +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_graph.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_graph.go new file mode 100644 index 0000000000..bd54e18886 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_graph.go @@ -0,0 +1,131 @@ +package commitgraph + +import ( + "fmt" + "time" + + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph" + "gopkg.in/src-d/go-git.v4/plumbing/object" + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +// graphCommitNode is a reduced representation of Commit as presented in the commit +// graph file (commitgraph.Node). It is merely useful as an optimization for walking +// the commit graphs. +// +// graphCommitNode implements the CommitNode interface. +type graphCommitNode struct { + // Hash for the Commit object + hash plumbing.Hash + // Index of the node in the commit graph file + index int + + commitData *commitgraph.CommitData + gci *graphCommitNodeIndex +} + +// graphCommitNodeIndex is an index that can load CommitNode objects from both the commit +// graph files and the object store. +// +// graphCommitNodeIndex implements the CommitNodeIndex interface +type graphCommitNodeIndex struct { + commitGraph commitgraph.Index + s storer.EncodedObjectStorer +} + +// NewGraphCommitNodeIndex returns CommitNodeIndex implementation that uses commit-graph +// files as backing storage and falls back to object storage when necessary +func NewGraphCommitNodeIndex(commitGraph commitgraph.Index, s storer.EncodedObjectStorer) CommitNodeIndex { + return &graphCommitNodeIndex{commitGraph, s} +} + +func (gci *graphCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) { + // Check the commit graph first + parentIndex, err := gci.commitGraph.GetIndexByHash(hash) + if err == nil { + parent, err := gci.commitGraph.GetCommitDataByIndex(parentIndex) + if err != nil { + return nil, err + } + + return &graphCommitNode{ + hash: hash, + index: parentIndex, + commitData: parent, + gci: gci, + }, nil + } + + // Fallback to loading full commit object + commit, err := object.GetCommit(gci.s, hash) + if err != nil { + return nil, err + } + + return &objectCommitNode{ + nodeIndex: gci, + commit: commit, + }, nil +} + +func (c *graphCommitNode) ID() plumbing.Hash { + return c.hash +} + +func (c *graphCommitNode) Tree() (*object.Tree, error) { + return object.GetTree(c.gci.s, c.commitData.TreeHash) +} + +func (c *graphCommitNode) CommitTime() time.Time { + return c.commitData.When +} + +func (c *graphCommitNode) NumParents() int { + return len(c.commitData.ParentIndexes) +} + +func (c *graphCommitNode) ParentNodes() CommitNodeIter { + return newParentgraphCommitNodeIter(c) +} + +func (c *graphCommitNode) ParentNode(i int) (CommitNode, error) { + if i < 0 || i >= len(c.commitData.ParentIndexes) { + return nil, object.ErrParentNotFound + } + + parent, err := c.gci.commitGraph.GetCommitDataByIndex(c.commitData.ParentIndexes[i]) + if err != nil { + return nil, err + } + + return &graphCommitNode{ + hash: c.commitData.ParentHashes[i], + index: c.commitData.ParentIndexes[i], + commitData: parent, + gci: c.gci, + }, nil +} + +func (c *graphCommitNode) ParentHashes() []plumbing.Hash { + return c.commitData.ParentHashes +} + +func (c *graphCommitNode) Generation() uint64 { + // If the commit-graph file was generated with older Git version that + // set the generation to zero for every commit the generation assumption + // is still valid. It is just less useful. + return uint64(c.commitData.Generation) +} + +func (c *graphCommitNode) Commit() (*object.Commit, error) { + return object.GetCommit(c.gci.s, c.hash) +} + +func (c *graphCommitNode) String() string { + return fmt.Sprintf( + "%s %s\nDate: %s", + plumbing.CommitObject, c.ID(), + c.CommitTime().Format(object.DateFormat), + ) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_object.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_object.go new file mode 100644 index 0000000000..2779a54bc7 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_object.go @@ -0,0 +1,90 @@ +package commitgraph + +import ( + "math" + "time" + + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/object" + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +// objectCommitNode is a representation of Commit as presented in the GIT object format. +// +// objectCommitNode implements the CommitNode interface. +type objectCommitNode struct { + nodeIndex CommitNodeIndex + commit *object.Commit +} + +// NewObjectCommitNodeIndex returns CommitNodeIndex implementation that uses +// only object storage to load the nodes +func NewObjectCommitNodeIndex(s storer.EncodedObjectStorer) CommitNodeIndex { + return &objectCommitNodeIndex{s} +} + +func (oci *objectCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) { + commit, err := object.GetCommit(oci.s, hash) + if err != nil { + return nil, err + } + + return &objectCommitNode{ + nodeIndex: oci, + commit: commit, + }, nil +} + +// objectCommitNodeIndex is an index that can load CommitNode objects only from the +// object store. +// +// objectCommitNodeIndex implements the CommitNodeIndex interface +type objectCommitNodeIndex struct { + s storer.EncodedObjectStorer +} + +func (c *objectCommitNode) CommitTime() time.Time { + return c.commit.Committer.When +} + +func (c *objectCommitNode) ID() plumbing.Hash { + return c.commit.ID() +} + +func (c *objectCommitNode) Tree() (*object.Tree, error) { + return c.commit.Tree() +} + +func (c *objectCommitNode) NumParents() int { + return c.commit.NumParents() +} + +func (c *objectCommitNode) ParentNodes() CommitNodeIter { + return newParentgraphCommitNodeIter(c) +} + +func (c *objectCommitNode) ParentNode(i int) (CommitNode, error) { + if i < 0 || i >= len(c.commit.ParentHashes) { + return nil, object.ErrParentNotFound + } + + // Note: It's necessary to go through CommitNodeIndex here to ensure + // that if the commit-graph file covers only part of the history we + // start using it when that part is reached. + return c.nodeIndex.Get(c.commit.ParentHashes[i]) +} + +func (c *objectCommitNode) ParentHashes() []plumbing.Hash { + return c.commit.ParentHashes +} + +func (c *objectCommitNode) Generation() uint64 { + // Commit nodes representing objects outside of the commit graph can never + // be reached by objects from the commit-graph thus we return the highest + // possible value. + return math.MaxUint64 +} + +func (c *objectCommitNode) Commit() (*object.Commit, error) { + return c.commit, nil +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_walker_ctime.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_walker_ctime.go new file mode 100644 index 0000000000..f6a1b6a4ef --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/commitnode_walker_ctime.go @@ -0,0 +1,105 @@ +package commitgraph + +import ( + "io" + + "github.com/emirpasic/gods/trees/binaryheap" + + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +type commitNodeIteratorByCTime struct { + heap *binaryheap.Heap + seenExternal map[plumbing.Hash]bool + seen map[plumbing.Hash]bool +} + +// NewCommitNodeIterCTime returns a CommitNodeIter that walks the commit history, +// starting at the given commit and visiting its parents while preserving Committer Time order. +// this appears to be the closest order to `git log` +// The given callback will be called for each visited commit. Each commit will +// be visited only once. If the callback returns an error, walking will stop +// and will return the error. Other errors might be returned if the history +// cannot be traversed (e.g. missing objects). Ignore allows to skip some +// commits from being iterated. +func NewCommitNodeIterCTime( + c CommitNode, + seenExternal map[plumbing.Hash]bool, + ignore []plumbing.Hash, +) CommitNodeIter { + seen := make(map[plumbing.Hash]bool) + for _, h := range ignore { + seen[h] = true + } + + heap := binaryheap.NewWith(func(a, b interface{}) int { + if a.(CommitNode).CommitTime().Before(b.(CommitNode).CommitTime()) { + return 1 + } + return -1 + }) + + heap.Push(c) + + return &commitNodeIteratorByCTime{ + heap: heap, + seenExternal: seenExternal, + seen: seen, + } +} + +func (w *commitNodeIteratorByCTime) Next() (CommitNode, error) { + var c CommitNode + for { + cIn, ok := w.heap.Pop() + if !ok { + return nil, io.EOF + } + c = cIn.(CommitNode) + cID := c.ID() + + if w.seen[cID] || w.seenExternal[cID] { + continue + } + + w.seen[cID] = true + + for i, h := range c.ParentHashes() { + if w.seen[h] || w.seenExternal[h] { + continue + } + pc, err := c.ParentNode(i) + if err != nil { + return nil, err + } + w.heap.Push(pc) + } + + return c, nil + } +} + +func (w *commitNodeIteratorByCTime) ForEach(cb func(CommitNode) error) error { + for { + c, err := w.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + + err = cb(c) + if err == storer.ErrStop { + break + } + if err != nil { + return err + } + } + + return nil +} + +func (w *commitNodeIteratorByCTime) Close() {} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/doc.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/doc.go new file mode 100644 index 0000000000..0a55ad5b01 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph/doc.go @@ -0,0 +1,7 @@ +// Package commitgraph provides an interface for efficient traversal over Git +// commit graph either through the regular object storage, or optionally with +// the index stored in commit-graph file (Git 2.18+). +// +// The API and functionality of this package are considered EXPERIMENTAL and is +// not considered stable nor production ready. +package commitgraph diff --git a/vendor/modules.txt b/vendor/modules.txt index fe21d938d3..70dff4c9ef 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -432,7 +432,9 @@ gopkg.in/src-d/go-git.v4/config gopkg.in/src-d/go-git.v4/plumbing gopkg.in/src-d/go-git.v4/plumbing/cache gopkg.in/src-d/go-git.v4/plumbing/filemode +gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph gopkg.in/src-d/go-git.v4/plumbing/object +gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph gopkg.in/src-d/go-git.v4/storage/filesystem gopkg.in/src-d/go-git.v4/internal/revision gopkg.in/src-d/go-git.v4/plumbing/format/gitignore @@ -455,8 +457,8 @@ gopkg.in/src-d/go-git.v4/utils/merkletrie/index gopkg.in/src-d/go-git.v4/utils/merkletrie/noder gopkg.in/src-d/go-git.v4/internal/url gopkg.in/src-d/go-git.v4/plumbing/format/config -gopkg.in/src-d/go-git.v4/plumbing/format/diff gopkg.in/src-d/go-git.v4/utils/binary +gopkg.in/src-d/go-git.v4/plumbing/format/diff gopkg.in/src-d/go-git.v4/plumbing/format/idxfile gopkg.in/src-d/go-git.v4/plumbing/format/objfile gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit From c39df040878c8ea22c14d56efcdc4280da63eb49 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Tue, 2 Jul 2019 12:06:25 +0200 Subject: [PATCH 177/220] Display Github support button (#7343) This need an option to be enabled on repo : https://help.github.com/en/articles/displaying-a-sponsor-button-in-your-repository --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..1447a6ea32 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: gitea From 68ec7b8be9d945ffb83431ba1113997cfc9e648c Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 2 Jul 2019 21:11:24 +0200 Subject: [PATCH 178/220] update dependencies and various tweaks (#7344) - ran `make npm-update` - ran `make js`, fixed new lint issue - ran `make css`, this added back some vendor prefixes - added `engines` property to package.json to specify minimum required Node.js version - added `private` property to package.json to prevent accidential publishing to npm --- package-lock.json | 372 ++++++++++++++++--------------------------- package.json | 8 +- public/css/index.css | 32 ++-- public/js/index.js | 22 ++- 4 files changed, 172 insertions(+), 262 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b3e047693..57e4af164c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -198,9 +198,9 @@ "dev": true }, "@types/node": { - "version": "12.0.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.8.tgz", - "integrity": "sha512-b8bbUOTwzIY3V5vDTY1fIJ+ePKDUBqt2hC2woVGotdQQhG/2Sh62HOKHrT7ab+VerXAcPyAiTEipPu/FsreUtg==", + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", + "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==", "dev": true }, "@types/unist": { @@ -729,9 +729,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000975", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000975.tgz", - "integrity": "sha512-ZsXA9YWQX6ATu5MNg+Vx/cMQ+hM6vBBSqDeJs8ruk9z0ky4yIHML15MoxcFt088ST2uyjgqyUGRJButkptWf0w==", + "version": "1.0.30000979", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000979.tgz", + "integrity": "sha512-gcu45yfq3B7Y+WB05fOMfr0EiSlq+1u+m6rPHyJli/Wy3PVQNGaU7VA4bZE5qw+AU2UVOBR/N5g1bzADUqdvFw==", "dev": true }, "caseless": { @@ -979,16 +979,6 @@ "typedarray": "^0.0.6" } }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", @@ -1197,6 +1187,15 @@ "integrity": "sha512-DCvzSq2UiMsuLnj/9AL484ummEgLtZIcRS7YvtO38QnpX3vqh9nJ8P+zhu8Ja+SmLrBHO2iDbva20jq38qvBkQ==", "dev": true }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1274,9 +1273,9 @@ } }, "electron-to-chromium": { - "version": "1.3.164", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.164.tgz", - "integrity": "sha512-VLlalqUeduN4+fayVtRZvGP2Hl1WrRxlwzh2XVVMJym3IFrQUS29BFQ1GP/BxOJXJI1OFCrJ5BnFEsAe8NHtOg==", + "version": "1.3.183", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.183.tgz", + "integrity": "sha512-WbKCYs7yAFOfpuoa2pK5kbOngriUtlPC+8mcQW5L/686wv04w7hYXfw5ScDrsl9kixFw1SPsALEob5V/gtlDxw==", "dev": true }, "emoji-regex": { @@ -1356,13 +1355,13 @@ "dev": true }, "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz", + "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", + "ajv": "^6.10.0", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", @@ -1370,18 +1369,19 @@ "eslint-scope": "^4.0.3", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", + "espree": "^6.0.0", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", + "glob-parent": "^3.1.0", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", "lodash": "^4.17.11", @@ -1389,7 +1389,6 @@ "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^5.5.1", @@ -1422,9 +1421,9 @@ "dev": true }, "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", + "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", "dev": true, "requires": { "acorn": "^6.0.7", @@ -1752,9 +1751,9 @@ } }, "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "flush-write-stream": { @@ -2498,6 +2497,22 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + } + }, "globjoin": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", @@ -2522,9 +2537,9 @@ } }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", "dev": true }, "graceful-readlink": { @@ -2741,9 +2756,9 @@ } }, "import-fresh": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", - "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -2802,9 +2817,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "ini": { @@ -2814,9 +2829,9 @@ "dev": true }, "inquirer": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", - "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.4.1.tgz", + "integrity": "sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw==", "dev": true, "requires": { "ansi-escapes": "^3.2.0", @@ -3292,6 +3307,14 @@ "parse-json": "^4.0.0", "pify": "^3.0.0", "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "locate-path": { @@ -3583,9 +3606,9 @@ } }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -3688,9 +3711,9 @@ } }, "node-releases": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.23.tgz", - "integrity": "sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w==", + "version": "1.1.24", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.24.tgz", + "integrity": "sha512-wym2jptfuKowMmkZsfCSTsn8qAVo8zm+UiQA6l5dNqUcpfChZSnS/vbbpOeXczf+VdPhutxh+99lWHhdd6xKzg==", "dev": true, "requires": { "semver": "^5.3.0" @@ -3726,16 +3749,6 @@ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", "dev": true }, - "npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", - "dev": true, - "requires": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -3972,12 +3985,6 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -3997,6 +4004,14 @@ "dev": true, "requires": { "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "performance-now": { @@ -4013,9 +4028,9 @@ "dev": true }, "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "posix-character-classes": { @@ -4064,45 +4079,6 @@ "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", "yargs": "^12.0.1" - }, - "dependencies": { - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dev": true, - "requires": { - "path-type": "^3.0.0" - } - }, - "globby": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - } } }, "postcss-html": { @@ -4204,6 +4180,17 @@ "postcss": "^7.0.0" } }, + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, "postcss-syntax": { "version": "0.36.2", "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", @@ -4229,9 +4216,9 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "progress": { @@ -4266,12 +4253,6 @@ "retry": "^0.10.0" } }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -4286,9 +4267,9 @@ "dev": true }, "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz", + "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==", "dev": true, "optional": true }, @@ -4500,12 +4481,12 @@ "dev": true }, "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", "dev": true, "requires": { - "rc": "^1.1.6", + "rc": "^1.2.8", "safe-buffer": "^5.0.1" } }, @@ -4743,9 +4724,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -4786,6 +4767,12 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -5251,15 +5238,6 @@ "fill-range": "^7.0.1" } }, - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dev": true, - "requires": { - "path-type": "^3.0.0" - } - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -5281,36 +5259,6 @@ "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", "dev": true }, - "globby": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "dependencies": { - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - } - } - }, "ignore": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.2.tgz", @@ -5348,23 +5296,6 @@ "picomatch": "^2.0.5" } }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -5681,38 +5612,15 @@ } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "uniq": { @@ -5840,20 +5748,19 @@ "dev": true }, "updates": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/updates/-/updates-8.1.0.tgz", - "integrity": "sha512-YyL4qlce1UrNbPSMnkqjp00u9sUCwDVnHonV61eew13F8/OVazASSokKzYRHs3cqHWnvvxr/cTWa5dszRnDUvw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/updates/-/updates-8.2.0.tgz", + "integrity": "sha512-HgTxeZwpx40My9OLzvXD7MpBHPKAAQM2ergvVjMDgmsLRH1DQXx5hrlQLuDhvO7HcGgBH+/P/y2MPnovpW2hAw==", "dev": true, "requires": { "chalk": "2.4.2", - "escape-string-regexp": "2.0.0", - "find-up": "4.0.0", + "find-up": "4.1.0", "hosted-git-info": "2.7.1", "make-fetch-happen": "4.0.1", "minimist": "1.2.0", - "npm-conf": "1.1.3", - "registry-auth-token": "3.4.0", - "semver": "6.1.1", + "rc": "1.2.8", + "registry-auth-token": "4.0.0", + "semver": "6.1.2", "string-width": "4.1.0", "text-table": "0.2.0" }, @@ -5870,19 +5777,14 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, "find-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.0.0.tgz", - "integrity": "sha512-zoH7ZWPkRdgwYCDVoQTzqjG8JSPANhtvLhh4KVUHyKnaUJJrNeFmWIkTcNuJmR3GLMEmGYEf2S2bjgx26JTF+Q==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "locate-path": "^5.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "is-fullwidth-code-point": { @@ -5915,10 +5817,16 @@ "p-limit": "^2.2.0" } }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "semver": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", - "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", + "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", "dev": true }, "string-width": { diff --git a/package.json b/package.json index b046430e41..059bbdefb3 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,18 @@ { "license": "MIT", + "private": true, + "engines": { + "node": ">=8" + }, "devDependencies": { "autoprefixer": "9.6.0", - "eslint": "5.16.0", + "eslint": "6.0.1", "less": "3.9.0", "less-plugin-clean-css": "1.5.1", "postcss-cli": "6.1.2", "stylelint": "10.1.0", "stylelint-config-standard": "18.3.0", - "updates": "8.1.0" + "updates": "8.2.0" }, "browserslist": [ "> 1%", diff --git a/public/css/index.css b/public/css/index.css index 303cbc4ef6..f4f95ce081 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -786,22 +786,22 @@ footer .ui.left,footer .ui.right{line-height:40px} #avatar-arrow:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px} #avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px} #delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important} -.tab-size-1{-moz-tab-size:1!important;tab-size:1!important} -.tab-size-2{-moz-tab-size:2!important;tab-size:2!important} -.tab-size-3{-moz-tab-size:3!important;tab-size:3!important} -.tab-size-4{-moz-tab-size:4!important;tab-size:4!important} -.tab-size-5{-moz-tab-size:5!important;tab-size:5!important} -.tab-size-6{-moz-tab-size:6!important;tab-size:6!important} -.tab-size-7{-moz-tab-size:7!important;tab-size:7!important} -.tab-size-8{-moz-tab-size:8!important;tab-size:8!important} -.tab-size-9{-moz-tab-size:9!important;tab-size:9!important} -.tab-size-10{-moz-tab-size:10!important;tab-size:10!important} -.tab-size-11{-moz-tab-size:11!important;tab-size:11!important} -.tab-size-12{-moz-tab-size:12!important;tab-size:12!important} -.tab-size-13{-moz-tab-size:13!important;tab-size:13!important} -.tab-size-14{-moz-tab-size:14!important;tab-size:14!important} -.tab-size-15{-moz-tab-size:15!important;tab-size:15!important} -.tab-size-16{-moz-tab-size:16!important;tab-size:16!important} +.tab-size-1{-moz-tab-size:1!important;-o-tab-size:1!important;tab-size:1!important} +.tab-size-2{-moz-tab-size:2!important;-o-tab-size:2!important;tab-size:2!important} +.tab-size-3{-moz-tab-size:3!important;-o-tab-size:3!important;tab-size:3!important} +.tab-size-4{-moz-tab-size:4!important;-o-tab-size:4!important;tab-size:4!important} +.tab-size-5{-moz-tab-size:5!important;-o-tab-size:5!important;tab-size:5!important} +.tab-size-6{-moz-tab-size:6!important;-o-tab-size:6!important;tab-size:6!important} +.tab-size-7{-moz-tab-size:7!important;-o-tab-size:7!important;tab-size:7!important} +.tab-size-8{-moz-tab-size:8!important;-o-tab-size:8!important;tab-size:8!important} +.tab-size-9{-moz-tab-size:9!important;-o-tab-size:9!important;tab-size:9!important} +.tab-size-10{-moz-tab-size:10!important;-o-tab-size:10!important;tab-size:10!important} +.tab-size-11{-moz-tab-size:11!important;-o-tab-size:11!important;tab-size:11!important} +.tab-size-12{-moz-tab-size:12!important;-o-tab-size:12!important;tab-size:12!important} +.tab-size-13{-moz-tab-size:13!important;-o-tab-size:13!important;tab-size:13!important} +.tab-size-14{-moz-tab-size:14!important;-o-tab-size:14!important;tab-size:14!important} +.tab-size-15{-moz-tab-size:15!important;-o-tab-size:15!important;tab-size:15!important} +.tab-size-16{-moz-tab-size:16!important;-o-tab-size:16!important;tab-size:16!important} .stats-table{display:table;width:100%} .stats-table .table-cell{display:table-cell} .stats-table .table-cell.tiny{height:.5em} diff --git a/public/js/index.js b/public/js/index.js index b932ef9590..22e4f9d419 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -396,18 +396,16 @@ function initCommentForm() { hasLabelUpdateAction = $listMenu.data('action') == 'update'; // Update the var if (hasLabelUpdateAction) { var promises = []; - for (var elementId in labels) { - if (labels.hasOwnProperty(elementId)) { - var label = labels[elementId]; - var promise = updateIssuesMeta( - label["update-url"], - label["action"], - label["issue-id"], - elementId - ); - promises.push(promise); - } - } + Object.keys(labels).forEach(function(elementId) { + var label = labels[elementId]; + var promise = updateIssuesMeta( + label["update-url"], + label["action"], + label["issue-id"], + elementId + ); + promises.push(promise); + }); Promise.all(promises).then(reload); } }); From b5aa7f7ceb4ca828f50395e404e19c5ba7679268 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 3 Jul 2019 13:31:29 +0800 Subject: [PATCH 179/220] fix api route (#7346) --- routers/api/v1/api.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 8e7a74eca2..8170b79dd2 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -798,14 +798,14 @@ func RegisterRoutes(m *macaron.Macaron) { Delete(reqToken(), reqOrgMembership(), org.ConcealMember) }) m.Combo("/teams", reqToken(), reqOrgMembership()).Get(org.ListTeams). - Post(bind(api.CreateTeamOption{}), org.CreateTeam) + Post(reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam) m.Group("/hooks", func() { m.Combo("").Get(org.ListHooks). Post(bind(api.CreateHookOption{}), org.CreateHook) m.Combo("/:id").Get(org.GetHook). - Patch(reqOrgOwnership(), bind(api.EditHookOption{}), org.EditHook). - Delete(reqOrgOwnership(), org.DeleteHook) - }, reqToken(), reqOrgMembership()) + Patch(bind(api.EditHookOption{}), org.EditHook). + Delete(org.DeleteHook) + }, reqToken(), reqOrgOwnership()) }, orgAssignment(true)) m.Group("/teams/:teamid", func() { m.Combo("").Get(org.GetTeam). From 49ee9d27718c31d5ab4fe9543fefc90cd40d4405 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Wed, 3 Jul 2019 19:28:48 -0400 Subject: [PATCH 180/220] update contributing to use recent version of drone cli (#7351) fix #7350 --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd3b35030f..82ab83fed5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,7 +71,7 @@ Here's how to run the test suite: - Install the correct version of the drone-cli package. As of this writing, the correct drone-cli version is - [0.8.6](https://0-8-0.docs.drone.io/cli-installation/). + [1.1.0](https://docs.drone.io/cli/install/). - Ensure you have enough free disk space. You will need at least 15-20 Gb of free disk space to hold all of the containers drone creates (a default AWS or GCE disk size won't work -- see From 86750325c76ec18c253fabd4aeed72caca0ee946 Mon Sep 17 00:00:00 2001 From: Cherrg Date: Sat, 6 Jul 2019 17:16:43 +0200 Subject: [PATCH 181/220] workaround broken drone build (#7362) * workaround broken swagger only master brach is not working, latest release seems to work Signed-off-by: Michael Gnehr * make vendor Signed-off-by: Michael Gnehr * Don't export GO111MODULE * set go-swagger to fixed release version mentioned here: https://github.com/go-gitea/gitea/pull/7362#discussion_r300831537 Signed-off-by: Michael Gnehr --- Makefile | 2 +- go.mod | 11 +- go.sum | 60 +- vendor/github.com/dgrijalva/jwt-go/README.md | 31 +- .../dgrijalva/jwt-go/VERSION_HISTORY.md | 13 + vendor/github.com/dgrijalva/jwt-go/ecdsa.go | 1 + vendor/github.com/dgrijalva/jwt-go/hmac.go | 3 +- vendor/github.com/dgrijalva/jwt-go/parser.go | 113 +- vendor/github.com/dgrijalva/jwt-go/rsa.go | 5 +- .../github.com/dgrijalva/jwt-go/rsa_utils.go | 32 + .../golang/protobuf/proto/decode.go | 1 - .../golang/protobuf/proto/deprecated.go | 63 + .../github.com/golang/protobuf/proto/equal.go | 3 +- .../golang/protobuf/proto/extensions.go | 78 +- .../github.com/golang/protobuf/proto/lib.go | 38 +- .../golang/protobuf/proto/message_set.go | 137 +- .../golang/protobuf/proto/pointer_reflect.go | 5 +- .../golang/protobuf/proto/pointer_unsafe.go | 15 +- .../golang/protobuf/proto/properties.go | 31 +- .../golang/protobuf/proto/table_marshal.go | 45 +- .../golang/protobuf/proto/table_unmarshal.go | 74 +- .../client_golang/prometheus/collector.go | 2 +- .../client_golang/prometheus/counter.go | 2 +- .../client_golang/prometheus/desc.go | 4 +- .../client_golang/prometheus/doc.go | 6 +- .../client_golang/prometheus/gauge.go | 2 +- .../client_golang/prometheus/go_collector.go | 89 +- .../client_golang/prometheus/histogram.go | 118 +- .../client_golang/prometheus/http.go | 108 +- .../client_golang/prometheus/labels.go | 21 +- .../prometheus/promhttp/delegator.go | 160 +- .../prometheus/promhttp/delegator_1_8.go | 181 --- .../prometheus/promhttp/delegator_pre_1_8.go | 44 - .../client_golang/prometheus/promhttp/http.go | 105 +- .../prometheus/promhttp/instrument_client.go | 122 ++ .../promhttp/instrument_client_1_8.go | 144 -- .../client_golang/prometheus/registry.go | 50 +- .../client_golang/prometheus/summary.go | 134 +- .../client_golang/prometheus/timer.go | 11 +- .../bitbucket.org/ww/goautoneg/autoneg.go | 6 +- .../prometheus/common/model/metric.go | 1 - .../prometheus/procfs/.golangci.yml | 6 + .../prometheus/procfs/MAINTAINERS.md | 3 +- vendor/github.com/prometheus/procfs/Makefile | 65 +- .../prometheus/procfs/Makefile.common | 272 ++++ .../github.com/prometheus/procfs/buddyinfo.go | 2 +- .../prometheus/procfs/fixtures.ttar | 1428 ++++++++++++++++- vendor/github.com/prometheus/procfs/fs.go | 67 +- vendor/github.com/prometheus/procfs/go.mod | 3 + vendor/github.com/prometheus/procfs/go.sum | 2 + .../prometheus/procfs/internal/fs/fs.go | 52 + .../prometheus/procfs/internal/util/parse.go | 59 - .../procfs/internal/util/sysreadfile_linux.go | 45 - vendor/github.com/prometheus/procfs/ipvs.go | 4 +- vendor/github.com/prometheus/procfs/mdstat.go | 2 +- .../prometheus/procfs/mountstats.go | 10 + .../github.com/prometheus/procfs/net_dev.go | 2 +- .../github.com/prometheus/procfs/nfs/nfs.go | 263 --- .../github.com/prometheus/procfs/nfs/parse.go | 317 ---- .../prometheus/procfs/nfs/parse_nfs.go | 67 - .../prometheus/procfs/nfs/parse_nfsd.go | 89 - vendor/github.com/prometheus/procfs/proc.go | 16 +- .../github.com/prometheus/procfs/proc_psi.go | 110 ++ .../github.com/prometheus/procfs/proc_stat.go | 13 +- vendor/github.com/prometheus/procfs/stat.go | 2 +- vendor/github.com/prometheus/procfs/xfrm.go | 2 +- .../github.com/prometheus/procfs/xfs/parse.go | 330 ---- .../github.com/prometheus/procfs/xfs/xfs.go | 163 -- vendor/gopkg.in/yaml.v2/encode.go | 28 + vendor/modules.txt | 20 +- 70 files changed, 3034 insertions(+), 2479 deletions(-) create mode 100644 vendor/github.com/golang/protobuf/proto/deprecated.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go create mode 100644 vendor/github.com/prometheus/procfs/.golangci.yml create mode 100644 vendor/github.com/prometheus/procfs/Makefile.common create mode 100644 vendor/github.com/prometheus/procfs/go.mod create mode 100644 vendor/github.com/prometheus/procfs/go.sum create mode 100644 vendor/github.com/prometheus/procfs/internal/fs/fs.go delete mode 100644 vendor/github.com/prometheus/procfs/internal/util/parse.go delete mode 100644 vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/nfs.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/parse.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfs.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go create mode 100644 vendor/github.com/prometheus/procfs/proc_psi.go delete mode 100644 vendor/github.com/prometheus/procfs/xfs/parse.go delete mode 100644 vendor/github.com/prometheus/procfs/xfs/xfs.go diff --git a/Makefile b/Makefile index be66cb3ef3..796a0e3b53 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ generate: .PHONY: generate-swagger generate-swagger: @hash swagger > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/go-swagger/go-swagger/cmd/swagger; \ + GO111MODULE="on" $(GO) get -u github.com/go-swagger/go-swagger/cmd/swagger@v0.19.0; \ fi swagger generate spec -o './$(SWAGGER_SPEC)' $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' diff --git a/go.mod b/go.mod index 614f3639f8..22ad85b136 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 // indirect - github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3 github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3 // indirect @@ -28,7 +27,7 @@ require ( github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 - github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect github.com/emirpasic/gods v1.12.0 github.com/etcd-io/bbolt v1.3.2 // indirect @@ -59,7 +58,6 @@ require ( github.com/go-xorm/xorm v0.7.3-0.20190620151208-f1b4f8368459 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 - github.com/gogo/protobuf v1.2.1 // indirect github.com/google/go-cmp v0.3.0 // indirect github.com/google/go-github/v24 v24.0.1 github.com/gorilla/context v1.1.1 @@ -83,7 +81,6 @@ require ( github.com/mattn/go-isatty v0.0.7 github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d // indirect github.com/mattn/go-sqlite3 v1.10.0 - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect @@ -92,10 +89,7 @@ require ( github.com/oliamb/cutter v0.2.2 github.com/philhofer/fwd v1.0.0 // indirect github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e - github.com/prometheus/client_golang v0.9.0 - github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect - github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 // indirect - github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d // indirect + github.com/prometheus/client_golang v0.9.3 github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect @@ -134,6 +128,7 @@ require ( gopkg.in/src-d/go-git.v4 v4.12.0 gopkg.in/stretchr/testify.v1 v1.2.2 // indirect gopkg.in/testfixtures.v2 v2.5.0 + gopkg.in/yaml.v2 v2.2.2 // indirect mvdan.cc/xurls/v2 v2.0.0 strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a xorm.io/builder v0.3.5 diff --git a/go.sum b/go.sum index f34fe7f3ec..80b30fc46e 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 h1:UsHpWO0Elp6NaWVARdZHjiYwkhrspHVEGsyIKPb9OI8= github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34/go.mod h1:T9ezsOHcCrDCgA8aF1Cqr3sSYbO/xgdy8/R/XiIMAhA= github.com/RoaringBitmap/roaring v0.4.7 h1:eGUudvFzvF7Kxh7JjYvXfI1f7l22/2duFby7r5+d4oc= @@ -17,6 +18,8 @@ github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 h1:SSvHGK7iMpeyp github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141/go.mod h1:fw0McLecf/G5NFwddCRmDckU6yovtk1YsgWIoepMbYo= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 h1:4jHLmof+Hba81591gfH5xYA8QXzuvgksxwPNrmjR2BA= github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470/go.mod h1:3I+3V7B6gTBYfdpYgIG2ymALS9H+5VDKUl3lHH7ToM4= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= @@ -25,6 +28,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3 h1:vinCy/rcjbtxWnMiw11CbMKcuyNi+y4L4MbZUpk7m4M= @@ -39,6 +44,7 @@ github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26 h1:NGpwhs9FOwddM github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a h1:k5TuEkqEYCRs8+66WdOkswWOj+L/YbP5ruainvn94wg= github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f h1:REH9VH5ubNR0skLaOxK7TRJeRbE2dDfvaouQo8FsRcA= github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f/go.mod h1:6QaC0vFoKWYDth94dHFNgRT2YkT5FHdQp/Yx15aAAi0= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= @@ -62,8 +68,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 h1:x0uHqLQTSEL9LKic8sWDt3ASkq07ve5ojIIUl5uF64M= github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= -github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac h1:xrQJVwQCGqDvOO7/0+RyIq5J2M3Q4ZF7Ug/BMQtML1E= -github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= @@ -99,6 +106,9 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04M github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76uRMLLlGVyb0hiYbgX1FM5+ur81TJWzIw= github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM= github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw= @@ -121,6 +131,8 @@ github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDA github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-xorm/core v0.6.0 h1:tp6hX+ku4OD9khFZS8VGBDRY3kfVCtelPfmkgCyHxL0= github.com/go-xorm/core v0.6.0/go.mod h1:d8FJ9Br8OGyQl12MCclmYBuBqqxsyeedpXciV5Myih8= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= @@ -131,10 +143,11 @@ github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04Pgtpy github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 h1:EBTlva3AOSb80G3JSwY6ZMdILEZJ1JKuewrbqrNjWuE= github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183/go.mod h1:pX+V62FFmklia2fhP3P4YSY6iJdPO5jIDKFQ5fEd5QE= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= @@ -176,6 +189,7 @@ github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06 github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= @@ -184,20 +198,21 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7cCpiRVEIr1B5ccDxRpbPsWT5JU3if2Di5nE4= github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6 h1:9mszGwKDxHEY2cy+9XxCQKWIfkGPSAEFrcN8ghzyAKg= github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f h1:tCnZKEmDovgV4jmsclh6CuKk9AMzTzyVWfejgkgccVg= github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc h1:WW8B7p7QBnFlqRVv/k6ro/S8Z7tCnYjJHcQNScx9YVs= github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -240,8 +255,10 @@ github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbM github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc h1:z1PgdCCmYYVL0BoJTUgmAq1p7ca8fzYIPsNyfsN3xAU= github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -253,20 +270,28 @@ github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWo github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e h1:ApqncJ84HYN8x8x5WV1T1YWDuPRF/0aXZhr91LnRMCQ= github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= -github.com/prometheus/client_golang v0.9.0 h1:tXuTFVHC03mW0D+Ua1Q2d1EAVqLTuggX50V0VLICCzY= -github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 h1:Cto4X6SVMWRPBkJ/3YHn1iDGDGc/Z+sW+AEMKHMVvN4= -github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkNDhPdWN3REluVa46HQOVuVkjkd2sWnrABNQ= github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff h1:g9ZlAHmkc/h5So+OjNCkZWh+FjuKEOOOoyRkqlGA8+c= @@ -287,6 +312,7 @@ github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1K github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= @@ -294,12 +320,14 @@ github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys= github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 h1:JNEGSiWg6D3lcBCMCBqN3ELniXujt+0QNHLhNnO0w3s= github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2/go.mod h1:mjqs7N0Q6m5HpR7QfXVBZXZWSqTjQLeTujjA/xUp2uw= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= @@ -325,6 +353,7 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190122013713-64072686203f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -336,6 +365,7 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -347,11 +377,16 @@ golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= @@ -366,8 +401,6 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635 h1:2eB4G6bDQDeP69ZXbOKC00S2Kf6TIiRS+DzfKsKeQU0= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a h1:aQmaYPOmKItb96VioBrTlYay5tSNUdKAFEhPCWMeLSM= golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -376,6 +409,7 @@ google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH2 google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8KqxhFwKci30UxHy3HXPTyQ= @@ -415,6 +449,8 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= mvdan.cc/xurls/v2 v2.0.0 h1:r1zSOSNS/kqtpmATyMMMvaZ4/djsesbYz5kr0+qMRWc= mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a h1:8q33ShxKXRwQ7JVd1ZnhIU3hZhwwn0Le+4fTeAackuM= diff --git a/vendor/github.com/dgrijalva/jwt-go/README.md b/vendor/github.com/dgrijalva/jwt-go/README.md index f48365fafb..d358d881b8 100644 --- a/vendor/github.com/dgrijalva/jwt-go/README.md +++ b/vendor/github.com/dgrijalva/jwt-go/README.md @@ -1,11 +1,15 @@ -A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html) +# jwt-go [![Build Status](https://travis-ci.org/dgrijalva/jwt-go.svg?branch=master)](https://travis-ci.org/dgrijalva/jwt-go) +[![GoDoc](https://godoc.org/github.com/dgrijalva/jwt-go?status.svg)](https://godoc.org/github.com/dgrijalva/jwt-go) -**BREAKING CHANGES:*** Version 3.0.0 is here. It includes _a lot_ of changes including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code. +A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html) -**NOTICE:** A vulnerability in JWT was [recently published](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). As this library doesn't force users to validate the `alg` is what they expected, it's possible your usage is effected. There will be an update soon to remedy this, and it will likey require backwards-incompatible changes to the API. In the short term, please make sure your implementation verifies the `alg` is what you expect. +**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3. +**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail. + +**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided. ## What the heck is a JWT? @@ -37,7 +41,7 @@ Here's an example of an extension that integrates with the Google App Engine sig ## Compliance -This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences: +This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences: * In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key. @@ -47,7 +51,10 @@ This library is considered production ready. Feedback and feature requests are This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases). -While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v2`. It will do the right thing WRT semantic versioning. +While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`. It will do the right thing WRT semantic versioning. + +**BREAKING CHANGES:*** +* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code. ## Usage Tips @@ -68,18 +75,26 @@ Symmetric signing methods, such as HSA, use only a single secret. This is probab Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification. +### Signing Methods and Key Types + +Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones: + +* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation +* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation +* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation + ### JWT and OAuth It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication. Without going too far down the rabbit hole, here's a description of the interaction of these technologies: -* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth. +* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth. * OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token. * Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL. - + ## More Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go). -The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in to documentation. +The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation. diff --git a/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md b/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md index b605b45093..6370298313 100644 --- a/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md +++ b/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md @@ -1,5 +1,18 @@ ## `jwt-go` Version History +#### 3.2.0 + +* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation +* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate +* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before. +* Deprecated `ParseFromRequestWithClaims` to simplify API in the future. + +#### 3.1.0 + +* Improvements to `jwt` command line tool +* Added `SkipClaimsValidation` option to `Parser` +* Documentation updates + #### 3.0.0 * **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code diff --git a/vendor/github.com/dgrijalva/jwt-go/ecdsa.go b/vendor/github.com/dgrijalva/jwt-go/ecdsa.go index 2f59a22236..f977381240 100644 --- a/vendor/github.com/dgrijalva/jwt-go/ecdsa.go +++ b/vendor/github.com/dgrijalva/jwt-go/ecdsa.go @@ -14,6 +14,7 @@ var ( ) // Implements the ECDSA family of signing methods signing methods +// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification type SigningMethodECDSA struct { Name string Hash crypto.Hash diff --git a/vendor/github.com/dgrijalva/jwt-go/hmac.go b/vendor/github.com/dgrijalva/jwt-go/hmac.go index c229919254..addbe5d401 100644 --- a/vendor/github.com/dgrijalva/jwt-go/hmac.go +++ b/vendor/github.com/dgrijalva/jwt-go/hmac.go @@ -7,6 +7,7 @@ import ( ) // Implements the HMAC-SHA family of signing methods signing methods +// Expects key type of []byte for both signing and validation type SigningMethodHMAC struct { Name string Hash crypto.Hash @@ -90,5 +91,5 @@ func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, return EncodeSegment(hasher.Sum(nil)), nil } - return "", ErrInvalidKey + return "", ErrInvalidKeyType } diff --git a/vendor/github.com/dgrijalva/jwt-go/parser.go b/vendor/github.com/dgrijalva/jwt-go/parser.go index 7bf1c4ea08..d6901d9adb 100644 --- a/vendor/github.com/dgrijalva/jwt-go/parser.go +++ b/vendor/github.com/dgrijalva/jwt-go/parser.go @@ -21,55 +21,9 @@ func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { } func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { - parts := strings.Split(tokenString, ".") - if len(parts) != 3 { - return nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed) - } - - var err error - token := &Token{Raw: tokenString} - - // parse Header - var headerBytes []byte - if headerBytes, err = DecodeSegment(parts[0]); err != nil { - if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") { - return token, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed) - } - return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - if err = json.Unmarshal(headerBytes, &token.Header); err != nil { - return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - - // parse Claims - var claimBytes []byte - token.Claims = claims - - if claimBytes, err = DecodeSegment(parts[1]); err != nil { - return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) - if p.UseJSONNumber { - dec.UseNumber() - } - // JSON Decode. Special case for map type to avoid weird pointer behavior - if c, ok := token.Claims.(MapClaims); ok { - err = dec.Decode(&c) - } else { - err = dec.Decode(&claims) - } - // Handle decode error + token, parts, err := p.ParseUnverified(tokenString, claims) if err != nil { - return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - - // Lookup signature method - if method, ok := token.Header["alg"].(string); ok { - if token.Method = GetSigningMethod(method); token.Method == nil { - return token, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable) - } - } else { - return token, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable) + return token, err } // Verify signing method is in the required set @@ -96,6 +50,9 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf } if key, err = keyFunc(token); err != nil { // keyFunc returned an error + if ve, ok := err.(*ValidationError); ok { + return token, ve + } return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable} } @@ -129,3 +86,63 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf return token, vErr } + +// WARNING: Don't use this method unless you know what you're doing +// +// This method parses the token but doesn't validate the signature. It's only +// ever useful in cases where you know the signature is valid (because it has +// been checked previously in the stack) and you want to extract values from +// it. +func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) { + parts = strings.Split(tokenString, ".") + if len(parts) != 3 { + return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed) + } + + token = &Token{Raw: tokenString} + + // parse Header + var headerBytes []byte + if headerBytes, err = DecodeSegment(parts[0]); err != nil { + if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") { + return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed) + } + return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} + } + if err = json.Unmarshal(headerBytes, &token.Header); err != nil { + return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} + } + + // parse Claims + var claimBytes []byte + token.Claims = claims + + if claimBytes, err = DecodeSegment(parts[1]); err != nil { + return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} + } + dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) + if p.UseJSONNumber { + dec.UseNumber() + } + // JSON Decode. Special case for map type to avoid weird pointer behavior + if c, ok := token.Claims.(MapClaims); ok { + err = dec.Decode(&c) + } else { + err = dec.Decode(&claims) + } + // Handle decode error + if err != nil { + return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} + } + + // Lookup signature method + if method, ok := token.Header["alg"].(string); ok { + if token.Method = GetSigningMethod(method); token.Method == nil { + return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable) + } + } else { + return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable) + } + + return token, parts, nil +} diff --git a/vendor/github.com/dgrijalva/jwt-go/rsa.go b/vendor/github.com/dgrijalva/jwt-go/rsa.go index 0ae0b1984e..e4caf1ca4a 100644 --- a/vendor/github.com/dgrijalva/jwt-go/rsa.go +++ b/vendor/github.com/dgrijalva/jwt-go/rsa.go @@ -7,6 +7,7 @@ import ( ) // Implements the RSA family of signing methods signing methods +// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation type SigningMethodRSA struct { Name string Hash crypto.Hash @@ -44,7 +45,7 @@ func (m *SigningMethodRSA) Alg() string { } // Implements the Verify method from SigningMethod -// For this signing method, must be an rsa.PublicKey structure. +// For this signing method, must be an *rsa.PublicKey structure. func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error { var err error @@ -73,7 +74,7 @@ func (m *SigningMethodRSA) Verify(signingString, signature string, key interface } // Implements the Sign method from SigningMethod -// For this signing method, must be an rsa.PrivateKey structure. +// For this signing method, must be an *rsa.PrivateKey structure. func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) { var rsaKey *rsa.PrivateKey var ok bool diff --git a/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go b/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go index 213a90dbbf..a5ababf956 100644 --- a/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go +++ b/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go @@ -39,6 +39,38 @@ func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) { return pkey, nil } +// Parse PEM encoded PKCS1 or PKCS8 private key protected with password +func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) { + var err error + + // Parse PEM block + var block *pem.Block + if block, _ = pem.Decode(key); block == nil { + return nil, ErrKeyMustBePEMEncoded + } + + var parsedKey interface{} + + var blockDecrypted []byte + if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil { + return nil, err + } + + if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil { + if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil { + return nil, err + } + } + + var pkey *rsa.PrivateKey + var ok bool + if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok { + return nil, ErrNotRSAPrivateKey + } + + return pkey, nil +} + // Parse PEM encoded PKCS1 or PKCS8 public key func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { var err error diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go index d9aa3c42d6..63b0f08bef 100644 --- a/vendor/github.com/golang/protobuf/proto/decode.go +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -186,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) { if b&0x80 == 0 { goto done } - // x -= 0x80 << 63 // Always zero. return 0, errOverflow diff --git a/vendor/github.com/golang/protobuf/proto/deprecated.go b/vendor/github.com/golang/protobuf/proto/deprecated.go new file mode 100644 index 0000000000..35b882c09a --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/deprecated.go @@ -0,0 +1,63 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import "errors" + +// Deprecated: do not use. +type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } + +// Deprecated: do not use. +func GetStats() Stats { return Stats{} } + +// Deprecated: do not use. +func MarshalMessageSet(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSet([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func MarshalMessageSetJSON(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSetJSON([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func RegisterMessageSetType(Message, int32, string) {} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go index d4db5a1c14..f9b6e41b3c 100644 --- a/vendor/github.com/golang/protobuf/proto/equal.go +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -246,7 +246,8 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { return false } - m1, m2 := e1.value, e2.value + m1 := extensionAsLegacyType(e1.value) + m2 := extensionAsLegacyType(e2.value) if m1 == nil && m2 == nil { // Both have only encoded form. diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go index 816a3b9d6c..fa88add30a 100644 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -185,9 +185,25 @@ type Extension struct { // extension will have only enc set. When such an extension is // accessed using GetExtension (or GetExtensions) desc and value // will be set. - desc *ExtensionDesc + desc *ExtensionDesc + + // value is a concrete value for the extension field. Let the type of + // desc.ExtensionType be the "API type" and the type of Extension.value + // be the "storage type". The API type and storage type are the same except: + // * For scalars (except []byte), the API type uses *T, + // while the storage type uses T. + // * For repeated fields, the API type uses []T, while the storage type + // uses *[]T. + // + // The reason for the divergence is so that the storage type more naturally + // matches what is expected of when retrieving the values through the + // protobuf reflection APIs. + // + // The value may only be populated if desc is also populated. value interface{} - enc []byte + + // enc is the raw bytes for the extension field. + enc []byte } // SetRawExtension is for testing only. @@ -334,7 +350,7 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { // descriptors with the same field number. return nil, errors.New("proto: descriptor conflict") } - return e.value, nil + return extensionAsLegacyType(e.value), nil } if extension.ExtensionType == nil { @@ -349,11 +365,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { // Remember the decoded version and drop the encoded version. // That way it is safe to mutate what we return. - e.value = v + e.value = extensionAsStorageType(v) e.desc = extension e.enc = nil emap[extension.Field] = e - return e.value, nil + return extensionAsLegacyType(e.value), nil } // defaultExtensionValue returns the default value for extension. @@ -488,7 +504,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error } typ := reflect.TypeOf(extension.ExtensionType) if typ != reflect.TypeOf(value) { - return errors.New("proto: bad extension value type") + return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) } // nil extension values need to be caught early, because the // encoder can't distinguish an ErrNil due to a nil extension @@ -500,7 +516,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error } extmap := epb.extensionsWrite() - extmap[extension.Field] = Extension{desc: extension, value: value} + extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)} return nil } @@ -541,3 +557,51 @@ func RegisterExtension(desc *ExtensionDesc) { func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { return extensionMaps[reflect.TypeOf(pb).Elem()] } + +// extensionAsLegacyType converts an value in the storage type as the API type. +// See Extension.value. +func extensionAsLegacyType(v interface{}) interface{} { + switch rv := reflect.ValueOf(v); rv.Kind() { + case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: + // Represent primitive types as a pointer to the value. + rv2 := reflect.New(rv.Type()) + rv2.Elem().Set(rv) + v = rv2.Interface() + case reflect.Ptr: + // Represent slice types as the value itself. + switch rv.Type().Elem().Kind() { + case reflect.Slice: + if rv.IsNil() { + v = reflect.Zero(rv.Type().Elem()).Interface() + } else { + v = rv.Elem().Interface() + } + } + } + return v +} + +// extensionAsStorageType converts an value in the API type as the storage type. +// See Extension.value. +func extensionAsStorageType(v interface{}) interface{} { + switch rv := reflect.ValueOf(v); rv.Kind() { + case reflect.Ptr: + // Represent slice types as the value itself. + switch rv.Type().Elem().Kind() { + case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: + if rv.IsNil() { + v = reflect.Zero(rv.Type().Elem()).Interface() + } else { + v = rv.Elem().Interface() + } + } + case reflect.Slice: + // Represent slice types as a pointer to the value. + if rv.Type().Elem().Kind() != reflect.Uint8 { + rv2 := reflect.New(rv.Type()) + rv2.Elem().Set(rv) + v = rv2.Interface() + } + } + return v +} diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go index 75565cc6dc..fdd328bb7f 100644 --- a/vendor/github.com/golang/protobuf/proto/lib.go +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -341,26 +341,6 @@ type Message interface { ProtoMessage() } -// Stats records allocation details about the protocol buffer encoders -// and decoders. Useful for tuning the library itself. -type Stats struct { - Emalloc uint64 // mallocs in encode - Dmalloc uint64 // mallocs in decode - Encode uint64 // number of encodes - Decode uint64 // number of decodes - Chit uint64 // number of cache hits - Cmiss uint64 // number of cache misses - Size uint64 // number of sizes -} - -// Set to true to enable stats collection. -const collectStats = false - -var stats Stats - -// GetStats returns a copy of the global Stats structure. -func GetStats() Stats { return stats } - // A Buffer is a buffer manager for marshaling and unmarshaling // protocol buffers. It may be reused between invocations to // reduce memory usage. It is not necessary to use a Buffer; @@ -960,13 +940,19 @@ func isProto3Zero(v reflect.Value) bool { return false } -// ProtoPackageIsVersion2 is referenced from generated protocol buffer files -// to assert that that code is compatible with this version of the proto package. -const ProtoPackageIsVersion2 = true +const ( + // ProtoPackageIsVersion3 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + ProtoPackageIsVersion3 = true -// ProtoPackageIsVersion1 is referenced from generated protocol buffer files -// to assert that that code is compatible with this version of the proto package. -const ProtoPackageIsVersion1 = true + // ProtoPackageIsVersion2 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + ProtoPackageIsVersion2 = true + + // ProtoPackageIsVersion1 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + ProtoPackageIsVersion1 = true +) // InternalMessageInfo is a type used internally by generated .pb.go files. // This type is not intended to be used by non-generated code. diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go index 3b6ca41d5e..f48a756761 100644 --- a/vendor/github.com/golang/protobuf/proto/message_set.go +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -36,13 +36,7 @@ package proto */ import ( - "bytes" - "encoding/json" "errors" - "fmt" - "reflect" - "sort" - "sync" ) // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. @@ -145,46 +139,9 @@ func skipVarint(buf []byte) []byte { return buf[i+1:] } -// MarshalMessageSet encodes the extension map represented by m in the message set wire format. -// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSet(exts interface{}) ([]byte, error) { - return marshalMessageSet(exts, false) -} - -// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal. -func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) { - switch exts := exts.(type) { - case *XXX_InternalExtensions: - var u marshalInfo - siz := u.sizeMessageSet(exts) - b := make([]byte, 0, siz) - return u.appendMessageSet(b, exts, deterministic) - - case map[int32]Extension: - // This is an old-style extension map. - // Wrap it in a new-style XXX_InternalExtensions. - ie := XXX_InternalExtensions{ - p: &struct { - mu sync.Mutex - extensionMap map[int32]Extension - }{ - extensionMap: exts, - }, - } - - var u marshalInfo - siz := u.sizeMessageSet(&ie) - b := make([]byte, 0, siz) - return u.appendMessageSet(b, &ie, deterministic) - - default: - return nil, errors.New("proto: not an extension map") - } -} - -// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSet(buf []byte, exts interface{}) error { +func unmarshalMessageSet(buf []byte, exts interface{}) error { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: @@ -222,93 +179,3 @@ func UnmarshalMessageSet(buf []byte, exts interface{}) error { } return nil } - -// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. -// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - var mu sync.Locker - m, mu = exts.extensionsRead() - if m != nil { - // Keep the extensions map locked until we're done marshaling to prevent - // races between marshaling and unmarshaling the lazily-{en,de}coded - // values. - mu.Lock() - defer mu.Unlock() - } - case map[int32]Extension: - m = exts - default: - return nil, errors.New("proto: not an extension map") - } - var b bytes.Buffer - b.WriteByte('{') - - // Process the map in key order for deterministic output. - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) // int32Slice defined in text.go - - for i, id := range ids { - ext := m[id] - msd, ok := messageSetMap[id] - if !ok { - // Unknown type; we can't render it, so skip it. - continue - } - - if i > 0 && b.Len() > 1 { - b.WriteByte(',') - } - - fmt.Fprintf(&b, `"[%s]":`, msd.name) - - x := ext.value - if x == nil { - x = reflect.New(msd.t.Elem()).Interface() - if err := Unmarshal(ext.enc, x.(Message)); err != nil { - return nil, err - } - } - d, err := json.Marshal(x) - if err != nil { - return nil, err - } - b.Write(d) - } - b.WriteByte('}') - return b.Bytes(), nil -} - -// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. -// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { - // Common-case fast path. - if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { - return nil - } - - // This is fairly tricky, and it's not clear that it is needed. - return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") -} - -// A global registry of types that can be used in a MessageSet. - -var messageSetMap = make(map[int32]messageSetDesc) - -type messageSetDesc struct { - t reflect.Type // pointer to struct - name string -} - -// RegisterMessageSetType is called from the generated code. -func RegisterMessageSetType(m Message, fieldNum int32, name string) { - messageSetMap[fieldNum] = messageSetDesc{ - t: reflect.TypeOf(m), - name: name, - } -} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go index b6cad90834..94fa9194a8 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -79,10 +79,13 @@ func toPointer(i *Message) pointer { // toAddrPointer converts an interface to a pointer that points to // the interface data. -func toAddrPointer(i *interface{}, isptr bool) pointer { +func toAddrPointer(i *interface{}, isptr, deref bool) pointer { v := reflect.ValueOf(*i) u := reflect.New(v.Type()) u.Elem().Set(v) + if deref { + u = u.Elem() + } return pointer{v: u} } diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go index d55a335d94..dbfffe071b 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -85,16 +85,21 @@ func toPointer(i *Message) pointer { // toAddrPointer converts an interface to a pointer that points to // the interface data. -func toAddrPointer(i *interface{}, isptr bool) pointer { +func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) { // Super-tricky - read or get the address of data word of interface value. if isptr { // The interface is of pointer type, thus it is a direct interface. // The data word is the pointer data itself. We take its address. - return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} + p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} + } else { + // The interface is not of pointer type. The data word is the pointer + // to the data. + p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} } - // The interface is not of pointer type. The data word is the pointer - // to the data. - return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} + if deref { + p.p = *(*unsafe.Pointer)(p.p) + } + return p } // valToPointer converts v to a pointer. v must be of pointer type. diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go index 50b99b83a8..79668ff5c5 100644 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -334,9 +334,6 @@ func GetProperties(t reflect.Type) *StructProperties { sprop, ok := propertiesMap[t] propertiesMu.RUnlock() if ok { - if collectStats { - stats.Chit++ - } return sprop } @@ -346,17 +343,20 @@ func GetProperties(t reflect.Type) *StructProperties { return sprop } +type ( + oneofFuncsIface interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + oneofWrappersIface interface { + XXX_OneofWrappers() []interface{} + } +) + // getPropertiesLocked requires that propertiesMu is held. func getPropertiesLocked(t reflect.Type) *StructProperties { if prop, ok := propertiesMap[t]; ok { - if collectStats { - stats.Chit++ - } return prop } - if collectStats { - stats.Cmiss++ - } prop := new(StructProperties) // in case of recursive protos, fill this in now. @@ -391,13 +391,14 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { // Re-order prop.order. sort.Sort(prop) - type oneofMessage interface { - XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + var oots []interface{} + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oots = m.XXX_OneofFuncs() + case oneofWrappersIface: + oots = m.XXX_OneofWrappers() } - if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { - var oots []interface{} - _, _, _, oots = om.XXX_OneofFuncs() - + if len(oots) > 0 { // Interpret oneof metadata. prop.OneofTypes = make(map[string]*OneofProperties) for _, oot := range oots { diff --git a/vendor/github.com/golang/protobuf/proto/table_marshal.go b/vendor/github.com/golang/protobuf/proto/table_marshal.go index b16794496f..5cb11fa955 100644 --- a/vendor/github.com/golang/protobuf/proto/table_marshal.go +++ b/vendor/github.com/golang/protobuf/proto/table_marshal.go @@ -87,6 +87,7 @@ type marshalElemInfo struct { sizer sizer marshaler marshaler isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) + deref bool // dereference the pointer before operating on it; implies isptr } var ( @@ -320,8 +321,11 @@ func (u *marshalInfo) computeMarshalInfo() { // get oneof implementers var oneofImplementers []interface{} - if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: _, _, _, oneofImplementers = m.XXX_OneofFuncs() + case oneofWrappersIface: + oneofImplementers = m.XXX_OneofWrappers() } n := t.NumField() @@ -407,13 +411,22 @@ func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo { panic("tag is not an integer") } wt := wiretype(tags[0]) + if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct { + t = t.Elem() + } sizer, marshaler := typeMarshaler(t, tags, false, false) + var deref bool + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + t = reflect.PtrTo(t) + deref = true + } e = &marshalElemInfo{ wiretag: uint64(tag)<<3 | wt, tagsize: SizeVarint(uint64(tag) << 3), sizer: sizer, marshaler: marshaler, isptr: t.Kind() == reflect.Ptr, + deref: deref, } // update cache @@ -448,7 +461,7 @@ func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { fi.field = toField(f) - fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. + fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. fi.isPointer = true fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) @@ -476,10 +489,6 @@ func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofI } } -type oneofMessage interface { - XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) -} - // wiretype returns the wire encoding of the type. func wiretype(encoding string) uint64 { switch encoding { @@ -2310,8 +2319,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { for _, k := range m.MapKeys() { ki := k.Interface() vi := m.MapIndex(k).Interface() - kaddr := toAddrPointer(&ki, false) // pointer to key - vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + kaddr := toAddrPointer(&ki, false, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) n += siz + SizeVarint(uint64(siz)) + tagsize } @@ -2329,8 +2338,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { for _, k := range keys { ki := k.Interface() vi := m.MapIndex(k).Interface() - kaddr := toAddrPointer(&ki, false) // pointer to key - vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + kaddr := toAddrPointer(&ki, false, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value b = appendVarint(b, tag) siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) b = appendVarint(b, uint64(siz)) @@ -2399,7 +2408,7 @@ func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int { // the last time this function was called. ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) n += ei.sizer(p, ei.tagsize) } mu.Unlock() @@ -2434,7 +2443,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) b, err = ei.marshaler(b, p, ei.wiretag, deterministic) if !nerr.Merge(err) { return b, err @@ -2465,7 +2474,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) b, err = ei.marshaler(b, p, ei.wiretag, deterministic) if !nerr.Merge(err) { return b, err @@ -2510,7 +2519,7 @@ func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int { ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) n += ei.sizer(p, 1) // message, tag = 3 (size=1) } mu.Unlock() @@ -2553,7 +2562,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) if !nerr.Merge(err) { return b, err @@ -2591,7 +2600,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) b = append(b, 1<<3|WireEndGroup) if !nerr.Merge(err) { @@ -2621,7 +2630,7 @@ func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int { ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) n += ei.sizer(p, ei.tagsize) } return n @@ -2656,7 +2665,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ ei := u.getExtElemInfo(e.desc) v := e.value - p := toAddrPointer(&v, ei.isptr) + p := toAddrPointer(&v, ei.isptr, ei.deref) b, err = ei.marshaler(b, p, ei.wiretag, deterministic) if !nerr.Merge(err) { return b, err diff --git a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go index ebf1caa56a..acee2fc529 100644 --- a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go +++ b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go @@ -136,7 +136,7 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error { u.computeUnmarshalInfo() } if u.isMessageSet { - return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions()) + return unmarshalMessageSet(b, m.offset(u.extensions).toExtensions()) } var reqMask uint64 // bitmask of required fields we've seen. var errLater error @@ -362,46 +362,48 @@ func (u *unmarshalInfo) computeUnmarshalInfo() { } // Find any types associated with oneof fields. - // TODO: XXX_OneofFuncs returns more info than we need. Get rid of some of it? - fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("XXX_OneofFuncs") - if fn.IsValid() { - res := fn.Call(nil)[3] // last return value from XXX_OneofFuncs: []interface{} - for i := res.Len() - 1; i >= 0; i-- { - v := res.Index(i) // interface{} - tptr := reflect.ValueOf(v.Interface()).Type() // *Msg_X - typ := tptr.Elem() // Msg_X + var oneofImplementers []interface{} + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oneofImplementers = m.XXX_OneofFuncs() + case oneofWrappersIface: + oneofImplementers = m.XXX_OneofWrappers() + } + for _, v := range oneofImplementers { + tptr := reflect.TypeOf(v) // *Msg_X + typ := tptr.Elem() // Msg_X - f := typ.Field(0) // oneof implementers have one field - baseUnmarshal := fieldUnmarshaler(&f) - tags := strings.Split(f.Tag.Get("protobuf"), ",") - fieldNum, err := strconv.Atoi(tags[1]) - if err != nil { - panic("protobuf tag field not an integer: " + tags[1]) - } - var name string - for _, tag := range tags { - if strings.HasPrefix(tag, "name=") { - name = strings.TrimPrefix(tag, "name=") - break - } - } - - // Find the oneof field that this struct implements. - // Might take O(n^2) to process all of the oneofs, but who cares. - for _, of := range oneofFields { - if tptr.Implements(of.ityp) { - // We have found the corresponding interface for this struct. - // That lets us know where this struct should be stored - // when we encounter it during unmarshaling. - unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) - u.setTag(fieldNum, of.field, unmarshal, 0, name) - } + f := typ.Field(0) // oneof implementers have one field + baseUnmarshal := fieldUnmarshaler(&f) + tags := strings.Split(f.Tag.Get("protobuf"), ",") + fieldNum, err := strconv.Atoi(tags[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tags[1]) + } + var name string + for _, tag := range tags { + if strings.HasPrefix(tag, "name=") { + name = strings.TrimPrefix(tag, "name=") + break } } + + // Find the oneof field that this struct implements. + // Might take O(n^2) to process all of the oneofs, but who cares. + for _, of := range oneofFields { + if tptr.Implements(of.ityp) { + // We have found the corresponding interface for this struct. + // That lets us know where this struct should be stored + // when we encounter it during unmarshaling. + unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) + u.setTag(fieldNum, of.field, unmarshal, 0, name) + } + } + } // Get extension ranges, if any. - fn = reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") + fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") if fn.IsValid() { if !u.extensions.IsValid() && !u.oldExtensions.IsValid() { panic("a message with extensions, but no extensions field in " + t.Name()) @@ -1948,7 +1950,7 @@ func encodeVarint(b []byte, x uint64) []byte { // If there is an error, it returns 0,0. func decodeVarint(b []byte) (uint64, int) { var x, y uint64 - if len(b) <= 0 { + if len(b) == 0 { goto bad } x = uint64(b[0]) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collector.go index c0d70b2faf..1e839650d4 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/collector.go @@ -79,7 +79,7 @@ type Collector interface { // of the Describe method. If a Collector sometimes collects no metrics at all // (for example vectors like CounterVec, GaugeVec, etc., which only collect // metrics after a metric with a fully specified label set has been accessed), -// it might even get registered as an unchecked Collecter (cf. the Register +// it might even get registered as an unchecked Collector (cf. the Register // method of the Registerer interface). Hence, only use this shortcut // implementation of Describe if you are certain to fulfill the contract. // diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go index 765e4550c6..d463e36d3e 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go @@ -136,7 +136,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { return &CounterVec{ metricVec: newMetricVec(desc, func(lvs ...string) Metric { if len(lvs) != len(desc.variableLabels) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) } result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} result.init(result) // Init self-collection. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index 7b8827ffbc..1d034f871c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -93,7 +93,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // First add only the const label names and sort them... for labelName := range constLabels { if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) + d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) return d } labelNames = append(labelNames, labelName) @@ -115,7 +115,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // dimension with a different mix between preset and variable labels. for _, labelName := range variableLabels { if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) + d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) return d } labelNames = append(labelNames, "$"+labelName) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go index 5d9525defc..1e0d578ee7 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/doc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/doc.go @@ -122,13 +122,13 @@ // the Collect method. The Describe method has to return separate Desc // instances, representative of the “throw-away” metrics to be created later. // NewDesc comes in handy to create those Desc instances. Alternatively, you -// could return no Desc at all, which will marke the Collector “unchecked”. No -// checks are porformed at registration time, but metric consistency will still +// could return no Desc at all, which will mark the Collector “unchecked”. No +// checks are performed at registration time, but metric consistency will still // be ensured at scrape time, i.e. any inconsistencies will lead to scrape // errors. Thus, with unchecked Collectors, the responsibility to not collect // metrics that lead to inconsistencies in the total scrape result lies with the // implementer of the Collector. While this is not a desirable state, it is -// sometimes necessary. The typical use case is a situatios where the exact +// sometimes necessary. The typical use case is a situation where the exact // metrics to be returned by a Collector cannot be predicted at registration // time, but the implementer has sufficient knowledge of the whole system to // guarantee metric consistency. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go index 17c72d7eb0..71d406bd92 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go @@ -147,7 +147,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { return &GaugeVec{ metricVec: newMetricVec(desc, func(lvs ...string) Metric { if len(lvs) != len(desc.variableLabels) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) } result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} result.init(result) // Init self-collection. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go index ba3b9333ed..b108ec5130 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go @@ -14,9 +14,9 @@ package prometheus import ( - "fmt" "runtime" "runtime/debug" + "sync" "time" ) @@ -26,16 +26,41 @@ type goCollector struct { gcDesc *Desc goInfoDesc *Desc - // metrics to describe and collect - metrics memStatsMetrics + // ms... are memstats related. + msLast *runtime.MemStats // Previously collected memstats. + msLastTimestamp time.Time + msMtx sync.Mutex // Protects msLast and msLastTimestamp. + msMetrics memStatsMetrics + msRead func(*runtime.MemStats) // For mocking in tests. + msMaxWait time.Duration // Wait time for fresh memstats. + msMaxAge time.Duration // Maximum allowed age of old memstats. } // NewGoCollector returns a collector which exports metrics about the current Go // process. This includes memory stats. To collect those, runtime.ReadMemStats -// is called. This causes a stop-the-world, which is very short with Go1.9+ -// (~25µs). However, with older Go versions, the stop-the-world duration depends -// on the heap size and can be quite significant (~1.7 ms/GiB as per +// is called. This requires to “stop the world”, which usually only happens for +// garbage collection (GC). Take the following implications into account when +// deciding whether to use the Go collector: +// +// 1. The performance impact of stopping the world is the more relevant the more +// frequently metrics are collected. However, with Go1.9 or later the +// stop-the-world time per metrics collection is very short (~25µs) so that the +// performance impact will only matter in rare cases. However, with older Go +// versions, the stop-the-world duration depends on the heap size and can be +// quite significant (~1.7 ms/GiB as per // https://go-review.googlesource.com/c/go/+/34937). +// +// 2. During an ongoing GC, nothing else can stop the world. Therefore, if the +// metrics collection happens to coincide with GC, it will only complete after +// GC has finished. Usually, GC is fast enough to not cause problems. However, +// with a very large heap, GC might take multiple seconds, which is enough to +// cause scrape timeouts in common setups. To avoid this problem, the Go +// collector will use the memstats from a previous collection if +// runtime.ReadMemStats takes more than 1s. However, if there are no previously +// collected memstats, or their collection is more than 5m ago, the collection +// will block until runtime.ReadMemStats succeeds. (The problem might be solved +// in Go1.13, see https://github.com/golang/go/issues/19812 for the related Go +// issue.) func NewGoCollector() Collector { return &goCollector{ goroutinesDesc: NewDesc( @@ -54,7 +79,11 @@ func NewGoCollector() Collector { "go_info", "Information about the Go environment.", nil, Labels{"version": runtime.Version()}), - metrics: memStatsMetrics{ + msLast: &runtime.MemStats{}, + msRead: runtime.ReadMemStats, + msMaxWait: time.Second, + msMaxAge: 5 * time.Minute, + msMetrics: memStatsMetrics{ { desc: NewDesc( memstatNamespace("alloc_bytes"), @@ -253,7 +282,7 @@ func NewGoCollector() Collector { } func memstatNamespace(s string) string { - return fmt.Sprintf("go_memstats_%s", s) + return "go_memstats_" + s } // Describe returns all descriptions of the collector. @@ -262,13 +291,27 @@ func (c *goCollector) Describe(ch chan<- *Desc) { ch <- c.threadsDesc ch <- c.gcDesc ch <- c.goInfoDesc - for _, i := range c.metrics { + for _, i := range c.msMetrics { ch <- i.desc } } // Collect returns the current state of all metrics of the collector. func (c *goCollector) Collect(ch chan<- Metric) { + var ( + ms = &runtime.MemStats{} + done = make(chan struct{}) + ) + // Start reading memstats first as it might take a while. + go func() { + c.msRead(ms) + c.msMtx.Lock() + c.msLast = ms + c.msLastTimestamp = time.Now() + c.msMtx.Unlock() + close(done) + }() + ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine())) n, _ := runtime.ThreadCreateProfile(nil) ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n)) @@ -286,9 +329,31 @@ func (c *goCollector) Collect(ch chan<- Metric) { ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1) - ms := &runtime.MemStats{} - runtime.ReadMemStats(ms) - for _, i := range c.metrics { + timer := time.NewTimer(c.msMaxWait) + select { + case <-done: // Our own ReadMemStats succeeded in time. Use it. + timer.Stop() // Important for high collection frequencies to not pile up timers. + c.msCollect(ch, ms) + return + case <-timer.C: // Time out, use last memstats if possible. Continue below. + } + c.msMtx.Lock() + if time.Since(c.msLastTimestamp) < c.msMaxAge { + // Last memstats are recent enough. Collect from them under the lock. + c.msCollect(ch, c.msLast) + c.msMtx.Unlock() + return + } + // If we are here, the last memstats are too old or don't exist. We have + // to wait until our own ReadMemStats finally completes. For that to + // happen, we have to release the lock. + c.msMtx.Unlock() + <-done + c.msCollect(ch, ms) +} + +func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) { + for _, i := range c.msMetrics { ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms)) } } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go index 4d7fa976e4..d7ea67bd2b 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go @@ -165,7 +165,7 @@ func NewHistogram(opts HistogramOpts) Histogram { func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram { if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) } for _, n := range desc.variableLabels { @@ -204,8 +204,8 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } } } - // Finally we know the final length of h.upperBounds and can make counts - // for both states: + // Finally we know the final length of h.upperBounds and can make buckets + // for both counts: h.counts[0].buckets = make([]uint64, len(h.upperBounds)) h.counts[1].buckets = make([]uint64, len(h.upperBounds)) @@ -224,18 +224,21 @@ type histogramCounts struct { } type histogram struct { - // countAndHotIdx is a complicated one. For lock-free yet atomic - // observations, we need to save the total count of observations again, - // combined with the index of the currently-hot counts struct, so that - // we can perform the operation on both values atomically. The least - // significant bit defines the hot counts struct. The remaining 63 bits - // represent the total count of observations. This happens under the - // assumption that the 63bit count will never overflow. Rationale: An - // observations takes about 30ns. Let's assume it could happen in - // 10ns. Overflowing the counter will then take at least (2^63)*10ns, - // which is about 3000 years. + // countAndHotIdx enables lock-free writes with use of atomic updates. + // The most significant bit is the hot index [0 or 1] of the count field + // below. Observe calls update the hot one. All remaining bits count the + // number of Observe calls. Observe starts by incrementing this counter, + // and finish by incrementing the count field in the respective + // histogramCounts, as a marker for completion. // - // This has to be first in the struct for 64bit alignment. See + // Calls of the Write method (which are non-mutating reads from the + // perspective of the histogram) swap the hot–cold under the writeMtx + // lock. A cooldown is awaited (while locked) by comparing the number of + // observations with the initiation count. Once they match, then the + // last observation on the now cool one has completed. All cool fields must + // be merged into the new hot before releasing writeMtx. + // + // Fields with atomic access first! See alignment constraint: // http://golang.org/pkg/sync/atomic/#pkg-note-BUG countAndHotIdx uint64 @@ -243,16 +246,14 @@ type histogram struct { desc *Desc writeMtx sync.Mutex // Only used in the Write method. - upperBounds []float64 - // Two counts, one is "hot" for lock-free observations, the other is // "cold" for writing out a dto.Metric. It has to be an array of // pointers to guarantee 64bit alignment of the histogramCounts, see // http://golang.org/pkg/sync/atomic/#pkg-note-BUG. counts [2]*histogramCounts - hotIdx int // Index of currently-hot counts. Only used within Write. - labelPairs []*dto.LabelPair + upperBounds []float64 + labelPairs []*dto.LabelPair } func (h *histogram) Desc() *Desc { @@ -271,11 +272,11 @@ func (h *histogram) Observe(v float64) { // 300 buckets: 154 ns/op linear - binary 61.6 ns/op i := sort.SearchFloat64s(h.upperBounds, v) - // We increment h.countAndHotIdx by 2 so that the counter in the upper - // 63 bits gets incremented by 1. At the same time, we get the new value + // We increment h.countAndHotIdx so that the counter in the lower + // 63 bits gets incremented. At the same time, we get the new value // back, which we can use to find the currently-hot counts. - n := atomic.AddUint64(&h.countAndHotIdx, 2) - hotCounts := h.counts[n%2] + n := atomic.AddUint64(&h.countAndHotIdx, 1) + hotCounts := h.counts[n>>63] if i < len(h.upperBounds) { atomic.AddUint64(&hotCounts.buckets[i], 1) @@ -293,72 +294,43 @@ func (h *histogram) Observe(v float64) { } func (h *histogram) Write(out *dto.Metric) error { - var ( - his = &dto.Histogram{} - buckets = make([]*dto.Bucket, len(h.upperBounds)) - hotCounts, coldCounts *histogramCounts - count uint64 - ) - - // For simplicity, we mutex the rest of this method. It is not in the - // hot path, i.e. Observe is called much more often than Write. The - // complication of making Write lock-free isn't worth it. + // For simplicity, we protect this whole method by a mutex. It is not in + // the hot path, i.e. Observe is called much more often than Write. The + // complication of making Write lock-free isn't worth it, if possible at + // all. h.writeMtx.Lock() defer h.writeMtx.Unlock() - // This is a bit arcane, which is why the following spells out this if - // clause in English: - // - // If the currently-hot counts struct is #0, we atomically increment - // h.countAndHotIdx by 1 so that from now on Observe will use the counts - // struct #1. Furthermore, the atomic increment gives us the new value, - // which, in its most significant 63 bits, tells us the count of - // observations done so far up to and including currently ongoing - // observations still using the counts struct just changed from hot to - // cold. To have a normal uint64 for the count, we bitshift by 1 and - // save the result in count. We also set h.hotIdx to 1 for the next - // Write call, and we will refer to counts #1 as hotCounts and to counts - // #0 as coldCounts. - // - // If the currently-hot counts struct is #1, we do the corresponding - // things the other way round. We have to _decrement_ h.countAndHotIdx - // (which is a bit arcane in itself, as we have to express -1 with an - // unsigned int...). - if h.hotIdx == 0 { - count = atomic.AddUint64(&h.countAndHotIdx, 1) >> 1 - h.hotIdx = 1 - hotCounts = h.counts[1] - coldCounts = h.counts[0] - } else { - count = atomic.AddUint64(&h.countAndHotIdx, ^uint64(0)) >> 1 // Decrement. - h.hotIdx = 0 - hotCounts = h.counts[0] - coldCounts = h.counts[1] - } + // Adding 1<<63 switches the hot index (from 0 to 1 or from 1 to 0) + // without touching the count bits. See the struct comments for a full + // description of the algorithm. + n := atomic.AddUint64(&h.countAndHotIdx, 1<<63) + // count is contained unchanged in the lower 63 bits. + count := n & ((1 << 63) - 1) + // The most significant bit tells us which counts is hot. The complement + // is thus the cold one. + hotCounts := h.counts[n>>63] + coldCounts := h.counts[(^n)>>63] - // Now we have to wait for the now-declared-cold counts to actually cool - // down, i.e. wait for all observations still using it to finish. That's - // the case once the count in the cold counts struct is the same as the - // one atomically retrieved from the upper 63bits of h.countAndHotIdx. - for { - if count == atomic.LoadUint64(&coldCounts.count) { - break - } + // Await cooldown. + for count != atomic.LoadUint64(&coldCounts.count) { runtime.Gosched() // Let observations get work done. } - his.SampleCount = proto.Uint64(count) - his.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))) + his := &dto.Histogram{ + Bucket: make([]*dto.Bucket, len(h.upperBounds)), + SampleCount: proto.Uint64(count), + SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + } var cumCount uint64 for i, upperBound := range h.upperBounds { cumCount += atomic.LoadUint64(&coldCounts.buckets[i]) - buckets[i] = &dto.Bucket{ + his.Bucket[i] = &dto.Bucket{ CumulativeCount: proto.Uint64(cumCount), UpperBound: proto.Float64(upperBound), } } - his.Bucket = buckets out.Histogram = his out.Label = h.labelPairs diff --git a/vendor/github.com/prometheus/client_golang/prometheus/http.go b/vendor/github.com/prometheus/client_golang/prometheus/http.go index 4b8e602733..19a3e8f493 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/http.go @@ -15,9 +15,7 @@ package prometheus import ( "bufio" - "bytes" "compress/gzip" - "fmt" "io" "net" "net/http" @@ -36,24 +34,14 @@ import ( const ( contentTypeHeader = "Content-Type" - contentLengthHeader = "Content-Length" contentEncodingHeader = "Content-Encoding" acceptEncodingHeader = "Accept-Encoding" ) -var bufPool sync.Pool - -func getBuf() *bytes.Buffer { - buf := bufPool.Get() - if buf == nil { - return &bytes.Buffer{} - } - return buf.(*bytes.Buffer) -} - -func giveBuf(buf *bytes.Buffer) { - buf.Reset() - bufPool.Put(buf) +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, } // Handler returns an HTTP handler for the DefaultGatherer. It is @@ -71,58 +59,40 @@ func Handler() http.Handler { // Deprecated: Use promhttp.HandlerFor(DefaultGatherer, promhttp.HandlerOpts{}) // instead. See there for further documentation. func UninstrumentedHandler() http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + return http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { mfs, err := DefaultGatherer.Gather() if err != nil { - http.Error(w, "An error has occurred during metrics collection:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } contentType := expfmt.Negotiate(req.Header) - buf := getBuf() - defer giveBuf(buf) - writer, encoding := decorateWriter(req, buf) - enc := expfmt.NewEncoder(writer, contentType) - var lastErr error + header := rsp.Header() + header.Set(contentTypeHeader, string(contentType)) + + w := io.Writer(rsp) + if gzipAccepted(req.Header) { + header.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + enc := expfmt.NewEncoder(w, contentType) + for _, mf := range mfs { if err := enc.Encode(mf); err != nil { - lastErr = err - http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } } - if closer, ok := writer.(io.Closer); ok { - closer.Close() - } - if lastErr != nil && buf.Len() == 0 { - http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError) - return - } - header := w.Header() - header.Set(contentTypeHeader, string(contentType)) - header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) - if encoding != "" { - header.Set(contentEncodingHeader, encoding) - } - w.Write(buf.Bytes()) }) } -// decorateWriter wraps a writer to handle gzip compression if requested. It -// returns the decorated writer and the appropriate "Content-Encoding" header -// (which is empty if no compression is enabled). -func decorateWriter(request *http.Request, writer io.Writer) (io.Writer, string) { - header := request.Header.Get(acceptEncodingHeader) - parts := strings.Split(header, ",") - for _, part := range parts { - part = strings.TrimSpace(part) - if part == "gzip" || strings.HasPrefix(part, "gzip;") { - return gzip.NewWriter(writer), "gzip" - } - } - return writer, "" -} - var instLabels = []string{"method", "code"} type nower interface { @@ -360,6 +330,8 @@ type fancyResponseWriterDelegator struct { } func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool { + //lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to + //remove support from client_golang yet. return f.ResponseWriter.(http.CloseNotifier).CloseNotify() } @@ -503,3 +475,31 @@ func sanitizeCode(s int) string { return strconv.Itoa(s) } } + +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(header http.Header) bool { + a := header.Get(acceptEncodingHeader) + parts := strings.Split(a, ",") + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "gzip" || strings.HasPrefix(part, "gzip;") { + return true + } + } + return false +} + +// httpError removes any content-encoding header and then calls http.Error with +// the provided error and http.StatusInternalServerErrer. Error contents is +// supposed to be uncompressed plain text. However, same as with a plain +// http.Error, any header settings will be void if the header has already been +// sent. The error message will still be written to the writer, but it will +// probably be of limited use. +func httpError(rsp http.ResponseWriter, err error) { + rsp.Header().Del(contentEncodingHeader) + http.Error( + rsp, + "An error has occurred while serving metrics:\n\n"+err.Error(), + http.StatusInternalServerError, + ) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/labels.go b/vendor/github.com/prometheus/client_golang/prometheus/labels.go index e68f132ece..2744443ac2 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/labels.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/labels.go @@ -37,9 +37,22 @@ const reservedLabelPrefix = "__" var errInconsistentCardinality = errors.New("inconsistent label cardinality") +func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error { + return fmt.Errorf( + "%s: %q has %d variable labels named %q but %d values %q were provided", + errInconsistentCardinality, fqName, + len(labels), labels, + len(labelValues), labelValues, + ) +} + func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { if len(labels) != expectedNumberOfValues { - return errInconsistentCardinality + return fmt.Errorf( + "%s: expected %d label values but got %d in %#v", + errInconsistentCardinality, expectedNumberOfValues, + len(labels), labels, + ) } for name, val := range labels { @@ -53,7 +66,11 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { func validateLabelValues(vals []string, expectedNumberOfValues int) error { if len(vals) != expectedNumberOfValues { - return errInconsistentCardinality + return fmt.Errorf( + "%s: expected %d label values but got %d in %#v", + errInconsistentCardinality, expectedNumberOfValues, + len(vals), vals, + ) } for _, val := range vals { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go index 67b56d37cf..fa535684f9 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go @@ -38,7 +38,6 @@ type delegator interface { type responseWriterDelegator struct { http.ResponseWriter - handler, method string status int written int64 wroteHeader bool @@ -75,8 +74,11 @@ type closeNotifierDelegator struct{ *responseWriterDelegator } type flusherDelegator struct{ *responseWriterDelegator } type hijackerDelegator struct{ *responseWriterDelegator } type readerFromDelegator struct{ *responseWriterDelegator } +type pusherDelegator struct{ *responseWriterDelegator } func (d closeNotifierDelegator) CloseNotify() <-chan bool { + //lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to + //remove support from client_golang yet. return d.ResponseWriter.(http.CloseNotifier).CloseNotify() } func (d flusherDelegator) Flush() { @@ -93,6 +95,9 @@ func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { d.written += n return n, err } +func (d pusherDelegator) Push(target string, opts *http.PushOptions) error { + return d.ResponseWriter.(http.Pusher).Push(target, opts) +} var pickDelegator = make([]func(*responseWriterDelegator) delegator, 32) @@ -196,4 +201,157 @@ func init() { http.CloseNotifier }{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} } + pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16 + return pusherDelegator{d} + } + pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17 + return struct { + *responseWriterDelegator + http.Pusher + http.CloseNotifier + }{d, pusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18 + return struct { + *responseWriterDelegator + http.Pusher + http.Flusher + }{d, pusherDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19 + return struct { + *responseWriterDelegator + http.Pusher + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + }{d, pusherDelegator{d}, hijackerDelegator{d}} + } + pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + http.CloseNotifier + }{d, pusherDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + http.Flusher + }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + }{d, pusherDelegator{d}, readerFromDelegator{d}} + } + pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Flusher + }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + http.Flusher + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } +} + +func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { + d := &responseWriterDelegator{ + ResponseWriter: w, + observeWriteHeader: observeWriteHeaderFunc, + } + + id := 0 + //lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to + //remove support from client_golang yet. + if _, ok := w.(http.CloseNotifier); ok { + id += closeNotifier + } + if _, ok := w.(http.Flusher); ok { + id += flusher + } + if _, ok := w.(http.Hijacker); ok { + id += hijacker + } + if _, ok := w.(io.ReaderFrom); ok { + id += readerFrom + } + if _, ok := w.(http.Pusher); ok { + id += pusher + } + + return pickDelegator[id](d) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go deleted file mode 100644 index 31a7069569..0000000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2017 The Prometheus 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. - -// +build go1.8 - -package promhttp - -import ( - "io" - "net/http" -) - -type pusherDelegator struct{ *responseWriterDelegator } - -func (d pusherDelegator) Push(target string, opts *http.PushOptions) error { - return d.ResponseWriter.(http.Pusher).Push(target, opts) -} - -func init() { - pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16 - return pusherDelegator{d} - } - pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17 - return struct { - *responseWriterDelegator - http.Pusher - http.CloseNotifier - }{d, pusherDelegator{d}, closeNotifierDelegator{d}} - } - pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18 - return struct { - *responseWriterDelegator - http.Pusher - http.Flusher - }{d, pusherDelegator{d}, flusherDelegator{d}} - } - pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19 - return struct { - *responseWriterDelegator - http.Pusher - http.Flusher - http.CloseNotifier - }{d, pusherDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} - } - pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20 - return struct { - *responseWriterDelegator - http.Pusher - http.Hijacker - }{d, pusherDelegator{d}, hijackerDelegator{d}} - } - pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21 - return struct { - *responseWriterDelegator - http.Pusher - http.Hijacker - http.CloseNotifier - }{d, pusherDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} - } - pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22 - return struct { - *responseWriterDelegator - http.Pusher - http.Hijacker - http.Flusher - }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} - } - pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23 - return struct { - *responseWriterDelegator - http.Pusher - http.Hijacker - http.Flusher - http.CloseNotifier - }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} - } - pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - }{d, pusherDelegator{d}, readerFromDelegator{d}} - } - pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - http.CloseNotifier - }{d, pusherDelegator{d}, readerFromDelegator{d}, closeNotifierDelegator{d}} - } - pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - http.Flusher - }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}} - } - pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - http.Flusher - http.CloseNotifier - }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} - } - pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - http.Hijacker - }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}} - } - pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - http.Hijacker - http.CloseNotifier - }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} - } - pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - http.Hijacker - http.Flusher - }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} - } - pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31 - return struct { - *responseWriterDelegator - http.Pusher - io.ReaderFrom - http.Hijacker - http.Flusher - http.CloseNotifier - }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} - } -} - -func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { - d := &responseWriterDelegator{ - ResponseWriter: w, - observeWriteHeader: observeWriteHeaderFunc, - } - - id := 0 - if _, ok := w.(http.CloseNotifier); ok { - id += closeNotifier - } - if _, ok := w.(http.Flusher); ok { - id += flusher - } - if _, ok := w.(http.Hijacker); ok { - id += hijacker - } - if _, ok := w.(io.ReaderFrom); ok { - id += readerFrom - } - if _, ok := w.(http.Pusher); ok { - id += pusher - } - - return pickDelegator[id](d) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go deleted file mode 100644 index 8bb9b8b68f..0000000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 The Prometheus 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. - -// +build !go1.8 - -package promhttp - -import ( - "io" - "net/http" -) - -func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { - d := &responseWriterDelegator{ - ResponseWriter: w, - observeWriteHeader: observeWriteHeaderFunc, - } - - id := 0 - if _, ok := w.(http.CloseNotifier); ok { - id += closeNotifier - } - if _, ok := w.(http.Flusher); ok { - id += flusher - } - if _, ok := w.(http.Hijacker); ok { - id += hijacker - } - if _, ok := w.(io.ReaderFrom); ok { - id += readerFrom - } - - return pickDelegator[id](d) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go index 01357374fe..b137c88307 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go @@ -32,7 +32,6 @@ package promhttp import ( - "bytes" "compress/gzip" "fmt" "io" @@ -48,24 +47,14 @@ import ( const ( contentTypeHeader = "Content-Type" - contentLengthHeader = "Content-Length" contentEncodingHeader = "Content-Encoding" acceptEncodingHeader = "Accept-Encoding" ) -var bufPool sync.Pool - -func getBuf() *bytes.Buffer { - buf := bufPool.Get() - if buf == nil { - return &bytes.Buffer{} - } - return buf.(*bytes.Buffer) -} - -func giveBuf(buf *bytes.Buffer) { - buf.Reset() - bufPool.Put(buf) +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, } // Handler returns an http.Handler for the prometheus.DefaultGatherer, using @@ -100,19 +89,18 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight) } - h := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { if inFlightSem != nil { select { case inFlightSem <- struct{}{}: // All good, carry on. defer func() { <-inFlightSem }() default: - http.Error(w, fmt.Sprintf( + http.Error(rsp, fmt.Sprintf( "Limit of concurrent requests reached (%d), try again later.", opts.MaxRequestsInFlight, ), http.StatusServiceUnavailable) return } } - mfs, err := reg.Gather() if err != nil { if opts.ErrorLog != nil { @@ -123,26 +111,40 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { panic(err) case ContinueOnError: if len(mfs) == 0 { - http.Error(w, "No metrics gathered, last error:\n\n"+err.Error(), http.StatusInternalServerError) + // Still report the error if no metrics have been gathered. + httpError(rsp, err) return } case HTTPErrorOnError: - http.Error(w, "An error has occurred during metrics gathering:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } } contentType := expfmt.Negotiate(req.Header) - buf := getBuf() - defer giveBuf(buf) - writer, encoding := decorateWriter(req, buf, opts.DisableCompression) - enc := expfmt.NewEncoder(writer, contentType) + header := rsp.Header() + header.Set(contentTypeHeader, string(contentType)) + + w := io.Writer(rsp) + if !opts.DisableCompression && gzipAccepted(req.Header) { + header.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + enc := expfmt.NewEncoder(w, contentType) + var lastErr error for _, mf := range mfs { if err := enc.Encode(mf); err != nil { lastErr = err if opts.ErrorLog != nil { - opts.ErrorLog.Println("error encoding metric family:", err) + opts.ErrorLog.Println("error encoding and sending metric family:", err) } switch opts.ErrorHandling { case PanicOnError: @@ -150,28 +152,15 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { case ContinueOnError: // Handled later. case HTTPErrorOnError: - http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } } } - if closer, ok := writer.(io.Closer); ok { - closer.Close() + + if lastErr != nil { + httpError(rsp, lastErr) } - if lastErr != nil && buf.Len() == 0 { - http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError) - return - } - header := w.Header() - header.Set(contentTypeHeader, string(contentType)) - header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) - if encoding != "" { - header.Set(contentEncodingHeader, encoding) - } - if _, err := w.Write(buf.Bytes()); err != nil && opts.ErrorLog != nil { - opts.ErrorLog.Println("error while sending encoded metrics:", err) - } - // TODO(beorn7): Consider streaming serving of metrics. }) if opts.Timeout <= 0 { @@ -292,20 +281,30 @@ type HandlerOpts struct { Timeout time.Duration } -// decorateWriter wraps a writer to handle gzip compression if requested. It -// returns the decorated writer and the appropriate "Content-Encoding" header -// (which is empty if no compression is enabled). -func decorateWriter(request *http.Request, writer io.Writer, compressionDisabled bool) (io.Writer, string) { - if compressionDisabled { - return writer, "" - } - header := request.Header.Get(acceptEncodingHeader) - parts := strings.Split(header, ",") +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(header http.Header) bool { + a := header.Get(acceptEncodingHeader) + parts := strings.Split(a, ",") for _, part := range parts { part = strings.TrimSpace(part) if part == "gzip" || strings.HasPrefix(part, "gzip;") { - return gzip.NewWriter(writer), "gzip" + return true } } - return writer, "" + return false +} + +// httpError removes any content-encoding header and then calls http.Error with +// the provided error and http.StatusInternalServerErrer. Error contents is +// supposed to be uncompressed plain text. However, same as with a plain +// http.Error, any header settings will be void if the header has already been +// sent. The error message will still be written to the writer, but it will +// probably be of limited use. +func httpError(rsp http.ResponseWriter, err error) { + rsp.Header().Del(contentEncodingHeader) + http.Error( + rsp, + "An error has occurred while serving metrics:\n\n"+err.Error(), + http.StatusInternalServerError, + ) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go index 86fd564470..83c49b66a8 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go @@ -14,7 +14,9 @@ package promhttp import ( + "crypto/tls" "net/http" + "net/http/httptrace" "time" "github.com/prometheus/client_golang/prometheus" @@ -95,3 +97,123 @@ func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundT return resp, err }) } + +// InstrumentTrace is used to offer flexibility in instrumenting the available +// httptrace.ClientTrace hook functions. Each function is passed a float64 +// representing the time in seconds since the start of the http request. A user +// may choose to use separately buckets Histograms, or implement custom +// instance labels on a per function basis. +type InstrumentTrace struct { + GotConn func(float64) + PutIdleConn func(float64) + GotFirstResponseByte func(float64) + Got100Continue func(float64) + DNSStart func(float64) + DNSDone func(float64) + ConnectStart func(float64) + ConnectDone func(float64) + TLSHandshakeStart func(float64) + TLSHandshakeDone func(float64) + WroteHeaders func(float64) + Wait100Continue func(float64) + WroteRequest func(float64) +} + +// InstrumentRoundTripperTrace is a middleware that wraps the provided +// RoundTripper and reports times to hook functions provided in the +// InstrumentTrace struct. Hook functions that are not present in the provided +// InstrumentTrace struct are ignored. Times reported to the hook functions are +// time since the start of the request. Only with Go1.9+, those times are +// guaranteed to never be negative. (Earlier Go versions are not using a +// monotonic clock.) Note that partitioning of Histograms is expensive and +// should be used judiciously. +// +// For hook functions that receive an error as an argument, no observations are +// made in the event of a non-nil error value. +// +// See the example for ExampleInstrumentRoundTripperDuration for example usage. +func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { + return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + start := time.Now() + + trace := &httptrace.ClientTrace{ + GotConn: func(_ httptrace.GotConnInfo) { + if it.GotConn != nil { + it.GotConn(time.Since(start).Seconds()) + } + }, + PutIdleConn: func(err error) { + if err != nil { + return + } + if it.PutIdleConn != nil { + it.PutIdleConn(time.Since(start).Seconds()) + } + }, + DNSStart: func(_ httptrace.DNSStartInfo) { + if it.DNSStart != nil { + it.DNSStart(time.Since(start).Seconds()) + } + }, + DNSDone: func(_ httptrace.DNSDoneInfo) { + if it.DNSDone != nil { + it.DNSDone(time.Since(start).Seconds()) + } + }, + ConnectStart: func(_, _ string) { + if it.ConnectStart != nil { + it.ConnectStart(time.Since(start).Seconds()) + } + }, + ConnectDone: func(_, _ string, err error) { + if err != nil { + return + } + if it.ConnectDone != nil { + it.ConnectDone(time.Since(start).Seconds()) + } + }, + GotFirstResponseByte: func() { + if it.GotFirstResponseByte != nil { + it.GotFirstResponseByte(time.Since(start).Seconds()) + } + }, + Got100Continue: func() { + if it.Got100Continue != nil { + it.Got100Continue(time.Since(start).Seconds()) + } + }, + TLSHandshakeStart: func() { + if it.TLSHandshakeStart != nil { + it.TLSHandshakeStart(time.Since(start).Seconds()) + } + }, + TLSHandshakeDone: func(_ tls.ConnectionState, err error) { + if err != nil { + return + } + if it.TLSHandshakeDone != nil { + it.TLSHandshakeDone(time.Since(start).Seconds()) + } + }, + WroteHeaders: func() { + if it.WroteHeaders != nil { + it.WroteHeaders(time.Since(start).Seconds()) + } + }, + Wait100Continue: func() { + if it.Wait100Continue != nil { + it.Wait100Continue(time.Since(start).Seconds()) + } + }, + WroteRequest: func(_ httptrace.WroteRequestInfo) { + if it.WroteRequest != nil { + it.WroteRequest(time.Since(start).Seconds()) + } + }, + } + r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace)) + + return next.RoundTrip(r) + }) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go deleted file mode 100644 index a034d1ec0f..0000000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2017 The Prometheus 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. - -// +build go1.8 - -package promhttp - -import ( - "context" - "crypto/tls" - "net/http" - "net/http/httptrace" - "time" -) - -// InstrumentTrace is used to offer flexibility in instrumenting the available -// httptrace.ClientTrace hook functions. Each function is passed a float64 -// representing the time in seconds since the start of the http request. A user -// may choose to use separately buckets Histograms, or implement custom -// instance labels on a per function basis. -type InstrumentTrace struct { - GotConn func(float64) - PutIdleConn func(float64) - GotFirstResponseByte func(float64) - Got100Continue func(float64) - DNSStart func(float64) - DNSDone func(float64) - ConnectStart func(float64) - ConnectDone func(float64) - TLSHandshakeStart func(float64) - TLSHandshakeDone func(float64) - WroteHeaders func(float64) - Wait100Continue func(float64) - WroteRequest func(float64) -} - -// InstrumentRoundTripperTrace is a middleware that wraps the provided -// RoundTripper and reports times to hook functions provided in the -// InstrumentTrace struct. Hook functions that are not present in the provided -// InstrumentTrace struct are ignored. Times reported to the hook functions are -// time since the start of the request. Only with Go1.9+, those times are -// guaranteed to never be negative. (Earlier Go versions are not using a -// monotonic clock.) Note that partitioning of Histograms is expensive and -// should be used judiciously. -// -// For hook functions that receive an error as an argument, no observations are -// made in the event of a non-nil error value. -// -// See the example for ExampleInstrumentRoundTripperDuration for example usage. -func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { - return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { - start := time.Now() - - trace := &httptrace.ClientTrace{ - GotConn: func(_ httptrace.GotConnInfo) { - if it.GotConn != nil { - it.GotConn(time.Since(start).Seconds()) - } - }, - PutIdleConn: func(err error) { - if err != nil { - return - } - if it.PutIdleConn != nil { - it.PutIdleConn(time.Since(start).Seconds()) - } - }, - DNSStart: func(_ httptrace.DNSStartInfo) { - if it.DNSStart != nil { - it.DNSStart(time.Since(start).Seconds()) - } - }, - DNSDone: func(_ httptrace.DNSDoneInfo) { - if it.DNSDone != nil { - it.DNSDone(time.Since(start).Seconds()) - } - }, - ConnectStart: func(_, _ string) { - if it.ConnectStart != nil { - it.ConnectStart(time.Since(start).Seconds()) - } - }, - ConnectDone: func(_, _ string, err error) { - if err != nil { - return - } - if it.ConnectDone != nil { - it.ConnectDone(time.Since(start).Seconds()) - } - }, - GotFirstResponseByte: func() { - if it.GotFirstResponseByte != nil { - it.GotFirstResponseByte(time.Since(start).Seconds()) - } - }, - Got100Continue: func() { - if it.Got100Continue != nil { - it.Got100Continue(time.Since(start).Seconds()) - } - }, - TLSHandshakeStart: func() { - if it.TLSHandshakeStart != nil { - it.TLSHandshakeStart(time.Since(start).Seconds()) - } - }, - TLSHandshakeDone: func(_ tls.ConnectionState, err error) { - if err != nil { - return - } - if it.TLSHandshakeDone != nil { - it.TLSHandshakeDone(time.Since(start).Seconds()) - } - }, - WroteHeaders: func() { - if it.WroteHeaders != nil { - it.WroteHeaders(time.Since(start).Seconds()) - } - }, - Wait100Continue: func() { - if it.Wait100Continue != nil { - it.Wait100Continue(time.Since(start).Seconds()) - } - }, - WroteRequest: func(_ httptrace.WroteRequestInfo) { - if it.WroteRequest != nil { - it.WroteRequest(time.Since(start).Seconds()) - } - }, - } - r = r.WithContext(httptrace.WithClientTrace(context.Background(), trace)) - - return next.RoundTrip(r) - }) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index e422ef3834..f2fb67aeeb 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -16,6 +16,9 @@ package prometheus import ( "bytes" "fmt" + "io/ioutil" + "os" + "path/filepath" "runtime" "sort" "strings" @@ -23,6 +26,7 @@ import ( "unicode/utf8" "github.com/golang/protobuf/proto" + "github.com/prometheus/common/expfmt" dto "github.com/prometheus/client_model/go" @@ -533,6 +537,38 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() } +// WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the +// Prometheus text format, and writes it to a temporary file. Upon success, the +// temporary file is renamed to the provided filename. +// +// This is intended for use with the textfile collector of the node exporter. +// Note that the node exporter expects the filename to be suffixed with ".prom". +func WriteToTextfile(filename string, g Gatherer) error { + tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)) + if err != nil { + return err + } + defer os.Remove(tmp.Name()) + + mfs, err := g.Gather() + if err != nil { + return err + } + for _, mf := range mfs { + if _, err := expfmt.MetricFamilyToText(tmp, mf); err != nil { + return err + } + } + if err := tmp.Close(); err != nil { + return err + } + + if err := os.Chmod(tmp.Name(), 0644); err != nil { + return err + } + return os.Rename(tmp.Name(), filename) +} + // processMetric is an internal helper method only used by the Gather method. func processMetric( metric Metric, @@ -644,7 +680,7 @@ func processMetric( // Gatherers is a slice of Gatherer instances that implements the Gatherer // interface itself. Its Gather method calls Gather on all Gatherers in the // slice in order and returns the merged results. Errors returned from the -// Gather calles are all returned in a flattened MultiError. Duplicate and +// Gather calls are all returned in a flattened MultiError. Duplicate and // inconsistent Metrics are skipped (first occurrence in slice order wins) and // reported in the returned error. // @@ -836,7 +872,13 @@ func checkMetricConsistency( h = hashAddByte(h, separatorByte) // Make sure label pairs are sorted. We depend on it for the consistency // check. - sort.Sort(labelPairSorter(dtoMetric.Label)) + if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) { + // We cannot sort dtoMetric.Label in place as it is immutable by contract. + copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label)) + copy(copiedLabels, dtoMetric.Label) + sort.Sort(labelPairSorter(copiedLabels)) + dtoMetric.Label = copiedLabels + } for _, lp := range dtoMetric.Label { h = hashAdd(h, lp.GetName()) h = hashAddByte(h, separatorByte) @@ -867,8 +909,8 @@ func checkDescConsistency( } // Is the desc consistent with the content of the metric? - lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label)) - lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...) + lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label)) + copy(lpsFromDesc, desc.constLabelPairs) for _, l := range desc.variableLabels { lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ Name: proto.String(l), diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go index f7e92d8294..1574b0fe7d 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go @@ -16,8 +16,10 @@ package prometheus import ( "fmt" "math" + "runtime" "sort" "sync" + "sync/atomic" "time" "github.com/beorn7/perks/quantile" @@ -125,9 +127,10 @@ type SummaryOpts struct { // its zero value (i.e. nil). To create a Summary without Objectives, // set it to an empty map (i.e. map[float64]float64{}). // - // Deprecated: Note that the current value of DefObjectives is - // deprecated. It will be replaced by an empty map in v0.10 of the - // library. Please explicitly set Objectives to the desired value. + // Note that the current value of DefObjectives is deprecated. It will + // be replaced by an empty map in v0.10 of the library. Please + // explicitly set Objectives to the desired value to avoid problems + // during the transition. Objectives map[float64]float64 // MaxAge defines the duration for which an observation stays relevant @@ -151,7 +154,7 @@ type SummaryOpts struct { BufCap uint32 } -// Great fuck-up with the sliding-window decay algorithm... The Merge method of +// Problem with the sliding-window decay algorithm... The Merge method of // perk/quantile is actually not working as advertised - and it might be // unfixable, as the underlying algorithm is apparently not capable of merging // summaries in the first place. To avoid using Merge, we are currently adding @@ -181,7 +184,7 @@ func NewSummary(opts SummaryOpts) Summary { func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) } for _, n := range desc.variableLabels { @@ -214,6 +217,17 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { opts.BufCap = DefBufCap } + if len(opts.Objectives) == 0 { + // Use the lock-free implementation of a Summary without objectives. + s := &noObjectivesSummary{ + desc: desc, + labelPairs: makeLabelPairs(desc, labelValues), + counts: [2]*summaryCounts{&summaryCounts{}, &summaryCounts{}}, + } + s.init(s) // Init self-collection. + return s + } + s := &summary{ desc: desc, @@ -382,6 +396,116 @@ func (s *summary) swapBufs(now time.Time) { } } +type summaryCounts struct { + // sumBits contains the bits of the float64 representing the sum of all + // observations. sumBits and count have to go first in the struct to + // guarantee alignment for atomic operations. + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG + sumBits uint64 + count uint64 +} + +type noObjectivesSummary struct { + // countAndHotIdx enables lock-free writes with use of atomic updates. + // The most significant bit is the hot index [0 or 1] of the count field + // below. Observe calls update the hot one. All remaining bits count the + // number of Observe calls. Observe starts by incrementing this counter, + // and finish by incrementing the count field in the respective + // summaryCounts, as a marker for completion. + // + // Calls of the Write method (which are non-mutating reads from the + // perspective of the summary) swap the hot–cold under the writeMtx + // lock. A cooldown is awaited (while locked) by comparing the number of + // observations with the initiation count. Once they match, then the + // last observation on the now cool one has completed. All cool fields must + // be merged into the new hot before releasing writeMtx. + + // Fields with atomic access first! See alignment constraint: + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG + countAndHotIdx uint64 + + selfCollector + desc *Desc + writeMtx sync.Mutex // Only used in the Write method. + + // Two counts, one is "hot" for lock-free observations, the other is + // "cold" for writing out a dto.Metric. It has to be an array of + // pointers to guarantee 64bit alignment of the histogramCounts, see + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG. + counts [2]*summaryCounts + + labelPairs []*dto.LabelPair +} + +func (s *noObjectivesSummary) Desc() *Desc { + return s.desc +} + +func (s *noObjectivesSummary) Observe(v float64) { + // We increment h.countAndHotIdx so that the counter in the lower + // 63 bits gets incremented. At the same time, we get the new value + // back, which we can use to find the currently-hot counts. + n := atomic.AddUint64(&s.countAndHotIdx, 1) + hotCounts := s.counts[n>>63] + + for { + oldBits := atomic.LoadUint64(&hotCounts.sumBits) + newBits := math.Float64bits(math.Float64frombits(oldBits) + v) + if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { + break + } + } + // Increment count last as we take it as a signal that the observation + // is complete. + atomic.AddUint64(&hotCounts.count, 1) +} + +func (s *noObjectivesSummary) Write(out *dto.Metric) error { + // For simplicity, we protect this whole method by a mutex. It is not in + // the hot path, i.e. Observe is called much more often than Write. The + // complication of making Write lock-free isn't worth it, if possible at + // all. + s.writeMtx.Lock() + defer s.writeMtx.Unlock() + + // Adding 1<<63 switches the hot index (from 0 to 1 or from 1 to 0) + // without touching the count bits. See the struct comments for a full + // description of the algorithm. + n := atomic.AddUint64(&s.countAndHotIdx, 1<<63) + // count is contained unchanged in the lower 63 bits. + count := n & ((1 << 63) - 1) + // The most significant bit tells us which counts is hot. The complement + // is thus the cold one. + hotCounts := s.counts[n>>63] + coldCounts := s.counts[(^n)>>63] + + // Await cooldown. + for count != atomic.LoadUint64(&coldCounts.count) { + runtime.Gosched() // Let observations get work done. + } + + sum := &dto.Summary{ + SampleCount: proto.Uint64(count), + SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + } + + out.Summary = sum + out.Label = s.labelPairs + + // Finally add all the cold counts to the new hot counts and reset the cold counts. + atomic.AddUint64(&hotCounts.count, count) + atomic.StoreUint64(&coldCounts.count, 0) + for { + oldBits := atomic.LoadUint64(&hotCounts.sumBits) + newBits := math.Float64bits(math.Float64frombits(oldBits) + sum.GetSampleSum()) + if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { + atomic.StoreUint64(&coldCounts.sumBits, 0) + break + } + } + return nil +} + type quantSort []*dto.Quantile func (s quantSort) Len() int { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go index b8fc5f18c8..8d5f105233 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/timer.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go @@ -39,13 +39,16 @@ func NewTimer(o Observer) *Timer { // ObserveDuration records the duration passed since the Timer was created with // NewTimer. It calls the Observe method of the Observer provided during -// construction with the duration in seconds as an argument. ObserveDuration is -// usually called with a defer statement. +// construction with the duration in seconds as an argument. The observed +// duration is also returned. ObserveDuration is usually called with a defer +// statement. // // Note that this method is only guaranteed to never observe negative durations // if used with Go1.9+. -func (t *Timer) ObserveDuration() { +func (t *Timer) ObserveDuration() time.Duration { + d := time.Since(t.begin) if t.observer != nil { - t.observer.Observe(time.Since(t.begin).Seconds()) + t.observer.Observe(d.Seconds()) } + return d } diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go index 648b38cb65..26e92288c7 100644 --- a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go +++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go @@ -1,12 +1,12 @@ /* +Copyright (c) 2011, Open Knowledge Foundation Ltd. +All rights reserved. + HTTP Content-Type Autonegotiation. The functions in this package implement the behaviour specified in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html -Copyright (c) 2011, Open Knowledge Foundation Ltd. -All rights reserved. - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go index f7250909b9..00804b7fed 100644 --- a/vendor/github.com/prometheus/common/model/metric.go +++ b/vendor/github.com/prometheus/common/model/metric.go @@ -21,7 +21,6 @@ import ( ) var ( - separator = []byte{0} // MetricNameRE is a regular expression matching valid metric // names. Note that the IsValidMetricName function performs the same // check but faster than a match with this regular expression. diff --git a/vendor/github.com/prometheus/procfs/.golangci.yml b/vendor/github.com/prometheus/procfs/.golangci.yml new file mode 100644 index 0000000000..438ca92eca --- /dev/null +++ b/vendor/github.com/prometheus/procfs/.golangci.yml @@ -0,0 +1,6 @@ +# Run only staticcheck for now. Additional linters will be enabled one-by-one. +linters: + enable: + - staticcheck + - govet + disable-all: true diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md index 35993c41c2..56ba67d3e3 100644 --- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md +++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md @@ -1 +1,2 @@ -* Tobias Schmidt +* Johannes 'fish' Ziemke @discordianfish +* Paul Gier @pgier diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile index 4d10983946..314d1ba568 100644 --- a/vendor/github.com/prometheus/procfs/Makefile +++ b/vendor/github.com/prometheus/procfs/Makefile @@ -11,67 +11,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Ensure GOBIN is not set during build so that promu is installed to the correct path -unexport GOBIN - -GO ?= go -GOFMT ?= $(GO)fmt -FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) -STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck -pkgs = $(shell $(GO) list ./... | grep -v /vendor/) - -PREFIX ?= $(shell pwd) -BIN_DIR ?= $(shell pwd) - -ifdef DEBUG - bindata_flags = -debug -endif - -STATICCHECK_IGNORE = - -all: format staticcheck build test - -style: - @echo ">> checking code style" - @! $(GOFMT) -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^' - -check_license: - @echo ">> checking license header" - @./scripts/check_license.sh - -test: fixtures/.unpacked sysfs/fixtures/.unpacked - @echo ">> running all tests" - @$(GO) test -race $(shell $(GO) list ./... | grep -v /vendor/ | grep -v examples) - -format: - @echo ">> formatting code" - @$(GO) fmt $(pkgs) - -vet: - @echo ">> vetting code" - @$(GO) vet $(pkgs) - -staticcheck: $(STATICCHECK) - @echo ">> running staticcheck" - @$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) +include Makefile.common %/.unpacked: %.ttar ./ttar -C $(dir $*) -x -f $*.ttar touch $@ -update_fixtures: fixtures.ttar sysfs/fixtures.ttar +update_fixtures: + rm -vf fixtures/.unpacked + ./ttar -c -f fixtures.ttar fixtures/ -%fixtures.ttar: %/fixtures - rm -v $(dir $*)fixtures/.unpacked - ./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/ +.PHONY: build +build: -$(FIRST_GOPATH)/bin/staticcheck: - @GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck - -.PHONY: all style check_license format test vet staticcheck - -# Declaring the binaries at their default locations as PHONY targets is a hack -# to ensure the latest version is downloaded on every make execution. -# If this is not desired, copy/symlink these binaries to a different path and -# set the respective environment variables. -.PHONY: $(GOPATH)/bin/staticcheck +.PHONY: test +test: fixtures/.unpacked common-test diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common new file mode 100644 index 0000000000..4f18ea5877 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -0,0 +1,272 @@ +# Copyright 2018 The Prometheus 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. + + +# A common Makefile that includes rules to be reused in different prometheus projects. +# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! + +# Example usage : +# Create the main Makefile in the root project directory. +# include Makefile.common +# customTarget: +# @echo ">> Running customTarget" +# + +# Ensure GOBIN is not set during build so that promu is installed to the correct path +unexport GOBIN + +GO ?= go +GOFMT ?= $(GO)fmt +FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) +GOOPTS ?= +GOHOSTOS ?= $(shell $(GO) env GOHOSTOS) +GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH) + +GO_VERSION ?= $(shell $(GO) version) +GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) +PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') + +GOVENDOR := +GO111MODULE := +ifeq (, $(PRE_GO_111)) + ifneq (,$(wildcard go.mod)) + # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). + GO111MODULE := on + + ifneq (,$(wildcard vendor)) + # Always use the local vendor/ directory to satisfy the dependencies. + GOOPTS := $(GOOPTS) -mod=vendor + endif + endif +else + ifneq (,$(wildcard go.mod)) + ifneq (,$(wildcard vendor)) +$(warning This repository requires Go >= 1.11 because of Go modules) +$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') + endif + else + # This repository isn't using Go modules (yet). + GOVENDOR := $(FIRST_GOPATH)/bin/govendor + endif +endif +PROMU := $(FIRST_GOPATH)/bin/promu +pkgs = ./... + +ifeq (arm, $(GOHOSTARCH)) + GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM) + GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM) +else + GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH) +endif + +PROMU_VERSION ?= 0.3.0 +PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz + +GOLANGCI_LINT := +GOLANGCI_LINT_OPTS ?= +GOLANGCI_LINT_VERSION ?= v1.16.0 +# golangci-lint only supports linux, darwin and windows platforms on i386/amd64. +# windows isn't included here because of the path separator being different. +ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) + ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) + GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint + endif +endif + +PREFIX ?= $(shell pwd) +BIN_DIR ?= $(shell pwd) +DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) +DOCKER_REPO ?= prom + +DOCKER_ARCHS ?= amd64 + +BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) +PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) +TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) + +ifeq ($(GOHOSTARCH),amd64) + ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows)) + # Only supported on amd64 + test-flags := -race + endif +endif + +# This rule is used to forward a target like "build" to "common-build". This +# allows a new "build" target to be defined in a Makefile which includes this +# one and override "common-build" without override warnings. +%: common-% ; + +.PHONY: common-all +common-all: precheck style check_license lint unused build test + +.PHONY: common-style +common-style: + @echo ">> checking code style" + @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ + if [ -n "$${fmtRes}" ]; then \ + echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ + echo "Please ensure you are using $$($(GO) version) for formatting code."; \ + exit 1; \ + fi + +.PHONY: common-check_license +common-check_license: + @echo ">> checking license header" + @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ + awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ + done); \ + if [ -n "$${licRes}" ]; then \ + echo "license header checking failed:"; echo "$${licRes}"; \ + exit 1; \ + fi + +.PHONY: common-deps +common-deps: + @echo ">> getting dependencies" +ifdef GO111MODULE + GO111MODULE=$(GO111MODULE) $(GO) mod download +else + $(GO) get $(GOOPTS) -t ./... +endif + +.PHONY: common-test-short +common-test-short: + @echo ">> running short tests" + GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs) + +.PHONY: common-test +common-test: + @echo ">> running all tests" + GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs) + +.PHONY: common-format +common-format: + @echo ">> formatting code" + GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs) + +.PHONY: common-vet +common-vet: + @echo ">> vetting code" + GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) + +.PHONY: common-lint +common-lint: $(GOLANGCI_LINT) +ifdef GOLANGCI_LINT + @echo ">> running golangci-lint" +ifdef GO111MODULE +# 'go list' needs to be executed before staticcheck to prepopulate the modules cache. +# Otherwise staticcheck might fail randomly for some reason not yet explained. + GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null + GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) +else + $(GOLANGCI_LINT) run $(pkgs) +endif +endif + +# For backward-compatibility. +.PHONY: common-staticcheck +common-staticcheck: lint + +.PHONY: common-unused +common-unused: $(GOVENDOR) +ifdef GOVENDOR + @echo ">> running check for unused packages" + @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' +else +ifdef GO111MODULE + @echo ">> running check for unused/missing packages in go.mod" + GO111MODULE=$(GO111MODULE) $(GO) mod tidy +ifeq (,$(wildcard vendor)) + @git diff --exit-code -- go.sum go.mod +else + @echo ">> running check for unused packages in vendor/" + GO111MODULE=$(GO111MODULE) $(GO) mod vendor + @git diff --exit-code -- go.sum go.mod vendor/ +endif +endif +endif + +.PHONY: common-build +common-build: promu + @echo ">> building binaries" + GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) + +.PHONY: common-tarball +common-tarball: promu + @echo ">> building release tarball" + $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) + +.PHONY: common-docker $(BUILD_DOCKER_ARCHS) +common-docker: $(BUILD_DOCKER_ARCHS) +$(BUILD_DOCKER_ARCHS): common-docker-%: + docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \ + --build-arg ARCH="$*" \ + --build-arg OS="linux" \ + . + +.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS) +common-docker-publish: $(PUBLISH_DOCKER_ARCHS) +$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: + docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" + +.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS) +common-docker-tag-latest: $(TAG_DOCKER_ARCHS) +$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" + +.PHONY: common-docker-manifest +common-docker-manifest: + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG)) + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" + +.PHONY: promu +promu: $(PROMU) + +$(PROMU): + $(eval PROMU_TMP := $(shell mktemp -d)) + curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP) + mkdir -p $(FIRST_GOPATH)/bin + cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu + rm -r $(PROMU_TMP) + +.PHONY: proto +proto: + @echo ">> generating code from proto files" + @./scripts/genproto.sh + +ifdef GOLANGCI_LINT +$(GOLANGCI_LINT): + mkdir -p $(FIRST_GOPATH)/bin + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) +endif + +ifdef GOVENDOR +.PHONY: $(GOVENDOR) +$(GOVENDOR): + GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor +endif + +.PHONY: precheck +precheck:: + +define PRECHECK_COMMAND_template = +precheck:: $(1)_precheck + +PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) +.PHONY: $(1)_precheck +$(1)_precheck: + @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ + echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ + exit 1; \ + fi +endef diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go index d3a8268078..5cd22a837f 100644 --- a/vendor/github.com/prometheus/procfs/buddyinfo.go +++ b/vendor/github.com/prometheus/procfs/buddyinfo.go @@ -43,7 +43,7 @@ func NewBuddyInfo() ([]BuddyInfo, error) { // NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem. func (fs FS) NewBuddyInfo() ([]BuddyInfo, error) { - file, err := os.Open(fs.Path("buddyinfo")) + file, err := os.Open(fs.proc.Path("buddyinfo")) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/fixtures.ttar index 13c831ef59..f7f84ef362 100644 --- a/vendor/github.com/prometheus/procfs/fixtures.ttar +++ b/vendor/github.com/prometheus/procfs/fixtures.ttar @@ -1,45 +1,48 @@ # Archive created by ttar -c -f fixtures.ttar fixtures/ Directory: fixtures +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/proc Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/26231 +Directory: fixtures/proc/26231 Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/cmdline +Path: fixtures/proc/26231/cmdline Lines: 1 vimNULLBYTEtest.goNULLBYTE+10NULLBYTEEOF Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/comm +Path: fixtures/proc/26231/comm Lines: 1 vim Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/cwd +Path: fixtures/proc/26231/cwd SymlinkTo: /usr/bin # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/exe +Path: fixtures/proc/26231/exe SymlinkTo: /usr/bin/vim # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/26231/fd +Directory: fixtures/proc/26231/fd Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/fd/0 +Path: fixtures/proc/26231/fd/0 SymlinkTo: ../../symlinktargets/abc # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/fd/1 +Path: fixtures/proc/26231/fd/1 SymlinkTo: ../../symlinktargets/def # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/fd/10 +Path: fixtures/proc/26231/fd/10 SymlinkTo: ../../symlinktargets/xyz # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/fd/2 +Path: fixtures/proc/26231/fd/2 SymlinkTo: ../../symlinktargets/ghi # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/fd/3 +Path: fixtures/proc/26231/fd/3 SymlinkTo: ../../symlinktargets/uvw # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/io +Path: fixtures/proc/26231/io Lines: 7 rchar: 750339 wchar: 818609 @@ -50,7 +53,7 @@ write_bytes: 2048 cancelled_write_bytes: -1024 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/limits +Path: fixtures/proc/26231/limits Lines: 17 Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds @@ -71,7 +74,7 @@ Max realtime priority 0 0 Max realtime timeout unlimited unlimited us Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/mountstats +Path: fixtures/proc/26231/mountstats Lines: 19 device rootfs mounted on / with fstype rootfs device sysfs mounted on /sys with fstype sysfs @@ -94,10 +97,10 @@ device 192.168.1.1:/srv/test mounted on /mnt/nfs/test with fstype nfs4 statvers= Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/26231/net +Directory: fixtures/proc/26231/net Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/net/dev +Path: fixtures/proc/26231/net/dev Lines: 4 Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed @@ -105,57 +108,57 @@ Inter-| Receive | Transmit eth0: 438 5 0 0 0 0 0 0 648 8 0 0 0 0 0 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/26231/ns +Directory: fixtures/proc/26231/ns Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/ns/mnt +Path: fixtures/proc/26231/ns/mnt SymlinkTo: mnt:[4026531840] # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/ns/net +Path: fixtures/proc/26231/ns/net SymlinkTo: net:[4026531993] # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/root +Path: fixtures/proc/26231/root SymlinkTo: / # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26231/stat +Path: fixtures/proc/26231/stat Lines: 1 26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/26232 +Directory: fixtures/proc/26232 Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/cmdline +Path: fixtures/proc/26232/cmdline Lines: 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/comm +Path: fixtures/proc/26232/comm Lines: 1 ata_sff Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/cwd +Path: fixtures/proc/26232/cwd SymlinkTo: /does/not/exist # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/26232/fd +Directory: fixtures/proc/26232/fd Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/fd/0 +Path: fixtures/proc/26232/fd/0 SymlinkTo: ../../symlinktargets/abc # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/fd/1 +Path: fixtures/proc/26232/fd/1 SymlinkTo: ../../symlinktargets/def # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/fd/2 +Path: fixtures/proc/26232/fd/2 SymlinkTo: ../../symlinktargets/ghi # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/fd/3 +Path: fixtures/proc/26232/fd/3 SymlinkTo: ../../symlinktargets/uvw # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/fd/4 +Path: fixtures/proc/26232/fd/4 SymlinkTo: ../../symlinktargets/xyz # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/limits +Path: fixtures/proc/26232/limits Lines: 17 Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds @@ -176,71 +179,98 @@ Max realtime priority 0 0 Max realtime timeout unlimited unlimited us Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/root +Path: fixtures/proc/26232/root SymlinkTo: /does/not/exist # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26232/stat +Path: fixtures/proc/26232/stat Lines: 1 33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/26233 +Directory: fixtures/proc/26233 Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/26233/cmdline +Path: fixtures/proc/26233/cmdline Lines: 1 com.github.uiautomatorNULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTEEOF Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/584 +Directory: fixtures/proc/584 Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/584/stat +Path: fixtures/proc/584/stat Lines: 2 1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0 #!/bin/cat /proc/self/stat Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/buddyinfo -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/buddyinfo/short -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/buddyinfo/short/buddyinfo -Lines: 3 -Node 0, zone -Node 0, zone -Node 0, zone -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/buddyinfo/sizemismatch -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/buddyinfo/sizemismatch/buddyinfo -Lines: 3 -Node 0, zone DMA 1 0 1 0 2 1 1 0 1 1 3 -Node 0, zone DMA32 759 572 791 475 194 45 12 0 0 0 0 0 -Node 0, zone Normal 4381 1093 185 1530 567 102 4 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/buddyinfo/valid -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/buddyinfo/valid/buddyinfo +Path: fixtures/proc/buddyinfo Lines: 3 Node 0, zone DMA 1 0 1 0 2 1 1 0 1 1 3 Node 0, zone DMA32 759 572 791 475 194 45 12 0 0 0 0 Node 0, zone Normal 4381 1093 185 1530 567 102 4 0 0 0 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/fs +Path: fixtures/proc/diskstats +Lines: 49 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 7 0 loop0 0 0 0 0 0 0 0 0 0 0 0 + 7 1 loop1 0 0 0 0 0 0 0 0 0 0 0 + 7 2 loop2 0 0 0 0 0 0 0 0 0 0 0 + 7 3 loop3 0 0 0 0 0 0 0 0 0 0 0 + 7 4 loop4 0 0 0 0 0 0 0 0 0 0 0 + 7 5 loop5 0 0 0 0 0 0 0 0 0 0 0 + 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0 + 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 25354637 34367663 1003346126 18492372 28444756 11134226 505697032 63877960 0 9653880 82621804 + 8 1 sda1 250 0 2000 36 0 0 0 0 0 36 36 + 8 2 sda2 246 0 1968 32 0 0 0 0 0 32 32 + 8 3 sda3 340 13 2818 52 11 8 152 8 0 56 60 + 8 4 sda4 25353629 34367650 1003337964 18492232 27448755 11134218 505696880 61593380 0 7576432 80332428 + 252 0 dm-0 59910002 0 1003337218 46229572 39231014 0 505696880 1158557800 0 11325968 1206301256 + 252 1 dm-1 388 0 3104 84 74 0 592 0 0 76 84 + 252 2 dm-2 11571 0 308350 6536 153522 0 5093416 122884 0 65400 129416 + 252 3 dm-3 3870 0 3870 104 0 0 0 0 0 16 104 + 252 4 dm-4 392 0 1034 28 38 0 137 16 0 24 44 + 252 5 dm-5 3729 0 84279 924 98918 0 1151688 104684 0 58848 105632 + 179 0 mmcblk0 192 3 1560 156 0 0 0 0 0 136 156 + 179 1 mmcblk0p1 17 3 160 24 0 0 0 0 0 24 24 + 179 2 mmcblk0p2 95 0 760 68 0 0 0 0 0 68 68 + 2 0 fd0 2 0 16 80 0 0 0 0 0 80 80 + 254 0 vda 1775784 15386 32670882 8655768 6038856 20711856 213637440 2069221364 0 41614592 2077872228 + 254 1 vda1 668 85 5984 956 207 4266 35784 32772 0 8808 33720 + 254 2 vda2 1774936 15266 32663262 8654692 5991028 20707590 213601656 2069152216 0 41607628 2077801992 + 11 0 sr0 0 0 0 0 0 0 0 0 0 0 0 + 259 0 nvme0n1 47114 4 4643973 21650 1078320 43950 39451633 1011053 0 222766 1032546 + 259 1 nvme0n1p1 1140 0 9370 16 1 0 1 0 0 16 16 + 259 2 nvme0n1p2 45914 4 4631243 21626 1036885 43950 39451632 919480 0 131580 940970 + 8 0 sdb 326552 841 9657779 84 41822 2895 1972905 5007 0 60730 67070 68851 0 1925173784 11130 + 8 1 sdb1 231 3 34466 4 24 23 106 0 0 64 64 0 0 0 0 + 8 2 sdb2 326310 838 9622281 67 40726 2872 1972799 4924 0 58250 64567 68851 0 1925173784 11130 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/proc/fs Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/fs/xfs +Directory: fixtures/proc/fs/xfs Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/fs/xfs/stat +Path: fixtures/proc/fs/xfs/stat Lines: 23 extent_alloc 92447 97589 92448 93751 abt 0 0 0 0 @@ -267,7 +297,7 @@ xpc 399724544 92823103 86219234 debug 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/mdstat +Path: fixtures/proc/mdstat Lines: 26 Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10] md3 : active raid6 sda1[8] sdh1[7] sdg1[6] sdf1[5] sde1[11] sdd1[3] sdc1[10] sdb1[9] @@ -297,10 +327,10 @@ md7 : active raid6 sdb1[0] sde1[3] sdd1[2] sdc1[1] unused devices: Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/net +Directory: fixtures/proc/net Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/net/dev +Path: fixtures/proc/net/dev Lines: 6 Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed @@ -310,7 +340,7 @@ docker0: 2568 38 0 0 0 0 0 0 438 eth0: 874354587 1036395 0 0 0 0 0 0 563352563 732147 0 0 0 0 0 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/net/ip_vs +Path: fixtures/proc/net/ip_vs Lines: 21 IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags @@ -335,7 +365,7 @@ FWM 10001000 wlc -> C0A83215:0CEA Route 0 0 2 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/net/ip_vs_stats +Path: fixtures/proc/net/ip_vs_stats Lines: 6 Total Incoming Outgoing Incoming Outgoing Conns Packets Packets Bytes Bytes @@ -345,10 +375,10 @@ Lines: 6 4 1FB3C 0 1282A8F 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/net/rpc +Directory: fixtures/proc/net/rpc Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/net/rpc/nfs +Path: fixtures/proc/net/rpc/nfs Lines: 5 net 18628 0 18628 6 rpc 4329785 0 4338291 @@ -357,7 +387,7 @@ proc3 22 1 4084749 29200 94754 32580 186 47747 7981 8639 0 6356 0 6962 0 7958 0 proc4 61 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/net/rpc/nfsd +Path: fixtures/proc/net/rpc/nfsd Lines: 11 rc 0 6 18622 fh 0 0 0 0 0 @@ -372,7 +402,7 @@ proc4 2 2 10853 proc4ops 72 0 0 0 1098 2 0 0 0 0 8179 5896 0 0 0 0 5900 0 0 2 0 2 0 9609 0 2 150 1272 0 0 0 1236 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/net/xfrm_stat +Path: fixtures/proc/net/xfrm_stat Lines: 28 XfrmInError 1 XfrmInBufferError 2 @@ -404,10 +434,30 @@ XfrmOutStateInvalid 28765 XfrmAcquireError 24532 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/self +Directory: fixtures/proc/pressure +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/pressure/cpu +Lines: 1 +some avg10=0.10 avg60=2.00 avg300=3.85 total=15 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/pressure/io +Lines: 2 +some avg10=0.10 avg60=2.00 avg300=3.85 total=15 +full avg10=0.20 avg60=3.00 avg300=4.95 total=25 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/pressure/memory +Lines: 2 +some avg10=0.10 avg60=2.00 avg300=3.85 total=15 +full avg10=0.20 avg60=3.00 avg300=4.95 total=25 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/self SymlinkTo: 26231 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/stat +Path: fixtures/proc/stat Lines: 16 cpu 301854 612 111922 8979004 3552 2 3944 0 0 0 cpu0 44490 19 21045 1087069 220 1 3410 0 0 0 @@ -427,36 +477,1238 @@ procs_blocked 1 softirq 5057579 250191 1481983 1647 211099 186066 0 1783454 622196 12499 508444 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/symlinktargets +Directory: fixtures/proc/symlinktargets Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/symlinktargets/README +Path: fixtures/proc/symlinktargets/README Lines: 2 This directory contains some empty files that are the symlinks the files in the "fd" directory point to. They are otherwise ignored by the tests Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/symlinktargets/abc +Path: fixtures/proc/symlinktargets/abc Lines: 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/symlinktargets/def +Path: fixtures/proc/symlinktargets/def Lines: 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/symlinktargets/ghi +Path: fixtures/proc/symlinktargets/ghi Lines: 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/symlinktargets/uvw +Path: fixtures/proc/symlinktargets/uvw Lines: 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/symlinktargets/xyz +Path: fixtures/proc/symlinktargets/xyz Lines: 0 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/.unpacked -Lines: 0 +Directory: fixtures/sys +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/block +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/block/dm-0 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/block/dm-0/stat +Lines: 1 +6447303 0 710266738 1529043 953216 0 31201176 4557464 0 796160 6088971 Mode: 664 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/block/sda +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/block/sda/stat +Lines: 1 +9652963 396792 759304206 412943 8422549 6731723 286915323 13947418 0 5658367 19174573 1 2 3 12 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/net +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/net/eth0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/addr_assign_type +Lines: 1 +3 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/addr_len +Lines: 1 +6 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/address +Lines: 1 +01:01:01:01:01:01 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/broadcast +Lines: 1 +ff:ff:ff:ff:ff:ff +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/carrier +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/carrier_changes +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/carrier_down_count +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/carrier_up_count +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/dev_id +Lines: 1 +0x20 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/dormant +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/duplex +Lines: 1 +full +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/flags +Lines: 1 +0x1303 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/ifalias +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/ifindex +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/iflink +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/link_mode +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/mtu +Lines: 1 +1500 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/name_assign_type +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/netdev_group +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/operstate +Lines: 1 +up +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/phys_port_id +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/phys_port_name +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/phys_switch_id +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/speed +Lines: 1 +1000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/tx_queue_len +Lines: 1 +1000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/type +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/power_supply +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/power_supply/AC +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/AC/online +Lines: 1 +0 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/AC/type +Lines: 1 +Mains +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/AC/uevent +Lines: 2 +POWER_SUPPLY_NAME=AC +POWER_SUPPLY_ONLINE=0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/power_supply/BAT0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/alarm +Lines: 1 +2503000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/capacity +Lines: 1 +98 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/capacity_level +Lines: 1 +Normal +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/charge_start_threshold +Lines: 1 +95 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/charge_stop_threshold +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/cycle_count +Lines: 1 +0 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/energy_full +Lines: 1 +50060000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/energy_full_design +Lines: 1 +47520000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/energy_now +Lines: 1 +49450000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/manufacturer +Lines: 1 +LGC +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/model_name +Lines: 1 +LNV-45N1 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/power_now +Lines: 1 +4830000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/present +Lines: 1 +1 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/serial_number +Lines: 1 +38109 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/status +Lines: 1 +Discharging +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/technology +Lines: 1 +Li-ion +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/type +Lines: 1 +Battery +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/uevent +Lines: 16 +POWER_SUPPLY_NAME=BAT0 +POWER_SUPPLY_STATUS=Discharging +POWER_SUPPLY_PRESENT=1 +POWER_SUPPLY_TECHNOLOGY=Li-ion +POWER_SUPPLY_CYCLE_COUNT=0 +POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000 +POWER_SUPPLY_VOLTAGE_NOW=12229000 +POWER_SUPPLY_POWER_NOW=4830000 +POWER_SUPPLY_ENERGY_FULL_DESIGN=47520000 +POWER_SUPPLY_ENERGY_FULL=50060000 +POWER_SUPPLY_ENERGY_NOW=49450000 +POWER_SUPPLY_CAPACITY=98 +POWER_SUPPLY_CAPACITY_LEVEL=Normal +POWER_SUPPLY_MODEL_NAME=LNV-45N1 +POWER_SUPPLY_MANUFACTURER=LGC +POWER_SUPPLY_SERIAL_NUMBER=38109 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/voltage_min_design +Lines: 1 +10800000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/power_supply/BAT0/voltage_now +Lines: 1 +12229000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/thermal +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/thermal/thermal_zone0 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone0/policy +Lines: 1 +step_wise +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone0/temp +Lines: 1 +49925 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone0/type +Lines: 1 +bcm2835_thermal +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/thermal/thermal_zone1 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone1/mode +Lines: 1 +enabled +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone1/passive +Lines: 1 +0 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone1/policy +Lines: 1 +step_wise +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone1/temp +Lines: 1 +44000 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/thermal/thermal_zone1/type +Lines: 1 +acpitz +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/dirty_data +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_hit_ratio +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_hits +Lines: 1 +289 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_hit_ratio +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_hit_ratio +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_hit_ratio +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_hits +Lines: 1 +546 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/io_errors +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/metadata_written +Lines: 1 +512 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/priority_stats +Lines: 5 +Unused: 99% +Metadata: 0% +Average: 10473 +Sectors per Q: 64 +Quantiles: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946] +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/written +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system/cpu +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system/cpu/cpu0 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu0/cpufreq +SymlinkTo: ../cpufreq/policy0 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system/cpu/cpu1 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system/cpu/cpu1/cpufreq +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq +Lines: 1 +1200195 +Mode: 400 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq +Lines: 1 +3300000 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_min_freq +Lines: 1 +1200000 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_transition_latency +Lines: 1 +4294967295 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/related_cpus +Lines: 1 +1 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_available_governors +Lines: 1 +performance powersave +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_driver +Lines: 1 +intel_pstate +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_governor +Lines: 1 +powersave +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq +Lines: 1 +3300000 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq +Lines: 1 +1200000 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed +Lines: 1 + +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system/cpu/cpufreq +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system/cpu/cpufreq/policy0 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/affected_cpus +Lines: 1 +0 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq +Lines: 1 +2400000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq +Lines: 1 +800000 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_transition_latency +Lines: 1 +0 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/related_cpus +Lines: 1 +0 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_available_governors +Lines: 1 +performance powersave +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq +Lines: 1 +1219917 +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_driver +Lines: 1 +intel_pstate +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_governor +Lines: 1 +powersave +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq +Lines: 1 +2400000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq +Lines: 1 +800000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed +Lines: 1 + +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/devices/system/cpu/cpufreq/policy1 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/average_key_size +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0 +Mode: 777 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/dirty_data +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_hit_ratio +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_hits +Lines: 1 +289 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_hit_ratio +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_hit_ratio +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_hit_ratio +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_hits +Lines: 1 +546 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/btree_cache_size +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0 +Mode: 777 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/io_errors +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/metadata_written +Lines: 1 +512 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/priority_stats +Lines: 5 +Unused: 99% +Metadata: 0% +Average: 10473 +Sectors per Q: 64 +Quantiles: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946] +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/written +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache_available_percent +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/congested +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/active_journal_entries +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/btree_nodes +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/btree_read_average_duration_us +Lines: 1 +1305 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/cache_read_races +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/root_usage_percent +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_hit_ratio +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_hits +Lines: 1 +289 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_hit_ratio +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_hit_ratio +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/bypassed +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_bypass_hits +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_bypass_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_hit_ratio +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_hits +Lines: 1 +546 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_miss_collisions +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_misses +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_readaheads +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/tree_depth +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/xfs +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/xfs/sda1 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/xfs/sda1/stats +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/xfs/sda1/stats/stats +Lines: 1 +extent_alloc 1 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/xfs/sdb1 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/fs/xfs/sdb1/stats +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/fs/xfs/sdb1/stats/stats +Lines: 1 +extent_alloc 2 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/github.com/prometheus/procfs/fs.go b/vendor/github.com/prometheus/procfs/fs.go index b6c6b2ce1f..9c56c83954 100644 --- a/vendor/github.com/prometheus/procfs/fs.go +++ b/vendor/github.com/prometheus/procfs/fs.go @@ -14,69 +14,24 @@ package procfs import ( - "fmt" - "os" - "path" - - "github.com/prometheus/procfs/nfs" - "github.com/prometheus/procfs/xfs" + "github.com/prometheus/procfs/internal/fs" ) -// FS represents the pseudo-filesystem proc, which provides an interface to +// FS represents the pseudo-filesystem sys, which provides an interface to // kernel data structures. -type FS string +type FS struct { + proc fs.FS +} // DefaultMountPoint is the common mount point of the proc filesystem. -const DefaultMountPoint = "/proc" +const DefaultMountPoint = fs.DefaultProcMountPoint -// NewFS returns a new FS mounted under the given mountPoint. It will error -// if the mount point can't be read. +// NewFS returns a new proc FS mounted under the given proc mountPoint. It will error +// if the mount point dirctory can't be read or is a file. func NewFS(mountPoint string) (FS, error) { - info, err := os.Stat(mountPoint) + fs, err := fs.NewFS(mountPoint) if err != nil { - return "", fmt.Errorf("could not read %s: %s", mountPoint, err) + return FS{}, err } - if !info.IsDir() { - return "", fmt.Errorf("mount point %s is not a directory", mountPoint) - } - - return FS(mountPoint), nil -} - -// Path returns the path of the given subsystem relative to the procfs root. -func (fs FS) Path(p ...string) string { - return path.Join(append([]string{string(fs)}, p...)...) -} - -// XFSStats retrieves XFS filesystem runtime statistics. -func (fs FS) XFSStats() (*xfs.Stats, error) { - f, err := os.Open(fs.Path("fs/xfs/stat")) - if err != nil { - return nil, err - } - defer f.Close() - - return xfs.ParseStats(f) -} - -// NFSClientRPCStats retrieves NFS client RPC statistics. -func (fs FS) NFSClientRPCStats() (*nfs.ClientRPCStats, error) { - f, err := os.Open(fs.Path("net/rpc/nfs")) - if err != nil { - return nil, err - } - defer f.Close() - - return nfs.ParseClientRPCStats(f) -} - -// NFSdServerRPCStats retrieves NFS daemon RPC statistics. -func (fs FS) NFSdServerRPCStats() (*nfs.ServerRPCStats, error) { - f, err := os.Open(fs.Path("net/rpc/nfsd")) - if err != nil { - return nil, err - } - defer f.Close() - - return nfs.ParseServerRPCStats(f) + return FS{fs}, nil } diff --git a/vendor/github.com/prometheus/procfs/go.mod b/vendor/github.com/prometheus/procfs/go.mod new file mode 100644 index 0000000000..8a1b839fd2 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/go.mod @@ -0,0 +1,3 @@ +module github.com/prometheus/procfs + +require golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 diff --git a/vendor/github.com/prometheus/procfs/go.sum b/vendor/github.com/prometheus/procfs/go.sum new file mode 100644 index 0000000000..7827dd3d56 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/vendor/github.com/prometheus/procfs/internal/fs/fs.go b/vendor/github.com/prometheus/procfs/internal/fs/fs.go new file mode 100644 index 0000000000..c66a1cf80e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/internal/fs/fs.go @@ -0,0 +1,52 @@ +// Copyright 2019 The Prometheus 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 fs + +import ( + "fmt" + "os" + "path/filepath" +) + +const ( + // DefaultProcMountPoint is the common mount point of the proc filesystem. + DefaultProcMountPoint = "/proc" + + // DefaultSysMountPoint is the common mount point of the sys filesystem. + DefaultSysMountPoint = "/sys" +) + +// FS represents a pseudo-filesystem, normally /proc or /sys, which provides an +// interface to kernel data structures. +type FS string + +// NewFS returns a new FS mounted under the given mountPoint. It will error +// if the mount point can't be read. +func NewFS(mountPoint string) (FS, error) { + info, err := os.Stat(mountPoint) + if err != nil { + return "", fmt.Errorf("could not read %s: %s", mountPoint, err) + } + if !info.IsDir() { + return "", fmt.Errorf("mount point %s is not a directory", mountPoint) + } + + return FS(mountPoint), nil +} + +// Path appends the given path elements to the filesystem path, adding separators +// as necessary. +func (fs FS) Path(p ...string) string { + return filepath.Join(append([]string{string(fs)}, p...)...) +} diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go deleted file mode 100644 index 2ff228e9d1..0000000000 --- a/vendor/github.com/prometheus/procfs/internal/util/parse.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018 The Prometheus 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 util - -import ( - "io/ioutil" - "strconv" - "strings" -) - -// ParseUint32s parses a slice of strings into a slice of uint32s. -func ParseUint32s(ss []string) ([]uint32, error) { - us := make([]uint32, 0, len(ss)) - for _, s := range ss { - u, err := strconv.ParseUint(s, 10, 32) - if err != nil { - return nil, err - } - - us = append(us, uint32(u)) - } - - return us, nil -} - -// ParseUint64s parses a slice of strings into a slice of uint64s. -func ParseUint64s(ss []string) ([]uint64, error) { - us := make([]uint64, 0, len(ss)) - for _, s := range ss { - u, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return nil, err - } - - us = append(us, u) - } - - return us, nil -} - -// ReadUintFromFile reads a file and attempts to parse a uint64 from it. -func ReadUintFromFile(path string) (uint64, error) { - data, err := ioutil.ReadFile(path) - if err != nil { - return 0, err - } - return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) -} diff --git a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go deleted file mode 100644 index df0d567b78..0000000000 --- a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Prometheus 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. - -// +build !windows - -package util - -import ( - "bytes" - "os" - "syscall" -) - -// SysReadFile is a simplified ioutil.ReadFile that invokes syscall.Read directly. -// https://github.com/prometheus/node_exporter/pull/728/files -func SysReadFile(file string) (string, error) { - f, err := os.Open(file) - if err != nil { - return "", err - } - defer f.Close() - - // On some machines, hwmon drivers are broken and return EAGAIN. This causes - // Go's ioutil.ReadFile implementation to poll forever. - // - // Since we either want to read data or bail immediately, do the simplest - // possible read using syscall directly. - b := make([]byte, 128) - n, err := syscall.Read(int(f.Fd()), b) - if err != nil { - return "", err - } - - return string(bytes.TrimSpace(b[:n])), nil -} diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go index e36d4a3bd0..41e645d23e 100644 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ b/vendor/github.com/prometheus/procfs/ipvs.go @@ -74,7 +74,7 @@ func NewIPVSStats() (IPVSStats, error) { // NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem. func (fs FS) NewIPVSStats() (IPVSStats, error) { - file, err := os.Open(fs.Path("net/ip_vs_stats")) + file, err := os.Open(fs.proc.Path("net/ip_vs_stats")) if err != nil { return IPVSStats{}, err } @@ -143,7 +143,7 @@ func NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem. func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { - file, err := os.Open(fs.Path("net/ip_vs")) + file, err := os.Open(fs.proc.Path("net/ip_vs")) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go index 9dc19583d8..6ac7a12f97 100644 --- a/vendor/github.com/prometheus/procfs/mdstat.go +++ b/vendor/github.com/prometheus/procfs/mdstat.go @@ -44,7 +44,7 @@ type MDStat struct { // ParseMDStat parses an mdstat-file and returns a struct with the relevant infos. func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { - mdStatusFilePath := fs.Path("mdstat") + mdStatusFilePath := fs.proc.Path("mdstat") content, err := ioutil.ReadFile(mdStatusFilePath) if err != nil { return []MDStat{}, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go index 7a8a1e0990..fc385afcfe 100644 --- a/vendor/github.com/prometheus/procfs/mountstats.go +++ b/vendor/github.com/prometheus/procfs/mountstats.go @@ -69,6 +69,8 @@ type MountStats interface { type MountStatsNFS struct { // The version of statistics provided. StatVersion string + // The optional mountaddr of the NFS mount. + MountAddress string // The age of the NFS mount. Age time.Duration // Statistics related to byte counters for various operations. @@ -317,6 +319,7 @@ func parseMount(ss []string) (*Mount, error) { func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) { // Field indicators for parsing specific types of data const ( + fieldOpts = "opts:" fieldAge = "age:" fieldBytes = "bytes:" fieldEvents = "events:" @@ -338,6 +341,13 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e } switch ss[0] { + case fieldOpts: + for _, opt := range strings.Split(ss[1], ",") { + split := strings.Split(opt, "=") + if len(split) == 2 && split[0] == "mountaddr" { + stats.MountAddress = split[1] + } + } case fieldAge: // Age integer is in seconds d, err := time.ParseDuration(ss[1] + "s") diff --git a/vendor/github.com/prometheus/procfs/net_dev.go b/vendor/github.com/prometheus/procfs/net_dev.go index 3f2523371a..0063594e69 100644 --- a/vendor/github.com/prometheus/procfs/net_dev.go +++ b/vendor/github.com/prometheus/procfs/net_dev.go @@ -59,7 +59,7 @@ func NewNetDev() (NetDev, error) { // NewNetDev returns kernel/system statistics read from /proc/net/dev. func (fs FS) NewNetDev() (NetDev, error) { - return newNetDev(fs.Path("net/dev")) + return newNetDev(fs.proc.Path("net/dev")) } // NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev. diff --git a/vendor/github.com/prometheus/procfs/nfs/nfs.go b/vendor/github.com/prometheus/procfs/nfs/nfs.go deleted file mode 100644 index 651bf68195..0000000000 --- a/vendor/github.com/prometheus/procfs/nfs/nfs.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2018 The Prometheus 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 nfs implements parsing of /proc/net/rpc/nfsd. -// Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/ -package nfs - -// ReplyCache models the "rc" line. -type ReplyCache struct { - Hits uint64 - Misses uint64 - NoCache uint64 -} - -// FileHandles models the "fh" line. -type FileHandles struct { - Stale uint64 - TotalLookups uint64 - AnonLookups uint64 - DirNoCache uint64 - NoDirNoCache uint64 -} - -// InputOutput models the "io" line. -type InputOutput struct { - Read uint64 - Write uint64 -} - -// Threads models the "th" line. -type Threads struct { - Threads uint64 - FullCnt uint64 -} - -// ReadAheadCache models the "ra" line. -type ReadAheadCache struct { - CacheSize uint64 - CacheHistogram []uint64 - NotFound uint64 -} - -// Network models the "net" line. -type Network struct { - NetCount uint64 - UDPCount uint64 - TCPCount uint64 - TCPConnect uint64 -} - -// ClientRPC models the nfs "rpc" line. -type ClientRPC struct { - RPCCount uint64 - Retransmissions uint64 - AuthRefreshes uint64 -} - -// ServerRPC models the nfsd "rpc" line. -type ServerRPC struct { - RPCCount uint64 - BadCnt uint64 - BadFmt uint64 - BadAuth uint64 - BadcInt uint64 -} - -// V2Stats models the "proc2" line. -type V2Stats struct { - Null uint64 - GetAttr uint64 - SetAttr uint64 - Root uint64 - Lookup uint64 - ReadLink uint64 - Read uint64 - WrCache uint64 - Write uint64 - Create uint64 - Remove uint64 - Rename uint64 - Link uint64 - SymLink uint64 - MkDir uint64 - RmDir uint64 - ReadDir uint64 - FsStat uint64 -} - -// V3Stats models the "proc3" line. -type V3Stats struct { - Null uint64 - GetAttr uint64 - SetAttr uint64 - Lookup uint64 - Access uint64 - ReadLink uint64 - Read uint64 - Write uint64 - Create uint64 - MkDir uint64 - SymLink uint64 - MkNod uint64 - Remove uint64 - RmDir uint64 - Rename uint64 - Link uint64 - ReadDir uint64 - ReadDirPlus uint64 - FsStat uint64 - FsInfo uint64 - PathConf uint64 - Commit uint64 -} - -// ClientV4Stats models the nfs "proc4" line. -type ClientV4Stats struct { - Null uint64 - Read uint64 - Write uint64 - Commit uint64 - Open uint64 - OpenConfirm uint64 - OpenNoattr uint64 - OpenDowngrade uint64 - Close uint64 - Setattr uint64 - FsInfo uint64 - Renew uint64 - SetClientID uint64 - SetClientIDConfirm uint64 - Lock uint64 - Lockt uint64 - Locku uint64 - Access uint64 - Getattr uint64 - Lookup uint64 - LookupRoot uint64 - Remove uint64 - Rename uint64 - Link uint64 - Symlink uint64 - Create uint64 - Pathconf uint64 - StatFs uint64 - ReadLink uint64 - ReadDir uint64 - ServerCaps uint64 - DelegReturn uint64 - GetACL uint64 - SetACL uint64 - FsLocations uint64 - ReleaseLockowner uint64 - Secinfo uint64 - FsidPresent uint64 - ExchangeID uint64 - CreateSession uint64 - DestroySession uint64 - Sequence uint64 - GetLeaseTime uint64 - ReclaimComplete uint64 - LayoutGet uint64 - GetDeviceInfo uint64 - LayoutCommit uint64 - LayoutReturn uint64 - SecinfoNoName uint64 - TestStateID uint64 - FreeStateID uint64 - GetDeviceList uint64 - BindConnToSession uint64 - DestroyClientID uint64 - Seek uint64 - Allocate uint64 - DeAllocate uint64 - LayoutStats uint64 - Clone uint64 -} - -// ServerV4Stats models the nfsd "proc4" line. -type ServerV4Stats struct { - Null uint64 - Compound uint64 -} - -// V4Ops models the "proc4ops" line: NFSv4 operations -// Variable list, see: -// v4.0 https://tools.ietf.org/html/rfc3010 (38 operations) -// v4.1 https://tools.ietf.org/html/rfc5661 (58 operations) -// v4.2 https://tools.ietf.org/html/draft-ietf-nfsv4-minorversion2-41 (71 operations) -type V4Ops struct { - //Values uint64 // Variable depending on v4.x sub-version. TODO: Will this always at least include the fields in this struct? - Op0Unused uint64 - Op1Unused uint64 - Op2Future uint64 - Access uint64 - Close uint64 - Commit uint64 - Create uint64 - DelegPurge uint64 - DelegReturn uint64 - GetAttr uint64 - GetFH uint64 - Link uint64 - Lock uint64 - Lockt uint64 - Locku uint64 - Lookup uint64 - LookupRoot uint64 - Nverify uint64 - Open uint64 - OpenAttr uint64 - OpenConfirm uint64 - OpenDgrd uint64 - PutFH uint64 - PutPubFH uint64 - PutRootFH uint64 - Read uint64 - ReadDir uint64 - ReadLink uint64 - Remove uint64 - Rename uint64 - Renew uint64 - RestoreFH uint64 - SaveFH uint64 - SecInfo uint64 - SetAttr uint64 - Verify uint64 - Write uint64 - RelLockOwner uint64 -} - -// ClientRPCStats models all stats from /proc/net/rpc/nfs. -type ClientRPCStats struct { - Network Network - ClientRPC ClientRPC - V2Stats V2Stats - V3Stats V3Stats - ClientV4Stats ClientV4Stats -} - -// ServerRPCStats models all stats from /proc/net/rpc/nfsd. -type ServerRPCStats struct { - ReplyCache ReplyCache - FileHandles FileHandles - InputOutput InputOutput - Threads Threads - ReadAheadCache ReadAheadCache - Network Network - ServerRPC ServerRPC - V2Stats V2Stats - V3Stats V3Stats - ServerV4Stats ServerV4Stats - V4Ops V4Ops -} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse.go b/vendor/github.com/prometheus/procfs/nfs/parse.go deleted file mode 100644 index 95a83cc5bc..0000000000 --- a/vendor/github.com/prometheus/procfs/nfs/parse.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2018 The Prometheus 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 nfs - -import ( - "fmt" -) - -func parseReplyCache(v []uint64) (ReplyCache, error) { - if len(v) != 3 { - return ReplyCache{}, fmt.Errorf("invalid ReplyCache line %q", v) - } - - return ReplyCache{ - Hits: v[0], - Misses: v[1], - NoCache: v[2], - }, nil -} - -func parseFileHandles(v []uint64) (FileHandles, error) { - if len(v) != 5 { - return FileHandles{}, fmt.Errorf("invalid FileHandles, line %q", v) - } - - return FileHandles{ - Stale: v[0], - TotalLookups: v[1], - AnonLookups: v[2], - DirNoCache: v[3], - NoDirNoCache: v[4], - }, nil -} - -func parseInputOutput(v []uint64) (InputOutput, error) { - if len(v) != 2 { - return InputOutput{}, fmt.Errorf("invalid InputOutput line %q", v) - } - - return InputOutput{ - Read: v[0], - Write: v[1], - }, nil -} - -func parseThreads(v []uint64) (Threads, error) { - if len(v) != 2 { - return Threads{}, fmt.Errorf("invalid Threads line %q", v) - } - - return Threads{ - Threads: v[0], - FullCnt: v[1], - }, nil -} - -func parseReadAheadCache(v []uint64) (ReadAheadCache, error) { - if len(v) != 12 { - return ReadAheadCache{}, fmt.Errorf("invalid ReadAheadCache line %q", v) - } - - return ReadAheadCache{ - CacheSize: v[0], - CacheHistogram: v[1:11], - NotFound: v[11], - }, nil -} - -func parseNetwork(v []uint64) (Network, error) { - if len(v) != 4 { - return Network{}, fmt.Errorf("invalid Network line %q", v) - } - - return Network{ - NetCount: v[0], - UDPCount: v[1], - TCPCount: v[2], - TCPConnect: v[3], - }, nil -} - -func parseServerRPC(v []uint64) (ServerRPC, error) { - if len(v) != 5 { - return ServerRPC{}, fmt.Errorf("invalid RPC line %q", v) - } - - return ServerRPC{ - RPCCount: v[0], - BadCnt: v[1], - BadFmt: v[2], - BadAuth: v[3], - BadcInt: v[4], - }, nil -} - -func parseClientRPC(v []uint64) (ClientRPC, error) { - if len(v) != 3 { - return ClientRPC{}, fmt.Errorf("invalid RPC line %q", v) - } - - return ClientRPC{ - RPCCount: v[0], - Retransmissions: v[1], - AuthRefreshes: v[2], - }, nil -} - -func parseV2Stats(v []uint64) (V2Stats, error) { - values := int(v[0]) - if len(v[1:]) != values || values != 18 { - return V2Stats{}, fmt.Errorf("invalid V2Stats line %q", v) - } - - return V2Stats{ - Null: v[1], - GetAttr: v[2], - SetAttr: v[3], - Root: v[4], - Lookup: v[5], - ReadLink: v[6], - Read: v[7], - WrCache: v[8], - Write: v[9], - Create: v[10], - Remove: v[11], - Rename: v[12], - Link: v[13], - SymLink: v[14], - MkDir: v[15], - RmDir: v[16], - ReadDir: v[17], - FsStat: v[18], - }, nil -} - -func parseV3Stats(v []uint64) (V3Stats, error) { - values := int(v[0]) - if len(v[1:]) != values || values != 22 { - return V3Stats{}, fmt.Errorf("invalid V3Stats line %q", v) - } - - return V3Stats{ - Null: v[1], - GetAttr: v[2], - SetAttr: v[3], - Lookup: v[4], - Access: v[5], - ReadLink: v[6], - Read: v[7], - Write: v[8], - Create: v[9], - MkDir: v[10], - SymLink: v[11], - MkNod: v[12], - Remove: v[13], - RmDir: v[14], - Rename: v[15], - Link: v[16], - ReadDir: v[17], - ReadDirPlus: v[18], - FsStat: v[19], - FsInfo: v[20], - PathConf: v[21], - Commit: v[22], - }, nil -} - -func parseClientV4Stats(v []uint64) (ClientV4Stats, error) { - values := int(v[0]) - if len(v[1:]) != values { - return ClientV4Stats{}, fmt.Errorf("invalid ClientV4Stats line %q", v) - } - - // This function currently supports mapping 59 NFS v4 client stats. Older - // kernels may emit fewer stats, so we must detect this and pad out the - // values to match the expected slice size. - if values < 59 { - newValues := make([]uint64, 60) - copy(newValues, v) - v = newValues - } - - return ClientV4Stats{ - Null: v[1], - Read: v[2], - Write: v[3], - Commit: v[4], - Open: v[5], - OpenConfirm: v[6], - OpenNoattr: v[7], - OpenDowngrade: v[8], - Close: v[9], - Setattr: v[10], - FsInfo: v[11], - Renew: v[12], - SetClientID: v[13], - SetClientIDConfirm: v[14], - Lock: v[15], - Lockt: v[16], - Locku: v[17], - Access: v[18], - Getattr: v[19], - Lookup: v[20], - LookupRoot: v[21], - Remove: v[22], - Rename: v[23], - Link: v[24], - Symlink: v[25], - Create: v[26], - Pathconf: v[27], - StatFs: v[28], - ReadLink: v[29], - ReadDir: v[30], - ServerCaps: v[31], - DelegReturn: v[32], - GetACL: v[33], - SetACL: v[34], - FsLocations: v[35], - ReleaseLockowner: v[36], - Secinfo: v[37], - FsidPresent: v[38], - ExchangeID: v[39], - CreateSession: v[40], - DestroySession: v[41], - Sequence: v[42], - GetLeaseTime: v[43], - ReclaimComplete: v[44], - LayoutGet: v[45], - GetDeviceInfo: v[46], - LayoutCommit: v[47], - LayoutReturn: v[48], - SecinfoNoName: v[49], - TestStateID: v[50], - FreeStateID: v[51], - GetDeviceList: v[52], - BindConnToSession: v[53], - DestroyClientID: v[54], - Seek: v[55], - Allocate: v[56], - DeAllocate: v[57], - LayoutStats: v[58], - Clone: v[59], - }, nil -} - -func parseServerV4Stats(v []uint64) (ServerV4Stats, error) { - values := int(v[0]) - if len(v[1:]) != values || values != 2 { - return ServerV4Stats{}, fmt.Errorf("invalid V4Stats line %q", v) - } - - return ServerV4Stats{ - Null: v[1], - Compound: v[2], - }, nil -} - -func parseV4Ops(v []uint64) (V4Ops, error) { - values := int(v[0]) - if len(v[1:]) != values || values < 39 { - return V4Ops{}, fmt.Errorf("invalid V4Ops line %q", v) - } - - stats := V4Ops{ - Op0Unused: v[1], - Op1Unused: v[2], - Op2Future: v[3], - Access: v[4], - Close: v[5], - Commit: v[6], - Create: v[7], - DelegPurge: v[8], - DelegReturn: v[9], - GetAttr: v[10], - GetFH: v[11], - Link: v[12], - Lock: v[13], - Lockt: v[14], - Locku: v[15], - Lookup: v[16], - LookupRoot: v[17], - Nverify: v[18], - Open: v[19], - OpenAttr: v[20], - OpenConfirm: v[21], - OpenDgrd: v[22], - PutFH: v[23], - PutPubFH: v[24], - PutRootFH: v[25], - Read: v[26], - ReadDir: v[27], - ReadLink: v[28], - Remove: v[29], - Rename: v[30], - Renew: v[31], - RestoreFH: v[32], - SaveFH: v[33], - SecInfo: v[34], - SetAttr: v[35], - Verify: v[36], - Write: v[37], - RelLockOwner: v[38], - } - - return stats, nil -} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse_nfs.go b/vendor/github.com/prometheus/procfs/nfs/parse_nfs.go deleted file mode 100644 index c0d3a5ad9b..0000000000 --- a/vendor/github.com/prometheus/procfs/nfs/parse_nfs.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 The Prometheus 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 nfs - -import ( - "bufio" - "fmt" - "io" - "strings" - - "github.com/prometheus/procfs/internal/util" -) - -// ParseClientRPCStats returns stats read from /proc/net/rpc/nfs -func ParseClientRPCStats(r io.Reader) (*ClientRPCStats, error) { - stats := &ClientRPCStats{} - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - line := scanner.Text() - parts := strings.Fields(scanner.Text()) - // require at least - if len(parts) < 2 { - return nil, fmt.Errorf("invalid NFS metric line %q", line) - } - - values, err := util.ParseUint64s(parts[1:]) - if err != nil { - return nil, fmt.Errorf("error parsing NFS metric line: %s", err) - } - - switch metricLine := parts[0]; metricLine { - case "net": - stats.Network, err = parseNetwork(values) - case "rpc": - stats.ClientRPC, err = parseClientRPC(values) - case "proc2": - stats.V2Stats, err = parseV2Stats(values) - case "proc3": - stats.V3Stats, err = parseV3Stats(values) - case "proc4": - stats.ClientV4Stats, err = parseClientV4Stats(values) - default: - return nil, fmt.Errorf("unknown NFS metric line %q", metricLine) - } - if err != nil { - return nil, fmt.Errorf("errors parsing NFS metric line: %s", err) - } - } - - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("error scanning NFS file: %s", err) - } - - return stats, nil -} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go b/vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go deleted file mode 100644 index 57bb4a3585..0000000000 --- a/vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2018 The Prometheus 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 nfs - -import ( - "bufio" - "fmt" - "io" - "strings" - - "github.com/prometheus/procfs/internal/util" -) - -// ParseServerRPCStats returns stats read from /proc/net/rpc/nfsd -func ParseServerRPCStats(r io.Reader) (*ServerRPCStats, error) { - stats := &ServerRPCStats{} - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - line := scanner.Text() - parts := strings.Fields(scanner.Text()) - // require at least - if len(parts) < 2 { - return nil, fmt.Errorf("invalid NFSd metric line %q", line) - } - label := parts[0] - - var values []uint64 - var err error - if label == "th" { - if len(parts) < 3 { - return nil, fmt.Errorf("invalid NFSd th metric line %q", line) - } - values, err = util.ParseUint64s(parts[1:3]) - } else { - values, err = util.ParseUint64s(parts[1:]) - } - if err != nil { - return nil, fmt.Errorf("error parsing NFSd metric line: %s", err) - } - - switch metricLine := parts[0]; metricLine { - case "rc": - stats.ReplyCache, err = parseReplyCache(values) - case "fh": - stats.FileHandles, err = parseFileHandles(values) - case "io": - stats.InputOutput, err = parseInputOutput(values) - case "th": - stats.Threads, err = parseThreads(values) - case "ra": - stats.ReadAheadCache, err = parseReadAheadCache(values) - case "net": - stats.Network, err = parseNetwork(values) - case "rpc": - stats.ServerRPC, err = parseServerRPC(values) - case "proc2": - stats.V2Stats, err = parseV2Stats(values) - case "proc3": - stats.V3Stats, err = parseV3Stats(values) - case "proc4": - stats.ServerV4Stats, err = parseServerV4Stats(values) - case "proc4ops": - stats.V4Ops, err = parseV4Ops(values) - default: - return nil, fmt.Errorf("unknown NFSd metric line %q", metricLine) - } - if err != nil { - return nil, fmt.Errorf("errors parsing NFSd metric line: %s", err) - } - } - - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("error scanning NFSd file: %s", err) - } - - return stats, nil -} diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go index 06bed0ef4a..8e38493a89 100644 --- a/vendor/github.com/prometheus/procfs/proc.go +++ b/vendor/github.com/prometheus/procfs/proc.go @@ -20,6 +20,8 @@ import ( "os" "strconv" "strings" + + "github.com/prometheus/procfs/internal/fs" ) // Proc provides information about a running process. @@ -27,7 +29,7 @@ type Proc struct { // The process ID. PID int - fs FS + fs fs.FS } // Procs represents a list of Proc structs. @@ -66,11 +68,11 @@ func AllProcs() (Procs, error) { // Self returns a process for the current process. func (fs FS) Self() (Proc, error) { - p, err := os.Readlink(fs.Path("self")) + p, err := os.Readlink(fs.proc.Path("self")) if err != nil { return Proc{}, err } - pid, err := strconv.Atoi(strings.Replace(p, string(fs), "", -1)) + pid, err := strconv.Atoi(strings.Replace(p, string(fs.proc), "", -1)) if err != nil { return Proc{}, err } @@ -79,15 +81,15 @@ func (fs FS) Self() (Proc, error) { // NewProc returns a process for the given pid. func (fs FS) NewProc(pid int) (Proc, error) { - if _, err := os.Stat(fs.Path(strconv.Itoa(pid))); err != nil { + if _, err := os.Stat(fs.proc.Path(strconv.Itoa(pid))); err != nil { return Proc{}, err } - return Proc{PID: pid, fs: fs}, nil + return Proc{PID: pid, fs: fs.proc}, nil } // AllProcs returns a list of all currently available processes. func (fs FS) AllProcs() (Procs, error) { - d, err := os.Open(fs.Path()) + d, err := os.Open(fs.proc.Path()) if err != nil { return Procs{}, err } @@ -104,7 +106,7 @@ func (fs FS) AllProcs() (Procs, error) { if err != nil { continue } - p = append(p, Proc{PID: int(pid), fs: fs}) + p = append(p, Proc{PID: int(pid), fs: fs.proc}) } return p, nil diff --git a/vendor/github.com/prometheus/procfs/proc_psi.go b/vendor/github.com/prometheus/procfs/proc_psi.go new file mode 100644 index 0000000000..a23d4c0f05 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_psi.go @@ -0,0 +1,110 @@ +// Copyright 2019 The Prometheus 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 procfs + +// The PSI / pressure interface is described at +// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/accounting/psi.txt +// Each resource (cpu, io, memory, ...) is exposed as a single file. +// Each file may contain up to two lines, one for "some" pressure and one for "full" pressure. +// Each line contains several averages (over n seconds) and a total in µs. +// +// Example io pressure file: +// > some avg10=0.06 avg60=0.21 avg300=0.99 total=8537362 +// > full avg10=0.00 avg60=0.13 avg300=0.96 total=8183134 + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "strings" +) + +const lineFormat = "avg10=%f avg60=%f avg300=%f total=%d" + +// PSILine is a single line of values as returned by /proc/pressure/* +// The Avg entries are averages over n seconds, as a percentage +// The Total line is in microseconds +type PSILine struct { + Avg10 float64 + Avg60 float64 + Avg300 float64 + Total uint64 +} + +// PSIStats represent pressure stall information from /proc/pressure/* +// Some indicates the share of time in which at least some tasks are stalled +// Full indicates the share of time in which all non-idle tasks are stalled simultaneously +type PSIStats struct { + Some *PSILine + Full *PSILine +} + +// NewPSIStatsForResource reads pressure stall information for the specified +// resource. At time of writing this can be either "cpu", "memory" or "io". +func NewPSIStatsForResource(resource string) (PSIStats, error) { + fs, err := NewFS(DefaultMountPoint) + if err != nil { + return PSIStats{}, err + } + + return fs.NewPSIStatsForResource(resource) +} + +// NewPSIStatsForResource reads pressure stall information from /proc/pressure/ +func (fs FS) NewPSIStatsForResource(resource string) (PSIStats, error) { + file, err := os.Open(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource))) + if err != nil { + return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %s", resource) + } + + defer file.Close() + return parsePSIStats(resource, file) +} + +// parsePSIStats parses the specified file for pressure stall information +func parsePSIStats(resource string, file io.Reader) (PSIStats, error) { + psiStats := PSIStats{} + stats, err := ioutil.ReadAll(file) + if err != nil { + return psiStats, fmt.Errorf("psi_stats: unable to read data for %s", resource) + } + + for _, l := range strings.Split(string(stats), "\n") { + prefix := strings.Split(l, " ")[0] + switch prefix { + case "some": + psi := PSILine{} + _, err := fmt.Sscanf(l, fmt.Sprintf("some %s", lineFormat), &psi.Avg10, &psi.Avg60, &psi.Avg300, &psi.Total) + if err != nil { + return PSIStats{}, err + } + psiStats.Some = &psi + case "full": + psi := PSILine{} + _, err := fmt.Sscanf(l, fmt.Sprintf("full %s", lineFormat), &psi.Avg10, &psi.Avg60, &psi.Avg300, &psi.Total) + if err != nil { + return PSIStats{}, err + } + psiStats.Full = &psi + default: + // If we encounter a line with an unknown prefix, ignore it and move on + // Should new measurement types be added in the future we'll simply ignore them instead + // of erroring on retrieval + continue + } + } + + return psiStats, nil +} diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go index 3cf2a9f18f..4c8b03ced4 100644 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ b/vendor/github.com/prometheus/procfs/proc_stat.go @@ -18,6 +18,8 @@ import ( "fmt" "io/ioutil" "os" + + "github.com/prometheus/procfs/internal/fs" ) // Originally, this USER_HZ value was dynamically retrieved via a sysconf call @@ -95,11 +97,11 @@ type ProcStat struct { // in clock ticks. Starttime uint64 // Virtual memory size in bytes. - VSize int + VSize uint // Resident set size in pages. RSS int - fs FS + proc fs.FS } // NewStat returns the current status information of the process. @@ -118,7 +120,7 @@ func (p Proc) NewStat() (ProcStat, error) { var ( ignore int - s = ProcStat{PID: p.PID, fs: p.fs} + s = ProcStat{PID: p.PID, proc: p.fs} l = bytes.Index(data, []byte("(")) r = bytes.LastIndex(data, []byte(")")) ) @@ -164,7 +166,7 @@ func (p Proc) NewStat() (ProcStat, error) { } // VirtualMemory returns the virtual memory size in bytes. -func (s ProcStat) VirtualMemory() int { +func (s ProcStat) VirtualMemory() uint { return s.VSize } @@ -175,7 +177,8 @@ func (s ProcStat) ResidentMemory() int { // StartTime returns the unix timestamp of the process in seconds. func (s ProcStat) StartTime() (float64, error) { - stat, err := s.fs.NewStat() + fs := FS{proc: s.proc} + stat, err := fs.NewStat() if err != nil { return 0, err } diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go index 61eb6b0e3c..44c9af1b0b 100644 --- a/vendor/github.com/prometheus/procfs/stat.go +++ b/vendor/github.com/prometheus/procfs/stat.go @@ -153,7 +153,7 @@ func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) { func (fs FS) NewStat() (Stat, error) { // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt - f, err := os.Open(fs.Path("stat")) + f, err := os.Open(fs.proc.Path("stat")) if err != nil { return Stat{}, err } diff --git a/vendor/github.com/prometheus/procfs/xfrm.go b/vendor/github.com/prometheus/procfs/xfrm.go index 8f1508f0fd..30aa417d53 100644 --- a/vendor/github.com/prometheus/procfs/xfrm.go +++ b/vendor/github.com/prometheus/procfs/xfrm.go @@ -97,7 +97,7 @@ func NewXfrmStat() (XfrmStat, error) { // NewXfrmStat reads the xfrm_stat statistics from the 'proc' filesystem. func (fs FS) NewXfrmStat() (XfrmStat, error) { - file, err := os.Open(fs.Path("net/xfrm_stat")) + file, err := os.Open(fs.proc.Path("net/xfrm_stat")) if err != nil { return XfrmStat{}, err } diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go deleted file mode 100644 index 2bc0ef3427..0000000000 --- a/vendor/github.com/prometheus/procfs/xfs/parse.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2017 The Prometheus 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 xfs - -import ( - "bufio" - "fmt" - "io" - "strings" - - "github.com/prometheus/procfs/internal/util" -) - -// ParseStats parses a Stats from an input io.Reader, using the format -// found in /proc/fs/xfs/stat. -func ParseStats(r io.Reader) (*Stats, error) { - const ( - // Fields parsed into stats structures. - fieldExtentAlloc = "extent_alloc" - fieldAbt = "abt" - fieldBlkMap = "blk_map" - fieldBmbt = "bmbt" - fieldDir = "dir" - fieldTrans = "trans" - fieldIg = "ig" - fieldLog = "log" - fieldRw = "rw" - fieldAttr = "attr" - fieldIcluster = "icluster" - fieldVnodes = "vnodes" - fieldBuf = "buf" - fieldXpc = "xpc" - - // Unimplemented at this time due to lack of documentation. - fieldPushAil = "push_ail" - fieldXstrat = "xstrat" - fieldAbtb2 = "abtb2" - fieldAbtc2 = "abtc2" - fieldBmbt2 = "bmbt2" - fieldIbt2 = "ibt2" - fieldFibt2 = "fibt2" - fieldQm = "qm" - fieldDebug = "debug" - ) - - var xfss Stats - - s := bufio.NewScanner(r) - for s.Scan() { - // Expect at least a string label and a single integer value, ex: - // - abt 0 - // - rw 1 2 - ss := strings.Fields(string(s.Bytes())) - if len(ss) < 2 { - continue - } - label := ss[0] - - // Extended precision counters are uint64 values. - if label == fieldXpc { - us, err := util.ParseUint64s(ss[1:]) - if err != nil { - return nil, err - } - - xfss.ExtendedPrecision, err = extendedPrecisionStats(us) - if err != nil { - return nil, err - } - - continue - } - - // All other counters are uint32 values. - us, err := util.ParseUint32s(ss[1:]) - if err != nil { - return nil, err - } - - switch label { - case fieldExtentAlloc: - xfss.ExtentAllocation, err = extentAllocationStats(us) - case fieldAbt: - xfss.AllocationBTree, err = btreeStats(us) - case fieldBlkMap: - xfss.BlockMapping, err = blockMappingStats(us) - case fieldBmbt: - xfss.BlockMapBTree, err = btreeStats(us) - case fieldDir: - xfss.DirectoryOperation, err = directoryOperationStats(us) - case fieldTrans: - xfss.Transaction, err = transactionStats(us) - case fieldIg: - xfss.InodeOperation, err = inodeOperationStats(us) - case fieldLog: - xfss.LogOperation, err = logOperationStats(us) - case fieldRw: - xfss.ReadWrite, err = readWriteStats(us) - case fieldAttr: - xfss.AttributeOperation, err = attributeOperationStats(us) - case fieldIcluster: - xfss.InodeClustering, err = inodeClusteringStats(us) - case fieldVnodes: - xfss.Vnode, err = vnodeStats(us) - case fieldBuf: - xfss.Buffer, err = bufferStats(us) - } - if err != nil { - return nil, err - } - } - - return &xfss, s.Err() -} - -// extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s. -func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) { - if l := len(us); l != 4 { - return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l) - } - - return ExtentAllocationStats{ - ExtentsAllocated: us[0], - BlocksAllocated: us[1], - ExtentsFreed: us[2], - BlocksFreed: us[3], - }, nil -} - -// btreeStats builds a BTreeStats from a slice of uint32s. -func btreeStats(us []uint32) (BTreeStats, error) { - if l := len(us); l != 4 { - return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l) - } - - return BTreeStats{ - Lookups: us[0], - Compares: us[1], - RecordsInserted: us[2], - RecordsDeleted: us[3], - }, nil -} - -// BlockMappingStat builds a BlockMappingStats from a slice of uint32s. -func blockMappingStats(us []uint32) (BlockMappingStats, error) { - if l := len(us); l != 7 { - return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l) - } - - return BlockMappingStats{ - Reads: us[0], - Writes: us[1], - Unmaps: us[2], - ExtentListInsertions: us[3], - ExtentListDeletions: us[4], - ExtentListLookups: us[5], - ExtentListCompares: us[6], - }, nil -} - -// DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s. -func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) { - if l := len(us); l != 4 { - return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l) - } - - return DirectoryOperationStats{ - Lookups: us[0], - Creates: us[1], - Removes: us[2], - Getdents: us[3], - }, nil -} - -// TransactionStats builds a TransactionStats from a slice of uint32s. -func transactionStats(us []uint32) (TransactionStats, error) { - if l := len(us); l != 3 { - return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l) - } - - return TransactionStats{ - Sync: us[0], - Async: us[1], - Empty: us[2], - }, nil -} - -// InodeOperationStats builds an InodeOperationStats from a slice of uint32s. -func inodeOperationStats(us []uint32) (InodeOperationStats, error) { - if l := len(us); l != 7 { - return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l) - } - - return InodeOperationStats{ - Attempts: us[0], - Found: us[1], - Recycle: us[2], - Missed: us[3], - Duplicate: us[4], - Reclaims: us[5], - AttributeChange: us[6], - }, nil -} - -// LogOperationStats builds a LogOperationStats from a slice of uint32s. -func logOperationStats(us []uint32) (LogOperationStats, error) { - if l := len(us); l != 5 { - return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l) - } - - return LogOperationStats{ - Writes: us[0], - Blocks: us[1], - NoInternalBuffers: us[2], - Force: us[3], - ForceSleep: us[4], - }, nil -} - -// ReadWriteStats builds a ReadWriteStats from a slice of uint32s. -func readWriteStats(us []uint32) (ReadWriteStats, error) { - if l := len(us); l != 2 { - return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l) - } - - return ReadWriteStats{ - Read: us[0], - Write: us[1], - }, nil -} - -// AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s. -func attributeOperationStats(us []uint32) (AttributeOperationStats, error) { - if l := len(us); l != 4 { - return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l) - } - - return AttributeOperationStats{ - Get: us[0], - Set: us[1], - Remove: us[2], - List: us[3], - }, nil -} - -// InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s. -func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) { - if l := len(us); l != 3 { - return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l) - } - - return InodeClusteringStats{ - Iflush: us[0], - Flush: us[1], - FlushInode: us[2], - }, nil -} - -// VnodeStats builds a VnodeStats from a slice of uint32s. -func vnodeStats(us []uint32) (VnodeStats, error) { - // The attribute "Free" appears to not be available on older XFS - // stats versions. Therefore, 7 or 8 elements may appear in - // this slice. - l := len(us) - if l != 7 && l != 8 { - return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l) - } - - s := VnodeStats{ - Active: us[0], - Allocate: us[1], - Get: us[2], - Hold: us[3], - Release: us[4], - Reclaim: us[5], - Remove: us[6], - } - - // Skip adding free, unless it is present. The zero value will - // be used in place of an actual count. - if l == 7 { - return s, nil - } - - s.Free = us[7] - return s, nil -} - -// BufferStats builds a BufferStats from a slice of uint32s. -func bufferStats(us []uint32) (BufferStats, error) { - if l := len(us); l != 9 { - return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l) - } - - return BufferStats{ - Get: us[0], - Create: us[1], - GetLocked: us[2], - GetLockedWaited: us[3], - BusyLocked: us[4], - MissLocked: us[5], - PageRetries: us[6], - PageFound: us[7], - GetRead: us[8], - }, nil -} - -// ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s. -func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) { - if l := len(us); l != 3 { - return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l) - } - - return ExtendedPrecisionStats{ - FlushBytes: us[0], - WriteBytes: us[1], - ReadBytes: us[2], - }, nil -} diff --git a/vendor/github.com/prometheus/procfs/xfs/xfs.go b/vendor/github.com/prometheus/procfs/xfs/xfs.go deleted file mode 100644 index d86794b7ca..0000000000 --- a/vendor/github.com/prometheus/procfs/xfs/xfs.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2017 The Prometheus 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 xfs provides access to statistics exposed by the XFS filesystem. -package xfs - -// Stats contains XFS filesystem runtime statistics, parsed from -// /proc/fs/xfs/stat. -// -// The names and meanings of each statistic were taken from -// http://xfs.org/index.php/Runtime_Stats and xfs_stats.h in the Linux -// kernel source. Most counters are uint32s (same data types used in -// xfs_stats.h), but some of the "extended precision stats" are uint64s. -type Stats struct { - // The name of the filesystem used to source these statistics. - // If empty, this indicates aggregated statistics for all XFS - // filesystems on the host. - Name string - - ExtentAllocation ExtentAllocationStats - AllocationBTree BTreeStats - BlockMapping BlockMappingStats - BlockMapBTree BTreeStats - DirectoryOperation DirectoryOperationStats - Transaction TransactionStats - InodeOperation InodeOperationStats - LogOperation LogOperationStats - ReadWrite ReadWriteStats - AttributeOperation AttributeOperationStats - InodeClustering InodeClusteringStats - Vnode VnodeStats - Buffer BufferStats - ExtendedPrecision ExtendedPrecisionStats -} - -// ExtentAllocationStats contains statistics regarding XFS extent allocations. -type ExtentAllocationStats struct { - ExtentsAllocated uint32 - BlocksAllocated uint32 - ExtentsFreed uint32 - BlocksFreed uint32 -} - -// BTreeStats contains statistics regarding an XFS internal B-tree. -type BTreeStats struct { - Lookups uint32 - Compares uint32 - RecordsInserted uint32 - RecordsDeleted uint32 -} - -// BlockMappingStats contains statistics regarding XFS block maps. -type BlockMappingStats struct { - Reads uint32 - Writes uint32 - Unmaps uint32 - ExtentListInsertions uint32 - ExtentListDeletions uint32 - ExtentListLookups uint32 - ExtentListCompares uint32 -} - -// DirectoryOperationStats contains statistics regarding XFS directory entries. -type DirectoryOperationStats struct { - Lookups uint32 - Creates uint32 - Removes uint32 - Getdents uint32 -} - -// TransactionStats contains statistics regarding XFS metadata transactions. -type TransactionStats struct { - Sync uint32 - Async uint32 - Empty uint32 -} - -// InodeOperationStats contains statistics regarding XFS inode operations. -type InodeOperationStats struct { - Attempts uint32 - Found uint32 - Recycle uint32 - Missed uint32 - Duplicate uint32 - Reclaims uint32 - AttributeChange uint32 -} - -// LogOperationStats contains statistics regarding the XFS log buffer. -type LogOperationStats struct { - Writes uint32 - Blocks uint32 - NoInternalBuffers uint32 - Force uint32 - ForceSleep uint32 -} - -// ReadWriteStats contains statistics regarding the number of read and write -// system calls for XFS filesystems. -type ReadWriteStats struct { - Read uint32 - Write uint32 -} - -// AttributeOperationStats contains statistics regarding manipulation of -// XFS extended file attributes. -type AttributeOperationStats struct { - Get uint32 - Set uint32 - Remove uint32 - List uint32 -} - -// InodeClusteringStats contains statistics regarding XFS inode clustering -// operations. -type InodeClusteringStats struct { - Iflush uint32 - Flush uint32 - FlushInode uint32 -} - -// VnodeStats contains statistics regarding XFS vnode operations. -type VnodeStats struct { - Active uint32 - Allocate uint32 - Get uint32 - Hold uint32 - Release uint32 - Reclaim uint32 - Remove uint32 - Free uint32 -} - -// BufferStats contains statistics regarding XFS read/write I/O buffers. -type BufferStats struct { - Get uint32 - Create uint32 - GetLocked uint32 - GetLockedWaited uint32 - BusyLocked uint32 - MissLocked uint32 - PageRetries uint32 - PageFound uint32 - GetRead uint32 -} - -// ExtendedPrecisionStats contains high precision counters used to track the -// total number of bytes read, written, or flushed, during XFS operations. -type ExtendedPrecisionStats struct { - FlushBytes uint64 - WriteBytes uint64 - ReadBytes uint64 -} diff --git a/vendor/gopkg.in/yaml.v2/encode.go b/vendor/gopkg.in/yaml.v2/encode.go index a14435e82f..0ee738e11b 100644 --- a/vendor/gopkg.in/yaml.v2/encode.go +++ b/vendor/gopkg.in/yaml.v2/encode.go @@ -13,6 +13,19 @@ import ( "unicode/utf8" ) +// jsonNumber is the interface of the encoding/json.Number datatype. +// Repeating the interface here avoids a dependency on encoding/json, and also +// supports other libraries like jsoniter, which use a similar datatype with +// the same interface. Detecting this interface is useful when dealing with +// structures containing json.Number, which is a string under the hood. The +// encoder should prefer the use of Int64(), Float64() and string(), in that +// order, when encoding this type. +type jsonNumber interface { + Float64() (float64, error) + Int64() (int64, error) + String() string +} + type encoder struct { emitter yaml_emitter_t event yaml_event_t @@ -89,6 +102,21 @@ func (e *encoder) marshal(tag string, in reflect.Value) { } iface := in.Interface() switch m := iface.(type) { + case jsonNumber: + integer, err := m.Int64() + if err == nil { + // In this case the json.Number is a valid int64 + in = reflect.ValueOf(integer) + break + } + float, err := m.Float64() + if err == nil { + // In this case the json.Number is a valid float64 + in = reflect.ValueOf(float) + break + } + // fallback case - no number could be obtained + in = reflect.ValueOf(m.String()) case time.Time, *time.Time: // Although time.Time implements TextMarshaler, // we don't want to treat it as a string for YAML diff --git a/vendor/modules.txt b/vendor/modules.txt index 70dff4c9ef..d9da4be69d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -15,7 +15,7 @@ github.com/Unknwon/i18n github.com/Unknwon/paginater # github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 github.com/andybalholm/cascadia -# github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 +# github.com/beorn7/perks v1.0.0 github.com/beorn7/perks/quantile # github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3 github.com/blevesearch/bleve @@ -88,7 +88,7 @@ github.com/davecgh/go-spew/spew # github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp -# github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac +# github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go # github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 github.com/edsrzf/mmap-go @@ -156,7 +156,7 @@ github.com/go-xorm/xorm github.com/gogits/chardet # github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 github.com/gogits/cron -# github.com/golang/protobuf v1.2.0 +# github.com/golang/protobuf v1.3.1 github.com/golang/protobuf/proto # github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db github.com/golang/snappy @@ -268,21 +268,19 @@ github.com/pmezard/go-difflib/difflib github.com/pquerna/otp/totp github.com/pquerna/otp github.com/pquerna/otp/hotp -# github.com/prometheus/client_golang v0.9.0 +# github.com/prometheus/client_golang v0.9.3 github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/promhttp github.com/prometheus/client_golang/prometheus/internal -# github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 +# github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 github.com/prometheus/client_model/go -# github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 +# github.com/prometheus/common v0.4.0 github.com/prometheus/common/expfmt github.com/prometheus/common/model github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg -# github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d +# github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 github.com/prometheus/procfs -github.com/prometheus/procfs/nfs -github.com/prometheus/procfs/xfs -github.com/prometheus/procfs/internal/util +github.com/prometheus/procfs/internal/fs # github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff github.com/russross/blackfriday # github.com/satori/go.uuid v1.2.0 @@ -474,7 +472,7 @@ gopkg.in/src-d/go-git.v4/plumbing/transport/server gopkg.in/testfixtures.v2 # gopkg.in/warnings.v0 v0.1.2 gopkg.in/warnings.v0 -# gopkg.in/yaml.v2 v2.2.1 +# gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2 # mvdan.cc/xurls/v2 v2.0.0 mvdan.cc/xurls/v2 From 96b66e330b9a592093799a50219c8118de6951eb Mon Sep 17 00:00:00 2001 From: leonklingele <5585491+leonklingele@users.noreply.github.com> Date: Sat, 6 Jul 2019 17:47:09 +0200 Subject: [PATCH 182/220] routers/user: ensure that decryption of cookie actually suceeds (#7363) Previously, only the first return value of ctx.GetSuperSecureCookie was used to check whether decryption of the auth cookie succeeded. ctx.GetSuperSecureCookie also returns a second value, a boolean, indicating success or not. That value should be checked first to be on the safe side and not rely on internal logic of the encryption and decryption blackbox. --- routers/user/auth.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/user/auth.go b/routers/user/auth.go index 0731e34675..576f630577 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -71,8 +71,8 @@ func AutoSignIn(ctx *context.Context) (bool, error) { return false, nil } - if val, _ := ctx.GetSuperSecureCookie( - base.EncodeMD5(u.Rands+u.Passwd), setting.CookieRememberName); val != u.Name { + if val, ok := ctx.GetSuperSecureCookie( + base.EncodeMD5(u.Rands+u.Passwd), setting.CookieRememberName); !ok || val != u.Name { return false, nil } From ef57fe4ae3c517a0bb10b81a641fb76976f404d3 Mon Sep 17 00:00:00 2001 From: leonklingele <5585491+leonklingele@users.noreply.github.com> Date: Sat, 6 Jul 2019 19:03:13 +0200 Subject: [PATCH 183/220] routers: do not leak secrets via timing side channel (#7364) * routers: do not leak secrets via timing side channel * routers/repo: do not leak secrets via timing side channel --- routers/metrics.go | 6 +++++- routers/repo/pull.go | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/routers/metrics.go b/routers/metrics.go index 78abd4a785..b7711dfced 100644 --- a/routers/metrics.go +++ b/routers/metrics.go @@ -5,6 +5,8 @@ package routers import ( + "crypto/subtle" + "github.com/prometheus/client_golang/prometheus/promhttp" "code.gitea.io/gitea/modules/context" @@ -22,7 +24,9 @@ func Metrics(ctx *context.Context) { ctx.Error(401) return } - if header != "Bearer "+setting.Metrics.Token { + got := []byte(header) + want := []byte("Bearer " + setting.Metrics.Token) + if subtle.ConstantTimeCompare(got, want) != 1 { ctx.Error(401) return } diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 4c377bb364..cb4fa9547e 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -8,6 +8,7 @@ package repo import ( "container/list" + "crypto/subtle" "fmt" "io" "path" @@ -771,7 +772,9 @@ func TriggerTask(ctx *context.Context) { if ctx.Written() { return } - if secret != base.EncodeMD5(owner.Salt) { + got := []byte(base.EncodeMD5(owner.Salt)) + want := []byte(secret) + if subtle.ConstantTimeCompare(got, want) != 1 { ctx.Error(404) log.Trace("TriggerTask [%s/%s]: invalid secret", owner.Name, repo.Name) return From 337d6915ff8967637ff515108612c3a7a4f51585 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 7 Jul 2019 03:24:50 +0800 Subject: [PATCH 184/220] Detect migrating batch size (#7353) * Make migrating batch size as configurable * detect different table batch insert size and remove config item * remove unrelated changes --- models/models.go | 6 +++ modules/migrations/base/uploader.go | 1 + modules/migrations/gitea.go | 19 +++++++++ modules/migrations/migrate.go | 64 +++++++++++++++++++++-------- 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/models/models.go b/models/models.go index 3b3d8ec30a..f746f680a5 100644 --- a/models/models.go +++ b/models/models.go @@ -368,3 +368,9 @@ func DumpDatabase(filePath string, dbType string) error { } return x.DumpTablesToFile(tbs, filePath) } + +// MaxBatchInsertSize returns the table's max batch insert size +func MaxBatchInsertSize(bean interface{}) int { + t := x.TableInfo(bean) + return 999 / len(t.ColumnsSeq()) +} diff --git a/modules/migrations/base/uploader.go b/modules/migrations/base/uploader.go index 9d2fd2af6a..8c1d649229 100644 --- a/modules/migrations/base/uploader.go +++ b/modules/migrations/base/uploader.go @@ -7,6 +7,7 @@ package base // Uploader uploads all the informations of one repository type Uploader interface { + MaxBatchInsertSize(tp string) int CreateRepo(repo *Repository, opts MigrateOptions) error CreateMilestones(milestones ...*Milestone) error CreateReleases(releases ...*Release) error diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index bfc5e49033..1df824c94f 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -53,6 +53,25 @@ func NewGiteaLocalUploader(doer *models.User, repoOwner, repoName string) *Gitea } } +// MaxBatchInsertSize returns the table's max batch insert size +func (g *GiteaLocalUploader) MaxBatchInsertSize(tp string) int { + switch tp { + case "issue": + return models.MaxBatchInsertSize(new(models.Issue)) + case "comment": + return models.MaxBatchInsertSize(new(models.Comment)) + case "milestone": + return models.MaxBatchInsertSize(new(models.Milestone)) + case "label": + return models.MaxBatchInsertSize(new(models.Label)) + case "release": + return models.MaxBatchInsertSize(new(models.Release)) + case "pullrequest": + return models.MaxBatchInsertSize(new(models.PullRequest)) + } + return 10 +} + // CreateRepo creates a repository func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.MigrateOptions) error { owner, err := models.GetUserByName(g.repoOwner) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index ce8f9b8022..5adf7f8050 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -91,8 +91,16 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - if err := uploader.CreateMilestones(milestones...); err != nil { - return err + msBatchSize := uploader.MaxBatchInsertSize("milestone") + for len(milestones) > 0 { + if len(milestones) < msBatchSize { + msBatchSize = len(milestones) + } + + if err := uploader.CreateMilestones(milestones...); err != nil { + return err + } + milestones = milestones[msBatchSize:] } } @@ -103,8 +111,16 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - if err := uploader.CreateLabels(labels...); err != nil { - return err + lbBatchSize := uploader.MaxBatchInsertSize("label") + for len(labels) > 0 { + if len(labels) < lbBatchSize { + lbBatchSize = len(labels) + } + + if err := uploader.CreateLabels(labels...); err != nil { + return err + } + labels = labels[lbBatchSize:] } } @@ -115,15 +131,27 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - if err := uploader.CreateReleases(releases...); err != nil { - return err + relBatchSize := uploader.MaxBatchInsertSize("release") + for len(releases) > 0 { + if len(releases) < relBatchSize { + relBatchSize = len(releases) + } + + if err := uploader.CreateReleases(releases[:relBatchSize]...); err != nil { + return err + } + releases = releases[relBatchSize:] } } + var commentBatchSize = uploader.MaxBatchInsertSize("comment") + if opts.Issues { log.Trace("migrating issues and comments") + var issueBatchSize = uploader.MaxBatchInsertSize("issue") + for i := 1; ; i++ { - issues, isEnd, err := downloader.GetIssues(i, 100) + issues, isEnd, err := downloader.GetIssues(i, issueBatchSize) if err != nil { return err } @@ -141,7 +169,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts continue } - var allComments = make([]*base.Comment, 0, 100) + var allComments = make([]*base.Comment, 0, commentBatchSize) for _, issue := range issues { comments, err := downloader.GetComments(issue.Number) if err != nil { @@ -154,11 +182,12 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } allComments = append(allComments, comments...) - if len(allComments) >= 100 { - if err := uploader.CreateComments(allComments...); err != nil { + if len(allComments) >= commentBatchSize { + if err := uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { return err } - allComments = make([]*base.Comment, 0, 100) + + allComments = allComments[commentBatchSize:] } } @@ -176,8 +205,9 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if opts.PullRequests { log.Trace("migrating pull requests and comments") + var prBatchSize = models.MaxBatchInsertSize("pullrequest") for i := 1; ; i++ { - prs, err := downloader.GetPullRequests(i, 100) + prs, err := downloader.GetPullRequests(i, prBatchSize) if err != nil { return err } @@ -195,7 +225,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts continue } - var allComments = make([]*base.Comment, 0, 100) + var allComments = make([]*base.Comment, 0, commentBatchSize) for _, pr := range prs { comments, err := downloader.GetComments(pr.Number) if err != nil { @@ -209,11 +239,11 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts allComments = append(allComments, comments...) - if len(allComments) >= 100 { - if err := uploader.CreateComments(allComments...); err != nil { + if len(allComments) >= commentBatchSize { + if err := uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { return err } - allComments = make([]*base.Comment, 0, 100) + allComments = allComments[commentBatchSize:] } } if len(allComments) > 0 { @@ -222,7 +252,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } } - if len(prs) < 100 { + if len(prs) < prBatchSize { break } } From 62d6127f1b945b3160d337a190b33aa96e0f60b5 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sat, 6 Jul 2019 13:48:02 -0600 Subject: [PATCH 185/220] Make captcha and password optional for external accounts (#6606) --- .../doc/advanced/config-cheat-sheet.en-us.md | 7 +- modules/auth/user_form.go | 3 +- modules/setting/service.go | 4 + routers/user/auth.go | 74 ++++++++++++------- routers/user/auth_openid.go | 26 ++++--- templates/user/auth/signin_inner.tmpl | 2 + templates/user/auth/signup_inner.tmpl | 19 +++-- 7 files changed, 88 insertions(+), 47 deletions(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 12cad995e5..11dbfc5d09 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -216,6 +216,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. Requires `Mailer` to be enabled. - `DISABLE_REGISTRATION`: **false**: Disable registration, after which only admin can create accounts for users. +- `REQUIRE_EXTERNAL_REGISTRATION_PASSWORD`: **false**: Enable this to force externally created + accounts (via GitHub, OpenID Connect, etc) to create a password. Warning: enabling this will + decrease security, so you should only enable it if you know what you're doing. - `REQUIRE_SIGNIN_VIEW`: **false**: Enable this to force users to log in to view any page. - `ENABLE_NOTIFY_MAIL`: **false**: Enable this to send e-mail to watchers of a repository when something happens, like creating issues. Requires `Mailer` to be enabled. @@ -225,6 +228,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `ENABLE_REVERSE_PROXY_EMAIL`: **false**: Enable this to allow to auto-registration with a provided email rather than a generated email. - `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration. +- `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation + even for External Accounts (i.e. GitHub, OpenID Connect, etc). You must `ENABLE_CAPTCHA` also. - `CAPTCHA_TYPE`: **image**: \[image, recaptcha\] - `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha. - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. @@ -419,7 +424,7 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` ## Metrics (`metrics`) -- `ENABLED`: **false**: Enables /metrics endpoint for prometheus. +- `ENABLED`: **false**: Enables /metrics endpoint for prometheus. - `TOKEN`: **\**: You need to specify the token, if you want to include in the authorization the metrics . The same token need to be used in prometheus parameters `bearer_token` or `bearer_token_file`. ## API (`api`) diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 0c8bd30abc..c117d038be 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -79,7 +79,7 @@ func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) bindin type RegisterForm struct { UserName string `binding:"Required;AlphaDashDot;MaxSize(40)"` Email string `binding:"Required;Email;MaxSize(254)"` - Password string `binding:"Required;MaxSize(255)"` + Password string `binding:"MaxSize(255)"` Retype string GRecaptchaResponse string `form:"g-recaptcha-response"` } @@ -129,6 +129,7 @@ func (f *MustChangePasswordForm) Validate(ctx *macaron.Context, errs binding.Err // SignInForm form for signing in with user/password type SignInForm struct { UserName string `binding:"Required;MaxSize(254)"` + // TODO remove required from password for SecondFactorAuthentication Password string `binding:"Required;MaxSize(255)"` Remember bool } diff --git a/modules/setting/service.go b/modules/setting/service.go index 7e4fb8d7d9..97babc5aaf 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -27,6 +27,8 @@ var Service struct { EnableReverseProxyAutoRegister bool EnableReverseProxyEmail bool EnableCaptcha bool + RequireExternalRegistrationCaptcha bool + RequireExternalRegistrationPassword bool CaptchaType string RecaptchaSecret string RecaptchaSitekey string @@ -61,6 +63,8 @@ func newService() { Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false) + Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha) + Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool() Service.CaptchaType = sec.Key("CAPTCHA_TYPE").MustString(ImageCaptcha) Service.RecaptchaSecret = sec.Key("RECAPTCHA_SECRET").MustString("") Service.RecaptchaSitekey = sec.Key("RECAPTCHA_SITEKEY").MustString("") diff --git a/routers/user/auth.go b/routers/user/auth.go index 576f630577..8203593739 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -697,9 +697,10 @@ func oAuth2UserLoginCallback(loginSource *models.LoginSource, request *http.Requ // LinkAccount shows the page where the user can decide to login or create a new account func LinkAccount(ctx *context.Context) { + ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationCaptcha || setting.Service.AllowOnlyExternalRegistration ctx.Data["Title"] = ctx.Tr("link_account") ctx.Data["LinkAccountMode"] = true - ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha + ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey @@ -746,10 +747,11 @@ func LinkAccount(ctx *context.Context) { // LinkAccountPostSignIn handle the coupling of external account with another account using signIn func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) { + ctx.Data["DisablePassword"] = setting.Service.AllowOnlyExternalRegistration ctx.Data["Title"] = ctx.Tr("link_account") ctx.Data["LinkAccountMode"] = true ctx.Data["LinkAccountModeSignIn"] = true - ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha + ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey @@ -824,10 +826,13 @@ func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) { // LinkAccountPostRegister handle the creation of a new account for an external account using signUp func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterForm) { + // TODO Make insecure passwords optional for local accounts also, + // once email-based Second-Factor Auth is available + ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationCaptcha || setting.Service.AllowOnlyExternalRegistration ctx.Data["Title"] = ctx.Tr("link_account") ctx.Data["LinkAccountMode"] = true ctx.Data["LinkAccountModeRegister"] = true - ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha + ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey @@ -854,14 +859,18 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au return } - if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ImageCaptcha && !cpt.VerifyReq(ctx.Req) { - ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplLinkAccount, &form) - return - } + if setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha { + var valid bool + switch setting.Service.CaptchaType { + case setting.ImageCaptcha: + valid = cpt.VerifyReq(ctx.Req) + case setting.ReCaptcha: + valid, _ = recaptcha.Verify(form.GRecaptchaResponse) + default: + ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) + return + } - if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ReCaptcha { - valid, _ := recaptcha.Verify(form.GRecaptchaResponse) if !valid { ctx.Data["Err_Captcha"] = true ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplLinkAccount, &form) @@ -869,15 +878,24 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au } } - if (len(strings.TrimSpace(form.Password)) > 0 || len(strings.TrimSpace(form.Retype)) > 0) && form.Password != form.Retype { - ctx.Data["Err_Password"] = true - ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplLinkAccount, &form) - return - } - if len(strings.TrimSpace(form.Password)) > 0 && len(form.Password) < setting.MinPasswordLength { - ctx.Data["Err_Password"] = true - ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form) - return + if setting.Service.AllowOnlyExternalRegistration || !setting.Service.RequireExternalRegistrationPassword { + // In models.User an empty password is classed as not set, so we set form.Password to empty. + // Eventually the database should be changed to indicate "Second Factor"-enabled accounts + // (accounts that do not introduce the security vulnerabilities of a password). + // If a user decides to circumvent second-factor security, and purposefully create a password, + // they can still do so using the "Recover Account" option. + form.Password = "" + } else { + if (len(strings.TrimSpace(form.Password)) > 0 || len(strings.TrimSpace(form.Retype)) > 0) && form.Password != form.Retype { + ctx.Data["Err_Password"] = true + ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplLinkAccount, &form) + return + } + if len(strings.TrimSpace(form.Password)) > 0 && len(form.Password) < setting.MinPasswordLength { + ctx.Data["Err_Password"] = true + ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form) + return + } } loginSource, err := models.GetActiveOAuth2LoginSourceByName(gothUser.(goth.User).Provider) @@ -1000,14 +1018,18 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo return } - if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ImageCaptcha && !cpt.VerifyReq(ctx.Req) { - ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUp, &form) - return - } + if setting.Service.EnableCaptcha { + var valid bool + switch setting.Service.CaptchaType { + case setting.ImageCaptcha: + valid = cpt.VerifyReq(ctx.Req) + case setting.ReCaptcha: + valid, _ = recaptcha.Verify(form.GRecaptchaResponse) + default: + ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) + return + } - if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ReCaptcha { - valid, _ := recaptcha.Verify(form.GRecaptchaResponse) if !valid { ctx.Data["Err_Captcha"] = true ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUp, &form) diff --git a/routers/user/auth_openid.go b/routers/user/auth_openid.go index f98c07acd7..d6baf0d92b 100644 --- a/routers/user/auth_openid.go +++ b/routers/user/auth_openid.go @@ -357,19 +357,23 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["OpenID"] = oid - if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ImageCaptcha && !cpt.VerifyReq(ctx.Req) { - ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUpOID, &form) - return - } - - if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ReCaptcha { - err := ctx.Req.ParseForm() - if err != nil { - ctx.ServerError("", err) + if setting.Service.EnableCaptcha { + var valid bool + switch setting.Service.CaptchaType { + case setting.ImageCaptcha: + valid = cpt.VerifyReq(ctx.Req) + case setting.ReCaptcha: + err := ctx.Req.ParseForm() + if err != nil { + ctx.ServerError("", err) + return + } + valid, _ = recaptcha.Verify(form.GRecaptchaResponse) + default: + ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) return } - valid, _ := recaptcha.Verify(form.GRecaptchaResponse) + if !valid { ctx.Data["Err_Captcha"] = true ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUpOID, &form) diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index 3e67aa7b32..07f85c954f 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -15,10 +15,12 @@
      + {{if not .DisablePassword}}
      + {{end}} {{if not .LinkAccountMode}}
      diff --git a/templates/user/auth/signup_inner.tmpl b/templates/user/auth/signup_inner.tmpl index 25b50dad86..cdacd910d9 100644 --- a/templates/user/auth/signup_inner.tmpl +++ b/templates/user/auth/signup_inner.tmpl @@ -25,14 +25,17 @@
      -
      - - -
      -
      - - -
      + + {{if not .DisablePassword}} +
      + + +
      +
      + + +
      + {{end}} {{if and .EnableCaptcha (eq .CaptchaType "image")}}
      From 89aa08d372000da552a084e57276f2ea115e2e0c Mon Sep 17 00:00:00 2001 From: Drew Date: Sat, 6 Jul 2019 16:01:21 -0400 Subject: [PATCH 186/220] Fix mirror sync not automatically sending webhook requests (#7366) --- models/action.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/models/action.go b/models/action.go index 89283930e9..21b008e3be 100644 --- a/models/action.go +++ b/models/action.go @@ -896,6 +896,11 @@ func mirrorSyncAction(e Engine, opType ActionType, repo *Repository, refName str }); err != nil { return fmt.Errorf("notifyWatchers: %v", err) } + + defer func() { + go HookQueue.Add(repo.ID) + }() + return nil } From 7166629d9c2b71fe29a717a121bc080ba656cda2 Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Sat, 6 Jul 2019 16:32:15 -0400 Subject: [PATCH 187/220] Fix typo in PR migration check (#7368) --- modules/migrations/migrate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 5adf7f8050..7fc7911f21 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -205,7 +205,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if opts.PullRequests { log.Trace("migrating pull requests and comments") - var prBatchSize = models.MaxBatchInsertSize("pullrequest") + var prBatchSize = uploader.MaxBatchInsertSize("pullrequest") for i := 1; ; i++ { prs, err := downloader.GetPullRequests(i, prBatchSize) if err != nil { From 5b92bc1bec26de0143efccf70927bc9e46f9101c Mon Sep 17 00:00:00 2001 From: Cherrg Date: Sat, 6 Jul 2019 23:37:46 +0200 Subject: [PATCH 188/220] ui - cut timeline length with last element on issue view (#7355) * cut timeline length with last element on issue view fix #7304 - lightly enlight dark theme issue timeline color Signed-off-by: Michael Gnehr * remove new container Signed-off-by: Michael Gnehr --- public/css/index.css | 4 +++- public/css/theme-arc-green.css | 2 +- public/less/_repository.less | 23 ++++++++++++++++++++++- public/less/themes/arc-green.less | 5 +++-- templates/repo/issue/view_content.tmpl | 4 ++-- 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index f4f95ce081..8af38e4825 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -524,7 +524,9 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .pull .review-item .type-icon{float:right;margin-right:1em} .repository.view.issue .pull .review-item .divider{margin:.5rem 0} .repository.view.issue .pull .review-item .review-content{padding:1em 0 1em 3.8em} -.repository.view.issue .comment-list:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1} +.repository.view.issue .comment-list:not(.prevent-before-timeline):before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1} +.repository.view.issue .comment-list .timeline-line{position:relative;display:block;width:100%;max-width:100%} +.repository.view.issue .comment-list .timeline-line:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:82px;width:2px;background-color:#f3f3f3;z-index:-1} .repository.view.issue .comment-list .comment .avatar{width:3em} .repository.view.issue .comment-list .comment .tag{color:#767676;margin-top:3px;padding:2px 5px;font-size:12px;border:1px solid rgba(0,0,0,.1);border-radius:3px} .repository.view.issue .comment-list .comment .actions .item{float:left} diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index a93404cad0..2a7836efc8 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -118,7 +118,7 @@ footer{background:#2e323e;border-top:1px solid #313131} .repository.new.issue .comment.form .content:after{border-right-color:#353945} .repository.view.issue .comment-list .comment .content .header:before{border-right-color:#404552} .repository.new.issue .comment.form .content:before{border-right-color:#353945} -.repository.view.issue .comment-list:before{background-color:#313c47} +.repository.view.issue .comment-list .timeline-line:before,.repository.view.issue .comment-list:not(.prevent-before-timeline):before{background-color:#3b4954} .repository .comment.form .content .form:after{border-right-color:#313c47} .repository .comment.form .content .form:before{border-right-color:#313c47} .ui .text.grey a:hover{color:#dbdbdb!important} diff --git a/public/less/_repository.less b/public/less/_repository.less index 5a57f5db71..dd986c8832 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -749,7 +749,7 @@ } .comment-list { - &:before { + &:not(.prevent-before-timeline):before { display: block; content: ""; position: absolute; @@ -763,6 +763,27 @@ z-index: -1; } + .timeline-line { + position: relative; + display: block; + width: 100%; + max-width: 100%; + + &:before { + display: block; + content: ""; + position: absolute; + margin-top: 12px; + margin-bottom: 14px; + top: 0; + bottom: 0; + left: 82px; + width: 2px; + background-color: #f3f3f3; + z-index: -1; + } + } + .comment { .avatar { width: @comment-avatar-width; diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index 4780756bce..d4200b5162 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -619,8 +619,9 @@ a.ui.basic.green.label:hover { border-right-color: #353945; } -.repository.view.issue .comment-list:before { - background-color: #313c47; +.repository.view.issue .comment-list:not(.prevent-before-timeline):before, +.repository.view.issue .comment-list .timeline-line:before { + background-color: #3b4954; } .repository .comment.form .content .form:after { diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index cb85c5be97..16700a8dc1 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -9,8 +9,8 @@ {{end}} {{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.Lang }} -
      - +
      +
      From 362100023cc4fffbe053fc69bd8dd7252a30a0e3 Mon Sep 17 00:00:00 2001 From: Cherrg Date: Sun, 7 Jul 2019 00:03:00 +0200 Subject: [PATCH 189/220] ui - issue view - fix icon position (#7354) * issue view - fix icon position - move style from template to css - add bullets to: key, circle-slash, comment Signed-off-by: Michael Gnehr * add border to symbols Signed-off-by: Michael Gnehr * fix circle slash position Signed-off-by: Michael Gnehr * fix top margin Signed-off-by: Michael Gnehr * changed mixed space/tab indent to tabindent only Signed-off-by: Michael Gnehr --- public/css/index.css | 14 ++- public/css/theme-arc-green.css | 2 + public/less/_repository.less | 50 ++++++-- public/less/themes/arc-green.less | 8 ++ .../repo/issue/view_content/comments.tmpl | 108 +++++++++--------- 5 files changed, 115 insertions(+), 67 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 8af38e4825..437605e1d3 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -553,12 +553,18 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} .repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px} .repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px} +.repository.view.issue .comment-list .event>.octicon:not(.issue-symbol){text-shadow:-2px 0 #fff,0 2px #fff,2px 0 #fff,0 -2px #fff} +.repository.view.issue .comment-list .event>.octicon.issue-symbol{font-size:20px;margin-left:-35px;margin-right:-1px;margin-top:0!important;height:28px;width:28px;border-radius:50%;text-align:center;line-height:28px;background:#eee} +.repository.view.issue .comment-list .event>.octicon.issue-symbol::before{width:15px;display:inline-block} +.repository.view.issue .comment-list .event>.octicon.issue-symbol.octicon-key::before{width:18px} +.repository.view.issue .comment-list .event>.octicon.issue-symbol.octicon-circle-slash::before{width:17px} +.repository.view.issue .comment-list .event>.octicon.issue-symbol.octicon-comment{font-size:21px;line-height:33px} +.repository.view.issue .comment-list .event>.octicon.issue-symbol.octicon-comment::before{width:20px} .repository.view.issue .comment-list .event .octicon{width:30px;float:left;text-align:center} .repository.view.issue .comment-list .event .octicon.octicon-circle-slash{margin-top:5px;margin-left:-34.5px;font-size:20px;color:#bd2c00} -.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644} -.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:3px;margin-left:-31px;margin-right:-1px;font-size:25px} -.repository.view.issue .comment-list .event .octicon.octicon-comment{margin-top:4px;margin-left:-35px;font-size:24px} -.repository.view.issue .comment-list .event .octicon.octicon-eye{margin-top:3px;margin-left:-35px;margin-right:0;font-size:22px} +.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-top:-1px;margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644} +.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:2px;margin-left:-31px;margin-right:-1px;font-size:25px} +.repository.view.issue .comment-list .event .octicon.octicon-eye{margin-top:3px;margin-left:-36px;margin-right:0;font-size:22px} .repository.view.issue .comment-list .event .octicon.octicon-x{margin-left:-33px;font-size:25px} .repository.view.issue .comment-list .event .detail{font-size:.9rem;margin-top:5px;margin-left:35px} .repository.view.issue .comment-list .event .detail .octicon.octicon-git-commit{margin-top:2px} diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index 2a7836efc8..b48e22b41e 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -112,6 +112,8 @@ footer{background:#2e323e;border-top:1px solid #313131} .repository.view.issue .comment-list .comment .content>.bottom.segment{background:#353945} .repository.view.issue .comment-list .comment .content .header{color:#dbdbdb;background-color:#404552;border-bottom:1px solid #353944} .repository.view.issue .comment-list .comment .content .merge-section{background-color:#404552;border-top:1px solid #353944} +.repository.view.issue .comment-list .event>.octicon.issue-symbol{background:#3b4954} +.repository.view.issue .comment-list .event>.octicon:not(.issue-symbol){text-shadow:-2px 0 #383c4a,0 2px #383c4a,2px 0 #383c4a,0 -2px #383c4a} .ui .text.grey a{color:#dbdbdb!important} .ui.comments .comment .actions a{color:#dbdbdb} .repository.view.issue .comment-list .comment .content .header:after{border-right-color:#404552} diff --git a/public/less/_repository.less b/public/less/_repository.less index dd986c8832..21aeea81e7 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -920,6 +920,45 @@ margin: 15px 0 15px 79px; padding-left: 25px; + & > .octicon:not(.issue-symbol) { + text-shadow: -2px 0 #fff, 0 2px #fff, 2px 0 #fff, 0 -2px #fff; + } + + & > .octicon.issue-symbol { + font-size: 20px; + margin-left: -35px; + margin-right: -1px; + margin-top: 0 !important; + height: 28px; + width: 28px; + border-radius: 50%; + text-align: center; + line-height: 28px; + background: #eee; + + &::before { + width: 15px; + display: inline-block; + } + + &.octicon-key::before { + width: 18px; + } + + &.octicon-circle-slash::before { + width: 17px; + } + + &.octicon-comment { + font-size: 21px; + line-height: 33px; + + &::before { + width: 20px; + } + } + } + .octicon { width: 30px; float: left; @@ -933,6 +972,7 @@ } &.octicon-primitive-dot { + margin-top: -1px; margin-left: -28.5px; margin-right: -1px; font-size: 30px; @@ -940,21 +980,15 @@ } &.octicon-bookmark { - margin-top: 3px; + margin-top: 2px; margin-left: -31px; margin-right: -1px; font-size: 25px; } - &.octicon-comment { - margin-top: 4px; - margin-left: -35px; - font-size: 24px; - } - &.octicon-eye { margin-top: 3px; - margin-left: -35px; + margin-left: -36px; margin-right: 0; font-size: 22px; } diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index d4200b5162..cde5b5e7f5 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -595,6 +595,14 @@ a.ui.basic.green.label:hover { border-top: 1px solid #353944; } +.repository.view.issue .comment-list .event > .octicon.issue-symbol { + background: #3b4954; +} + +.repository.view.issue .comment-list .event > .octicon:not(.issue-symbol) { + text-shadow: -2px 0 #383c4a, 0 2px #383c4a, 2px 0 #383c4a, 0 -2px #383c4a; +} + .ui .text.grey a { color: #dbdbdb !important; } diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 6f562dc6b0..20474f6302 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -82,7 +82,7 @@
      {{else if eq .Type 2}}
      - + @@ -172,7 +172,7 @@ {{$.i18n.Tr "repo.issues.delete_branch_at" (.CommitSHA|Escape) $createdStr | Safe}}
      - {{else if eq .Type 12}} + {{else if eq .Type 12}} {{else if eq .Type 19}}
      - - + + - - - {{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}} - -
      - + + + {{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}} + + -
      +
      {{else if eq .Type 20}}
      - - - - - - {{$.i18n.Tr "repo.issues.dependency.removed_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}} - -
      - + + + + + + {{$.i18n.Tr "repo.issues.dependency.removed_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}} + + -
      +
      +
      {{else if eq .Type 22}} -
      - - - - - {{.Poster.GetDisplayName}} - {{if eq .Review.Type 1}} - {{$.i18n.Tr "repo.issues.review.approve" $createdStr | Safe}} - {{else if eq .Review.Type 2}} - {{$.i18n.Tr "repo.issues.review.comment" $createdStr | Safe}} - {{else if eq .Review.Type 3}} - {{$.i18n.Tr "repo.issues.review.reject" $createdStr | Safe}} - {{else}} - {{$.i18n.Tr "repo.issues.review.comment" $createdStr | Safe}} - {{end}} - - {{if .Content}} -
      +
      + + + + + {{.Poster.GetDisplayName}} + {{if eq .Review.Type 1}} + {{$.i18n.Tr "repo.issues.review.approve" $createdStr | Safe}} + {{else if eq .Review.Type 2}} + {{$.i18n.Tr "repo.issues.review.comment" $createdStr | Safe}} + {{else if eq .Review.Type 3}} + {{$.i18n.Tr "repo.issues.review.reject" $createdStr | Safe}} + {{else}} + {{$.i18n.Tr "repo.issues.review.comment" $createdStr | Safe}} + {{end}} + + {{if .Content}} +
      - {{.Content}} -
      - {{end}} + {{.Content}} +
      + {{end}} {{ range $filename, $lines := .Review.CodeComments}} {{range $line, $comms := $lines}}
      @@ -358,36 +358,34 @@
      {{end}} {{end}} -
      +
      {{else if eq .Type 23}}
      - + {{ if .Content }} - {{.Poster.GetDisplayName}} + {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.lock_with_reason" .Content $createdStr | Safe}} - + {{ else }} - {{.Poster.GetDisplayName}} + {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.lock_no_reason" $createdStr | Safe}} - + {{ end }}
      {{else if eq .Type 24}}
      - + - {{.Poster.GetDisplayName}} - {{$.i18n.Tr "repo.issues.unlock_comment" $createdStr | Safe}} - + {{.Poster.GetDisplayName}} + {{$.i18n.Tr "repo.issues.unlock_comment" $createdStr | Safe}} +
      {{end}} {{end}} From 8baa2dc8eb975f575360684f2b1c24f606aea8af Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 6 Jul 2019 22:14:41 +0000 Subject: [PATCH 190/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_lv-LV.ini | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 01a8bd070c..cdc0df84ca 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -86,12 +86,18 @@ host=Resursdators user=Lietotāja vārds password=Parole db_name=Datu bāzes nosaukums +db_helper=Piezīme MySQL lietotājiem: izmantojiet InnoDB glabāšanas programmu, un ja izmantojat "utf8mb4", tad InnoDB versijai ir jābūt lielākai par 5.6. ssl_mode=SSL +charset=Rakstzīmju kopa path=Ceļš sqlite_helper=Faila ceļš SQLite3 datu bāzei.
      Ievadiet absolūto ceļu, ja Gitea tiek startēts kā serviss. err_empty_db_path=Nav norādīts SQLite3 datu bāzes ceļš. no_admin_and_disable_registration=Reģistrāciju nevar atslēgt, kamēr nav izveidots administratora konts. err_empty_admin_password=Administratora kontam ir obligāti jānorāda parole. +err_empty_admin_email=Administratora e-pasta adrese nevar būt tukša. +err_admin_name_is_reserved=Administratora lietotāja nav korekts, šāds lietotāja vārds ir rezervēts +err_admin_name_pattern_not_allowed=Administratora lietotāja nav korekts, šāds lietotāja vārds satur neatļautus simbolus +err_admin_name_is_invalid=Administratora lietotāja nav korekts general_title=Vispārīgie iestatījumi app_name=Vietnes nosaukums @@ -243,6 +249,10 @@ openid_register_desc=Izvēlētais OpenID konts sistēmā netika atpazīts, bet J openid_signin_desc=Ievadiet savu OpenID URI, piemēram: https://anna.me, peteris.openid.org.lv, gnusocial.net/janis. disable_forgot_password_mail=Paroles atjaunošanas iespēja ir atslēgta. Sazinieties ar lapas administratoru. email_domain_blacklisted=Nav atļauts reģistrēties ar šādu e-pasta adresi. +authorize_application=Autorizēt lietotni +authroize_redirect_notice=Jūs tiksiet nosūtīts uz %s, ja autorizēsiet šo lietotni. +authorize_application_created_by=Šo lietotni izveidoja %s. +authorize_application_description=Ja piešķirsiet tiesības, tā varēs piekļūt un mainīt Jūsu konta informāciju, ieskaitot privātos repozitorijus un organizācijas. authorize_title=Autorizēt "%s" piekļuvi jūsu kontam? authorization_failed=Autorizācija neizdevās authorization_failed_desc=Autorizācija neizdevās, jo tika veikts kļūdains pieprasījums. Sazinieties ar lietojumprogrammas, ar kuru mēģinājāt autorizēties, uzturētāju. @@ -250,6 +260,7 @@ authorization_failed_desc=Autorizācija neizdevās, jo tika veikts kļūdains pi [mail] activate_account=Lūdzu, aktivizējiet savu kontu activate_email=Apstipriniet savu e-pasta adresi +reset_password=Atgūt kontu register_success=Veiksmīga reģistrācija register_notify=Laipni lūdzam Gitea @@ -294,6 +305,8 @@ password_not_match=Izvēlētā parole nesakrīt ar atkārtoti ievadīto. username_been_taken=Lietotājvārds jau ir aizņemts. repo_name_been_taken=Jau eksistē repozitorijs ar šādu nosaukumu. +visit_rate_limit=Attālinātā piekļuve ir ierobežota ar ātruma ierobežotāju. +2fa_auth_required=Attālinātai piekļuvei ir nepieciešama divu faktoru autentifikācija. org_name_been_taken=Organizācijas nosaukums jau ir aizņemts. team_name_been_taken=Komandas nosaukums jau ir aizņemts. team_no_units_error=Komandai ir jābūt iespējotai vismaz vienai sadaļai. @@ -375,6 +388,7 @@ choose_new_avatar=Izvēlēties jaunu profila attēlu update_avatar=Saglabāt profila bildi delete_current_avatar=Dzēst pašreizējo profila bildi uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls. +uploaded_avatar_is_too_big=Augšupielādētais fails parsniedz maksimālo izmēru. update_avatar_success=Profila attēls tika saglabāts. change_password=Mainīt paroli @@ -469,12 +483,37 @@ access_token_deletion=Dzēst piekļuves talonu access_token_deletion_desc=Dzēšot piekļuves talonu tiks liegta piekļuve visām aplikācijām, kas to izmanto. Vai turpināt? delete_token_success=Piekļuves talons tika noņemts. Neaizmirstiet atjaunot informāciju lietojumprogrammās, kas izmantoja šo talonu. +manage_oauth2_applications=Pārvaldīt OAuth2 lietotnes +edit_oauth2_application=Labot OAuth2 lietotni +oauth2_applications_desc=OAuth2 lietotnes ļauj trešo pušu lietotnēm droša veidā autentificēt lietotajus šajā Gitea instancē. +remove_oauth2_application=Noņemt OAuth2 lietotni +remove_oauth2_application_desc=Noņemot OAuth2 lietotni tiks noņemta piekļuve visiem parakstītajiem piekļuves taloniem. Vai turpināt? +remove_oauth2_application_success=Lietotne tika dzēsta. +create_oauth2_application=Izveidot jaunu OAuth2 lietotni +create_oauth2_application_button=Izveidot lietotni +create_oauth2_application_success=OAuth2 lietotne veiksmīgi izveidota. +update_oauth2_application_success=OAuth2 lietotne veiksmīgi atjaunināta. +oauth2_application_name=Lietotnes nosaukums +oauth2_select_type=Kāds lietotnes veids visvairāk atbilst? +oauth2_type_web=Tīmekļa (piemēram, Node.JS, Tomcat, Go) +oauth2_type_native=Specializētā (piemēram, mobilā, darbvirsmas, tīmekļa pārlūks) oauth2_redirect_uri=Novirzīšanas URI save_application=Saglabāt oauth2_client_id=Klienta ID oauth2_client_secret=Klienta noslēpums +oauth2_regenerate_secret=Pārģenerēt noslēpumus +oauth2_regenerate_secret_hint=Pazaudēts noslēpums? +oauth2_client_secret_hint=Atverot šo lapu atkārtoti, šis noslēpums vairs nebūs redzams. Saglabājiet to. oauth2_application_edit=Labot +oauth2_application_create_description=OAuth2 lietotnes ļauj trešas puses lietotnēm piekļūt lietotāja kontiem šajā instancē. +oauth2_application_remove_description=Noņemot OAuth2 lietotni neļaus trešas puses lietotnēm piekļūt lietotāja kontiem šajā instancē. Vai turpināt? +authorized_oauth2_applications=Autorizētās OAuth2 lietotnes +authorized_oauth2_applications_description=Jūs esat atļāvis piekļuvi savam Gitea kontam šādām trešo pušu lietotnēm. Atsauciet piekļuvi lietotnēm, kas vairs nav vajadzīgas. +revoke_key=Atsaukt +revoke_oauth2_grant=Atsaukt piekļuvi +revoke_oauth2_grant_description=Atsaucot piekļuvi šai trešas puses lietotnei tiks liegta piekļuve Jūsu datiem. Vai turpināt? +revoke_oauth2_grant_success=Piekļuve veiksmīgi atsaukta. twofa_desc=Divu faktoru autentifikācija uzlabo Jūsu konta drošību. twofa_is_enrolled=Kontam ir ieslēgta divu faktoru autentifikācija. @@ -544,6 +583,9 @@ mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā mirror_interval=Spoguļošanas biežums (atļautās laika vienības 'h', 'm' un 's'). Ievadiet 0, lai atslēgtu automātisko spoguļošanu. mirror_interval_invalid=Nekorekts spoguļošanas intervāls. mirror_address=Spoguļa adrese +mirror_address_desc=Iekļaujiet visus nepieciešamos autorizācijas akreditācijas datus URL. Tiem ir jābūt korekti pierakstītiem +mirror_address_url_invalid=Norādītais URL nav korekts. Norādiet visas URL daļas korekti. +mirror_address_protocol_invalid=Norādītais URL nav korekts. Var spoguļot tikai no http(s):// vai git:// adresēm. mirror_last_synced=Pēdējo reizi sinhronizēts watchers=Novērotāji stargazers=Zvaigžņdevēji @@ -562,6 +604,13 @@ form.name_pattern_not_allowed=Repozitorija nosaukums '%s' nav atļauts. need_auth=Nepieciešama autorizācija migrate_type=Migrācijas veids migrate_type_helper=Šis repozitorijs būs spogulis +migrate_items=Vienības, ko pārņemt +migrate_items_wiki=Vikivietni +migrate_items_milestones=Atskaites punktus +migrate_items_labels=Etiķetes +migrate_items_issues=Problēmas +migrate_items_pullrequests=Izmaiņu pieprasījumus +migrate_items_releases=Laidienus migrate_repo=Migrēt repozitoriju migrate.clone_address=Klonēšanas adrese migrate.clone_address_desc=Tā var būt HTTP(S) adrese vai Git 'clone' URL eksistējošam repozitorijam @@ -570,6 +619,7 @@ migrate.permission_denied=Jums nav tiesību importēt lokālu repozitoriju. migrate.invalid_local_path=Nederīgs lokālais ceļš. Tas neeksistē vai nav direktorija. migrate.failed=Migrācija neizdevās: %v migrate.lfs_mirror_unsupported=LFS objektu spoguļošana netiek atbalstīta - tā vietā izmantojiet 'git lfs fetch --all' un 'git lfs push --all'. +migrate.migrate_items_options=Pārņemot datus no GitHub, ievadiet lietotāja vārdu, lai redzētu papildus iestatījumus. mirror_from=spogulis no forked_from=atdalīts no @@ -646,12 +696,14 @@ editor.create_new_branch=Izveidot jaunu atzaru un izmaiņu piep editor.new_branch_name_desc=Jaunā atzara nosaukums… editor.cancel=Atcelt editor.filename_cannot_be_empty=Faila nosaukums nevar būt tukšs. +editor.filename_is_invalid=Faila nosaukums nav korekts: '%s'. editor.branch_does_not_exist=Šajā repozitorijā neeksistē atzars '%s'. editor.branch_already_exists=Atzars '%s' šajā repozitorijā jau eksistē. editor.directory_is_a_file=Ieraksts '%s' vecāka ceļā ir fails nevis direktorija šajā repozitorijā. editor.file_is_a_symlink=Fails '%s' ir norāde, kuru nav iespējams labot no tīmekļa redaktora editor.filename_is_a_directory=Faila nosaukums '%s' sakrīt ar direktorijas nosaukumu šajā repozitorijā. editor.file_editing_no_longer_exists=Fails '%s', ko labojat, vairs neeksistē šajā repozitorijā. +editor.file_deleting_no_longer_exists=Fails '%s', ko dzēšat, vairs neeksistē šajā repozitorijā. editor.file_changed_while_editing=Faila saturs ir mainījies kopš sākāt to labot. Noklikšķiniet šeit, lai apskatītu, vai Nosūtiet izmaiņas atkārtoti, lai pārrakstītu. editor.file_already_exists=Fails ar nosaukumu '%s' šajā repozitorijā jau eksistē. editor.no_changes_to_show=Nav izmaiņu, ko rādīt. @@ -665,6 +717,7 @@ commits.desc=Pārlūkot pirmkoda izmaiņu vēsturi. commits.commits=Revīzijas commits.no_commits=Nav kopīgu revīziju. Atzariem '%s' un '%s' ir pilnībā atšķirīga izmaiņu vēsture. commits.search=Meklēt revīzijas… +commits.search.tooltip=Jūs varat izmantot atslēgas vārdus "author:", "committer:", "after:" vai "before:", piemēram, "revert author:Alice before:2019-04-01". commits.find=Meklēt commits.search_all=Visi atzari commits.author=Autors @@ -801,12 +854,26 @@ issues.lock=Slēgt komentēšanu issues.unlock=Atļaut komentēšanu issues.lock.unknown_reason=Neizdevās slēgt problēmas komentēšanu. issues.lock_duplicate=Problēmas komentēšanu nevar slēgt vairākas reizes. +issues.unlock_error=Nevar atļaut komentēšanu, ja problēmai tā nav slēgta. +issues.lock_with_reason=slēdza ar iemeslu %s un ierobežoja komentāru pievienošanu tikai līdzstrādniekiem %s +issues.lock_no_reason=slēdza un ierobežoja komentāru pievienošanu tikai līdzstrādniekiem %s +issues.unlock_comment=atļāva komentēšanu %s issues.lock_confirm=Slēgt issues.unlock_confirm=Atļaut +issues.lock.notice_1=- Citi lietotāji nevar pievienot jaunus komentārus šai problēmai. +issues.lock.notice_2=- Jums un citiem līdzstrādniekiem ar piekļuvi šim repozitorijam tiks saglabāta iespēja pievienot komentārus. +issues.lock.notice_3=- Jūs vienmēr varat atkal atļaut komentēšanu. +issues.unlock.notice_1=- Ikviens varēs atkal pievienot jaunus komentārus. +issues.unlock.notice_2=- Jūs vienmēr varat atkal slēgt komentēšanu. +issues.lock.reason=Slēgšanas iemesls +issues.lock.title=Slēgt komentēšanu šai problēmai. +issues.unlock.title=Atļaut komentēšanu šai problēmai. +issues.comment_on_locked=Jūs nevarat komentēt slēgtai problēmai. issues.tracker=Laika uzskaite issues.start_tracking_short=Sākt issues.start_tracking=Uzsākt laika uzskaiti issues.start_tracking_history=` uzsāka darbu %s` +issues.tracker_auto_close=Taimeris tiks automātiski apturēts, kad šī problēma tiks aizvērta issues.tracking_already_started=`Jums jau ir iesākta laika uzskaite pie citas problēmas!` issues.stop_tracking=Beigt issues.stop_tracking_history=` beidza strādāt %s` @@ -892,11 +959,13 @@ pulls.tab_conversation=Saruna pulls.tab_commits=Revīzijas pulls.tab_files=Izmainītie faili pulls.reopen_to_merge=Atkārtoti atveriet izmaiņu pieprasījumu, lai veiktu sapludināšanu. +pulls.cant_reopen_deleted_branch=Šo izmaiņu pieprasīju nevar atkāroti atvērt, jo atzars ir izdzēsts. pulls.merged=Sapludināts pulls.has_merged=Šis izmaiņu pieprasījums tika veiksmīgi sapludināts. pulls.title_wip_desc=`Sāciet virsrakstu ar %s, lai ierobežotu, ka izmaiņu pieprasījums netīšām tiktu sapludināts.` pulls.cannot_merge_work_in_progress=Šis izmaiņu pieprasījums ir atzīmēts, ka pie tā vēl notiek izstrāde. Noņemiet %s no virsraksta sākuma, kad tas ir pabeigts. pulls.data_broken=Izmaiņu pieprasījums ir bojāts, jo dzēsta informācija no atdalītā repozitorija. +pulls.files_conflicted=Šīs izmaiņu pieprasījuma izmaiņas konfliktē ar mērķa atzaru. pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu. pulls.blocked_by_approvals=Šim izmaiņu pieprasījumam nav nepieciešamais apstiprinājumu daudzums. %d no %d apstiprinājumi piešķirti. pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski sapludināt. @@ -911,6 +980,9 @@ pulls.rebase_merge_commit_pull_request=Pārbāzēt un sapludināt (--no-ff) pulls.squash_merge_pull_request=Saspiest un sapludināt pulls.invalid_merge_option=Nav iespējams izmantot šādu sapludināšanas veidu šim izmaiņu pieprasījumam. pulls.open_unmerged_pull_exists=`Jūs nevarat veikt atkārtotas atvēršanas darbību, jo jau eksistē izmaiņu pieprasījums (#%d) ar šādu sapludināšanas informāciju.` +pulls.status_checking=Dažas pārbaudes vēl tiek veiktas +pulls.status_checks_success=Visas pārbaudes ir veiksmīgas +pulls.status_checks_error=Dažas pārbaudes bija neveiksmīgas milestones.new=Jauns atskaites punkts milestones.open_tab=%d atvērti @@ -1078,6 +1150,7 @@ settings.pulls.allow_rebase_merge_commit=Iespējot pārbāzēšanu sapludinot re settings.pulls.allow_squash_commits=Iespējot saspiešanu sapludinot revīzijas settings.admin_settings=Administratora iestatījumi settings.admin_enable_health_check=Iespējot veselības pārbaudi (git fsck) šim repozitorijam +settings.admin_enable_close_issues_via_commit_in_any_branch=Aizvērt problēmu ar izmaiņu komentāru iesūtītu jebkurā atzarā settings.danger_zone=Bīstamā zona settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu. settings.convert=Konvertēt uz parastu repozitoriju @@ -1204,7 +1277,9 @@ settings.protected_branch_can_push_yes=Jūs varat nosūtīt izmaiņas settings.protected_branch_can_push_no=Jūs nevarat nosūtīt izmaiņas settings.branch_protection=Atzara aizsardzība atzaram '%s' settings.protect_this_branch=Iespējot atzara aizsardzību +settings.protect_this_branch_desc=Neļaut dzēšanu un atspējot jebkādu Git izmaiņu nosūtīšanu uz šo atzaru. settings.protect_whitelist_committers=Iespējot izmaiņu nosūtīšanas ierobežojumus +settings.protect_whitelist_committers_desc=Atļaut norādītajiem lietotājiem vai komandām iesūtīt šajā atzarā (bet ne veikt piespiedu piegādi). settings.protect_whitelist_users=Lietotāji, kas var veikt izmaiņu nosūtīšanu: settings.protect_whitelist_search_users=Meklēt lietotājus… settings.protect_whitelist_teams=Komandas, kas var veikt izmaiņu nosūtīšanu: @@ -1229,19 +1304,25 @@ settings.no_protected_branch=Nav neviena aizsargātā atzara. settings.edit_protected_branch=Labot settings.protected_branch_required_approvals_min=Pieprasīto recenziju skaits nevar būt negatīvs. settings.bot_token=Bota talons +settings.chat_id=Tērzēšanas ID settings.archive.button=Arhivēt settings.archive.header=Arhivēt repozitoriju settings.archive.text=Arhivējot repozitoriju, tas paliks tikai skatīšanās režīmā. Tas netiks attēlots infopanelī, tam nevarēs iesūtīt jaunas izmaiņas, kā arī pieteikt jaunas problēmas un veidot jaunus izmaiņu pieprasījumus. settings.archive.success=Repozitorijs veiksmīgi arhivēts. +settings.archive.error=Arhivējot repozitoriju radās neparedzēta kļūda. Pārbaudiet kļūdu žurnālu, lai uzzinātu sīkāk. settings.archive.error_ismirror=Nav iespējams arhivēt spoguļotus repozitorijus. settings.archive.branchsettings_unavailable=Atzaru iestatījumi nav pieejami, ja repozitorijs ir arhivēts. settings.unarchive.button=Atcelt arhivāciju settings.unarchive.header=Atcelt repozitorija arhivāciju +settings.unarchive.text=Atceļot repozitoriju arhivāciju, tam atkal varēs iesūtīt jaunas izmaiņas, kā arī pieteikt problēmas un veidot izmaiņu pieprasījumus. settings.unarchive.success=Repozitorijam veiksmīgi atcelta arhivācija. +settings.unarchive.error=Atceļot repozitorija arhivāciju radās neparedzēta kļūda. Pārbaudiet kļūdu žurnālu, lai uzzinātu sīkāk. +settings.update_avatar_success=Repozitorija attēls tika atjaunināts. diff.browse_source=Pārlūkot izejas kodu diff.parent=vecāks diff.commit=revīzija +diff.git-notes=Piezīmes diff.data_not_available=Satura salīdzināšana nav pieejama diff.show_diff_stats=Rādīt salīdzināšanas statistiku diff.show_split_view=Dalītais skats @@ -1419,6 +1500,7 @@ dashboard=Infopanelis users=Lietotāju konti organizations=Organizācijas repositories=Repozitoriji +hooks=Noklusēti tīmekļa āķi authentication=Autentificēšanas avoti config=Konfigurācija notices=Sistēmas paziņojumi @@ -1442,6 +1524,8 @@ dashboard.delete_repo_archives=Dzēst visu repozitoriju arhīvus dashboard.delete_repo_archives_success=Visu repozitoriju arhīvi tika izdzēsti. dashboard.delete_missing_repos=Dzēst visus repozitorijus, kam trūkst Git failu dashboard.delete_missing_repos_success=Visi repozitoriji, kam trūka Git failu, tika pilnībā dzēsti. +dashboard.delete_generated_repository_avatars=Dzēst ģenerētos repozitoriju attēlus +dashboard.delete_generated_repository_avatars_success=Ģenerētie repozitoriju attēli tika izdzēsti. dashboard.git_gc_repos=Veikt atkritumu uzkopšanas darbus visiem repozitorijiem dashboard.git_gc_repos_success=Atkritumu uzkopšanas darbi visiem repozitorijiem pabeigti. dashboard.resync_all_sshkeys=Pārrakstīt '.ssh/authorized_keys' failu ar Gitea SSH atslēgām. (To nav nepieciešams darīt, ja izmantojat iebūvēto SSH serveri.) @@ -1532,6 +1616,9 @@ repos.forks=Atdalītie repos.issues=Problēmas repos.size=Izmērs +hooks.desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikumiem, kas notiek Gitea. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Šeit izveidotie tīmekļa āķi tiks pievienoti visiem jaunajajiem repozitorijiem. Lai uzzinātu sīkāk skatieties tīmekļa āķu rokasgrāmatā. +hooks.add_webhook=Pievienot noklusēto tīmekļa āķi +hooks.update_webhook=Mainīt noklusēto tīmekļa āķi auths.auth_manage_panel=Autentifikācijas avotu pārvaldība auths.new=Pievienot autentifikācijas avotu @@ -1611,6 +1698,7 @@ config.app_name=Vietnes nosaukums config.app_ver=Gitea versija config.app_url=Gitea pamata URL config.custom_conf=Konfigurācijas faila ceļš +config.custom_file_root_path=Pielāgoto failu pamata ceļš config.domain=SSH servera domēns config.offline_mode=Bezsaistes režīms config.disable_router_log=Atspējot maršrutētāja žurnalizēšanu @@ -1636,6 +1724,10 @@ config.ssh_keygen_path=Keygen ('ssh-keygen') ceļš config.ssh_minimum_key_size_check=Minimālā atslēgas lieluma pārbaude config.ssh_minimum_key_sizes=Minimālais atslēgas lielums +config.lfs_config=LFS konfigurācija +config.lfs_enabled=Iespējots +config.lfs_content_path=LFS satura ceļš +config.lfs_http_auth_expiry=LFS HTTP autorizācijas beigšanās config.db_config=Datu bāzes konfigurācija config.db_type=Veids @@ -1657,6 +1749,7 @@ config.mail_notify=Iespējot e-pasta paziņojumus config.disable_key_size_check=Atspējot atslēgas minimālā garuma pārbaudi config.enable_captcha=Iespējot drošības kodu config.active_code_lives=Aktīvā koda ilgums +config.reset_password_code_lives=Konta atjaunošanas koda beigšanās laiks config.default_keep_email_private=Pēc noklusējuma slēpt e-pasta adreses config.default_allow_create_organization=Pēc noklusējuma ļaut veidot organizācijas config.enable_timetracking=Iespējot laika uzskaiti @@ -1691,6 +1784,7 @@ config.cache_config=Kešatmiņas konfigurācija config.cache_adapter=Kešatmiņas adapteris config.cache_interval=Kešatmiņas intervāls config.cache_conn=Kešatmiņas pieslēguma parametri +config.cache_item_ttl=Kešatmiņas vienuma TTL config.session_config=Sesijas konfigurācja config.session_provider=Sesijas nodrošinātājs @@ -1721,8 +1815,15 @@ config.git_gc_timeout=GC darbības noilgums config.log_config=Žurnalizēšanas konfigurācija config.log_mode=Žurnalizēšanas veids +config.macaron_log_mode=Macaron žurnalizēšanas veids +config.own_named_logger=Pielāgots žurnalizētājs +config.routes_to_default_logger=Pārsūtīt uz noklusēto žurnalizētāju +config.go_log=Izmanto Go žurnalizēšanu (pārsūtīts uz noklusēto) +config.router_log_mode=Maršrutētāja žurnalizēšanas veids config.disabled_logger=Atspējots +config.access_log_mode=Piekļuves žurnalizēšanas veids config.access_log_template=Šablons +config.xorm_log_mode=XORM žurnalizēšanas veids config.xorm_log_sql=SQL žurnalizēšana monitor.cron=Cron uzdevumi @@ -1767,6 +1868,7 @@ push_tag=pievienoja tagu %[2]s repozitorijam %[3]s delete_branch=izdzēsa atzaru %[2]s no %[3]s compare_commits=Salīdzināt %d revīzijas +compare_commits_general=Salīdzināt revīzijas mirror_sync_push=ar spoguli sinhronizētas revīzijas %[3]s uz repozitoriju %[4]s mirror_sync_create=ar spoguli sinhronizēta jauna atsauce %[2]s uz repozitoriju %[3]s mirror_sync_delete=ar spoguli sinhronizēta un izdzēsta atsauce %[2]s repozitorijam %[3]s From 7b82056b0e332249823b1ece5370b2bab4201822 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 6 Jul 2019 19:00:49 -0400 Subject: [PATCH 191/220] 1.9.0-RC1 changelog (#7367) --- CHANGELOG.md | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f66d08ec4e..790263d641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,324 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.9.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.9.0-rc1) - 2019-07-06 +* BREAKING + * Better logging (#6038) (#6095) +* FEATURE + * Content API for Creating, Updating, Deleting Files (#6314) + * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229) + * Add command to convert mysql database from utf8 to utf8mb4 (#7144) + * Fixes #2738 - Adds the /git/tags API endpoint (#7138) + * Compare branches, commits and tags with each other (#6991) + * Show Pull Request button or status of latest PR in branch list (#6990) + * Repository avatars (#6986) + * Show git-notes (#6984) + * Add commit statuses reports on pull request view (#6845) + * Number of commits ahead/behind in branch overview (#6695) + * Add CLI commands to manage LDAP authentication source (#6681) + * Add support for MS Teams webhooks (#6632) + * OAuth2 Grant UI (#6625) + * Add SUBJECT_PREFIX mailer config option (#6605) + * Include custom configuration file in dump (#6516) + * Add API for manipulating Git hooks (#6436) + * Improve migrations to support migrating milestones/labels/issues/comments/pullrequests (#6290) + * Add option to blame files (#5721) + * Implement Default Webhooks (#4299) + * Telegram webhook (#4227) +* BUGFIXES + * Correctly adjust mirror url (#6593) + * Handle early git version's lack of get-url (#7065) + * Fix icon position in issue view (#7354) + * Cut timeline length with last element on issue view (#7355) + * Fix mirror repository webhooks (#7366) + * Fix api route for hooks (#7346) + * Fix bug conflict between SyncReleasesWithTags and InsertReleases (#7337) + * Fix pull view ui merge section (#7335) + * Fix 7303 - remove unnessesary buttons on archived repos (#7326) + * Fix topic bar to allow prefixes (#7325) + * Fixes #7152 - Allow create/update/delete message to be empty, use default message (#7324) + * Fixes #7238 - Annotated tag commit ID incorrect (#7321) + * Dark theme fixes (#7319) + * Gitea own dark codemirror theme (#7317) + * Fixes #7292 - API File Contents bug (#7301) + * Fix API link header (#7298) + * Fix extra newlines when copying from diff in Firefox (#7288) + * Make diff line-marker non-selectable (#7279) + * Fix Submodule dection in subdir (#7275) + * Fix error log when loading issues caused by a xorm bug (#7271) + * Add .fa icon margin like .octicon (#7258) + * Fix hljs unintenionally highlighting commit links (#7244) + * Only check and config git on web subcommand but not others (#7236) + * Fix migration panic when Head.User is not exist (#7226) + * Only warn on errors in deleting LFS orphaned files during repo deletion (#7213) + * Fix duplicated file on pull request conflicted files (#7211) + * Allow colon between fixing word and issue (#7207) + * Fix overflow issues in repo (#7190) + * API error cleanup (#7186) + * Add error for fork already existing (#7185) + * Fixes diff on merged pull requests (#7171) + * If milestone id is zero don't get it from database (#7169) + * Fix pusher name via ssh push (#7167) + * Fix database lock when use random repository fallback image (#7166) + * Various fixes for issue mail notifications (#7165) + * Allow archived repos to be (un)starred and (un)watched (#7163) + * Fix GCArgs load from ini (#7156) + * Detect noreply email address as user (#7133) + * Avoid arbitrary format strings upon calling fail() function (#7112) + * Validate External Tracker URL Format (#7089) + * Repository avatar fallback configuration (#7087) + * Fix #732: Add LFS objects to base repository on merging (#7082) + * Install page - Handle invalid administrator username better (#7060) + * Workaround for posting single comments in split diff view (#7052) + * Fix possbile mysql invalid connnection error (#7051) + * Fix charset was not saved after installation finished (#7048) + * Handle insecure and ports in go get (#7041) + * Avoid bad database state after failed migration (#7040) + * Fix wrong init dependency on markup extensions (#7038) + * Fix default for allowing new organization creation for new users (#7017) + * Fix content download and /verify LFS handler expecting wrong content-type (#7015) + * Fix missing repo description when migrating (#7000) + * Fix LFS Locks over SSH (#6999) + * Do not attempt to return blob on submodule (#6996) + * Fix U2F for Chrome >= 74 (#6980) + * Fix index produces problem when issues/pulls deleted (#6973) + * Allow collaborators to view repo owned by private org (#6965) + * Stop running hooks on pr merge (#6963) + * Run hooks on merge/edit and cope with protected branches (#6961) + * Webhook Logs show proper HTTP Method, and allow change HTTP method in form (#6953) + * Stop colorizing log files by default (#6949) + * Rotate serv.log, http.log and hook logs and stop stacktracing in these (#6935) + * Fix plain text overflow line wrap (#6915) + * Fix input size for dependency select (#6913) + * Change drone token name to let users know to use oauth2 (#6912) + * Fix syntax highlight in blame view #6895 (#6909) + * Use AppURL for Oauth user link (#6894) + * Fixes #6881 - API users search fix (#6882) + * Fix 404 when send pull request some situation (#6871) + * Enforce osusergo build tag for releases (#6862) + * Fix 500 when reviewer is deleted with integration tests (#6856) + * Fix v85.go (#6851) + * Make dropTableColumns drop columns on sqlite and constraints on all (#6849) + * Fix double-generation of scratch token (#6832) (#6833) + * When mirroring we should set the remote to mirror (#6824) + * Fix the v78 migration "Drop is_bare" on MSSQL #6707 (#6823) + * Change verbose flag in dump command to avoid colliding with global version flag (#6822) + * Fix #6813: Allow git.GetTree to take both commit and tree names (#6816) + * Remove `seen` map from `getLastCommitForPaths` (#6807) + * Show scrollbar only when needed (#6802) + * Restore IsWindows variable assignment (#6722) (#6790) + * Service worker js is a missing comma (#6788) + * Fix team edit API panic (#6780) + * Set user search base field optional in LDAP (simple auth) edit page (#6779) + * Ignore already existing public keys after ldap sync (#6766) + * Fix pulls broken when fork repository deleted (#6754) + * Fix missing return (#6751) + * Fix new team 500 (#6749) + * OAuth2 token can be used in basic auth (#6747) + * Fix org visibility bug when git cloning (#6743) + * Fix bug when sort repos on org home page login with non-admin (#6741) + * Stricter domain name pattern in email regex (#6739) + * Fix admin template error (#6737) + * Drop is_bare IDX only when it exists for MySQL and MariaDB (#6736) + * UI: Detect and restore encoding and BOM in content (#6727) + * Load issue attributes when editing an issue with API (#6723) + * Fix team members API (#6714) + * Unfortunately MemProvider Init does not actually Init properly (#6692) + * Fix partial reversion of #6657 caused by #6314 (#6685) + * Prevent creating empty sessions (#6677) + * Fixes #6659 - Swagger schemes selection default to page's protocol (#6660) + * Update highlight.js to 9.15.6 (#6658) + * Properly escape on the redirect from the web editor (#6657) + * Fix #6655 - Don't EscapePound .Link as it is already escaped (#6656) + * Use ctx.metas for SHA hash links (#6645) + * Fix wrong GPG expire date (#6643) + * upgrade version of lib/pq to v1.1.0 (#6640) + * Fix forking an empty repository (#6637) + * Fix issuer of OTP URI should be URI-encoded. (#6634) + * Return a UserList from /api/v1/admin/users (#6629) + * Add json tags for oauth2 form (#6627) + * Remove extra slash from twitter card (#6619) + * remove bash requirement in makefile (#6617) + * Fix Open Graph og:image link (#6612) + * Fix cross-compile builds (#6609) + * Change commit summary to full message in API (#6591) + * Fix bug user search API pagesize didn't obey ExplorePagingNum (#6579) + * Prevent server 500 on compare branches with no common history (#6555) + * Properly escape release attachment URL (#6512) + * Delete local branch when repo branch is deleted (#6497) + * Fix bug when user login and want to resend register confirmation email (#6482) + * Fix upload attachments (#6481) + * Avoid multi-clicks in oauth2 login (#6467) + * Hacky fix for alignment of the create-organization dialog (#6455) + * Change order that PostProcess Processors are run (#6445) + * Clean up ref name rules (#6437) + * Fix Hook & HookList in Swagger (#6432) + * Fixed unitTypeCode not being used in accessLevelUnit (#6419) + * Display correct error for invalid mirror interval (#6414) + * Don't Unescape redirect_to cookie value (#6399) + * Fix dump table name error and add some test for dump database (#6394) + * Fix migrations 82 to ignore unsynced tags between database and git data and missing is_archived on repository table (#6387) + * Make sure units of a team are returned (#6379) + * Fix bug manifest.json will not request with cookie so that session will created every request (#6372) + * Disable benchmarking during tag events on DroneIO (#6365) + * Comments list performance optimization (#5305) +* ENHANCEMENT + * Add API Endpoint for Repo Edit (#7006) + * Add state param to milestone listing API (#7131) + * Make captcha and password optional for external accounts (#6606) + * Detect migrating batch size (#7353) + * Fix 7255 - wrap long texts on user profile info (#7333) + * Use commit graph files for listing pages (#7314) + * Add git command line commitgraph support global default true when git version >= 2.18 (#7313) + * Add LFS_START_SERVER option to control git-lfs support (#7281) + * Dark theme markdown fixes (#7260) + * Update go-git to v4.12.0 (#7249) + * Show lfs config on admin panel (#7220) + * Disable same user check for internal SSH (#7215) + * Add LastLogin to the User API (#7196) + * Add missing description of label on API (#7159) + * Use go method to calculate ssh key fingerprint (#7128) + * Enable Rust highlighting (#7125) + * Refactor submodule URL parsing (#7100) + * Change issue mail title. (#7064) + * Use batch insert on migrating repository to make the process faster (#7050) + * Improve github downloader on migrations (#7049) + * When git version >= 2.18, git command could run with git wire protocol version 2 param if enabled (#7047) + * Fix Erlang and Elixir highlight mappings (#7044) + * API Org Visibility (#7028) + * Improve handling of non-square avatars (#7025) + * Bugfix: Align comment label and actions to the right (#7024) + * Change UpdateRepoIndex api to include watchers (#7012) + * Move serv hook functionality & drop GitLogger (#6993) + * Add support of utf8mb4 for mysql (#6992) + * Make webhook http connections resuable (#6976) + * Move xorm logger bridge from log to models so that log module could be a standalone package (#6944) + * Refactor models.NewRepoContext to extract git related codes to modules/git (#6941) + * Remove macaron dependent on models (#6940) + * Add less linter via npx (#6936) + * Remove macaron dependent on modules/log (#6933) + * Remove macaron dependent on models/mail.go (#6931) + * Clean less files (#6921) + * Fix code overflow (#6914) + * Style orgs list in user profile (#6911) + * Improve description of branch protection (fix #6886) (#6906) + * Move sdk structs to modules/structs (#6905) + * update sdk to latest (#6903) + * Escape the commit message on issues update and title in telegram hook (#6901) + * SearchRepositoryByName improvements and unification (#6897) + * Change the color of issues/pulls list, merged is purple and closed is red (#6874) + * Refactor table width to have more info shown in file list (#6867) + * Monitor all git commands; move blame to git package and replace git as a variable (#6864) + * Fix config ui error about cache ttl (#6861) + * Improve localization of git activity stats (#6848) + * Generate access token in admin cli (#6847) + * Update github.com/urfave/cli to version 1.2.0 (#6838) + * Rename LFS_JWT_SECRET cli option to include OAUTH2 as well (#6826) + * internal/ssh: ignore env command totally (#6825) + * Allow Recaptcha service url to be configured (#6820) + * update github.com/mcuadros/go-version to v0.0.0-20190308113854-92cdf37c5b75 (#6815) + * Use modules/git for git commands (#6775) + * Add GET requests to webhook (#6771) + * Move PushUpdate dependency from models to repofiles (#6763) + * Tweak tab text and icon colors (#6760) + * Ignore non-standard refs in git push (#6758) + * Disable web preview for telegram webhook (#6719) + * Show full name if DEFAULT_SHOW_FULL_NAME setting enabled (#6710) + * Reorder file actions (#6706) + * README WordPress the code is overflowing #6679 (#6696) + * Improve issue reference on commit (#6694) + * Handle redirects for git clone commands (#6688) + * Fix one performance/correctness regression in #6478 found on Rails repository. (#6686) + * API OTP Context (#6674) + * Remove local clones & make hooks run on merge/edit/upload (#6672) + * Bump github.com/stretchr/testify from 1.2.2 to 1.3.0 (#6663) + * Bump gopkg.in/src-d/go-git.v4 from 4.8.0 to 4.10.0 (#6662) + * Fix dropdown icon padding (#6651) + * Add more title attributes on shortened names (#6647) + * Update UI for topics labels on projects (#6639) + * Trace Logging on Permission Denied & ColorFormat (#6618) + * Add .gpg url (match github behaviour) (#6610) + * Support for custom GITEA_CUSTOM env var in docker(#6608) + * Show "delete branch" button on closed pull requests (#6570) (#6601) + * Add option to disable refresh token invalidation (#6584) + * Fix new repo dropdown alignment (#6583) + * Fix mail notification when close/reopen issue (#6581) + * Pre-calculate the absolute path of git (#6575) + * Minor CSS cleanup for the navbar (#6553) + * Render SHA1 links as code blocks (#6546) + * Add username flag in create-user command (#6534) + * Unifies pagination template usage (#6531) (#6533) + * Fixes pagination width on mobile view (#5711) (#6532) + * Improve SHA1 link detection (#6526) + * Fixes #6446 - Sort team members and team's repositories (#6525) + * Use stricter boundaries for auto-link detection (#6522) + * Use regular line-height on frontpage entries (#6518) + * Fixes #6514 - New Pull Request on files and pulls pages the same (#6515) + * Make distinction between DisplayName and Username in email templates (#6495) + * Add X-Auto-Response-Suppress header to outgoing messages (#6492) + * Cleaned permission checks for API -> site admin can now do anything (#6483) + * Support search operators for commits search (#6479) + * Improve listing performance by using go-git (#6478) + * Fix repo sub_menu font color in arc-green (#6477) + * Show last commit status in pull request lists (#6465) + * Add signatures to webhooks (#6428) + * Optimize all images in public/img (#6427) + * Add golangci (#6418) + * Make "Ghost" not link to 404 page (#6410) + * Include more variables on admin/config page (#6378) + * Markdown: enable some more extensions (#6362) + * Include repo name in page title tag (#6343) + * Show locale string on timestamp (#6324) + * Handle CORS requests (#6289) + * Improve issue autolinks (#6273) + * Migration Tweaks (#6260) + * Add title attributes to all items in the repo list viewer (#6258) + * Issue indexer queue redis support (#6218) + * Add bio field for user (#6113) + * Make the version within makefile overwriteable (#6080) + * Updates to API 404 responses (#6077) + * Use Go1.11 module (#5743) + * UX + Security current user password reset (#5042) + * Refactor: append, build variable and type switch (#4940) + * Git statistics in Activity tab (#4724) + * Drop the bits argument when generating an ed25519 key (#6504) +* SECURITY + * Shadow the password on cache and session config on admin panel (#7300) +* TESTING + * Exclude pull_request from fetch-tags step, fixes #7108 (#7120) + * Refactor and improve git test (#7086) + * Fix TestSearchRepo by waiting till indexing is done (#7004) + * Add mssql migration tests (needs #6823) (#6852) + * Add tests for Org API (#6731) + * Context.ServerError and NotFound should log from their caller (#6550) +* TRANSLATION + * Add french specific rule for translating plural texts (#6846) +* BUILD + * Update mssql driver to last working version 20180314172330-6a30f4e59a44 (#7306) + * Alpine 3.10 (#7256) + * Use vfsgen instead of go-bindata (#7080) + * remove and disable package-lock (#6969) + * add make targets for js and css, add js linter (#6952) + * Added tags pull step to drone config to show correct version hashes i… (#6836) + * Make CustomPath, CustomConf and AppWorkPath configurable at build (#6631) + * chore: update drone format to 1.0 (#6602) + * Fix race in integration testlogger (#6556) + * Quieter Integration Tests (#6513) + * Drop the docker Makefile from the image (#6507) + * Add make version on gitea version (#6485) + * Fix #6468 - Uses space match and adds newline for all sed flavors (#6473) + * Move code.gitea.io/git to code.gitea.io/gitea/modules/git (#6364) + * Update npm dependencies and various tweaks (#7344) + * Fix updated drone file (#7336) + * Add 'npm' and 'npm-update' make targets and lockfile (#7246) +* DOCS + * Add work path CLI option (#6922) + * Fix logging documentation (#6904) + * Some logging documentation (#6498) + * Fix link to Hacking on Gitea on From-Source doc page (#6471) + * Fix typos in docs command-line examples (#6466) + * Added docker example for backup (#5846) + ## [1.8.3](https://github.com/go-gitea/gitea/releases/tag/v1.8.3) - 2019-06-17 * BUGFIXES * Always set userID on LFS authentication (#7224) (Part of #6993) From c44f0b1c760855f578d2e5ce6fafbf9cba97da4f Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 6 Jul 2019 23:30:08 +0000 Subject: [PATCH 192/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index f8eba821d9..a7d4487ca9 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -305,6 +305,7 @@ password_not_match=Las contraseñas no coinciden. username_been_taken=El nombre de usuario ya está en uso. repo_name_been_taken=El nombre del repositorio ya está usado. +visit_rate_limit=Limitar tasa a visitas remotas. org_name_been_taken=Ya existe una organización con este nombre. team_name_been_taken=Ya existe un equipo con este nombre. team_no_units_error=Permitir el acceso a por lo menos una sección del repositorio. From d0ec940dd7b79876c91288be54e8fd62eb42fe54 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 6 Jul 2019 21:28:09 -0400 Subject: [PATCH 193/220] switch to use gliderlabs/ssh for builtin server (#7250) resolves git conflicts from #3896 (credit to @belak, in case github doesn't keep original author during squash) Co-Authored-By: Matti Ranta --- go.mod | 8 +- go.sum | 16 +- integrations/mssql.ini.tmpl | 1 + integrations/mysql.ini.tmpl | 1 + integrations/mysql8.ini.tmpl | 1 + integrations/pgsql.ini.tmpl | 1 + integrations/repo_test.go | 2 +- integrations/sqlite.ini | 1 + modules/ssh/ssh.go | 293 ++++++------- vendor/github.com/anmitsu/go-shlex/.gitignore | 1 + vendor/github.com/anmitsu/go-shlex/LICENSE | 20 + vendor/github.com/anmitsu/go-shlex/README.md | 38 ++ vendor/github.com/anmitsu/go-shlex/shlex.go | 193 +++++++++ vendor/github.com/gliderlabs/ssh/LICENSE | 27 ++ vendor/github.com/gliderlabs/ssh/README.md | 96 +++++ vendor/github.com/gliderlabs/ssh/agent.go | 83 ++++ vendor/github.com/gliderlabs/ssh/circle.yml | 26 ++ vendor/github.com/gliderlabs/ssh/conn.go | 55 +++ vendor/github.com/gliderlabs/ssh/context.go | 152 +++++++ vendor/github.com/gliderlabs/ssh/doc.go | 45 ++ vendor/github.com/gliderlabs/ssh/options.go | 77 ++++ vendor/github.com/gliderlabs/ssh/server.go | 394 ++++++++++++++++++ vendor/github.com/gliderlabs/ssh/session.go | 308 ++++++++++++++ vendor/github.com/gliderlabs/ssh/ssh.go | 123 ++++++ vendor/github.com/gliderlabs/ssh/tcpip.go | 193 +++++++++ vendor/github.com/gliderlabs/ssh/util.go | 83 ++++ vendor/github.com/gliderlabs/ssh/wrap.go | 33 ++ vendor/golang.org/x/sys/unix/syscall_linux.go | 5 +- vendor/golang.org/x/sys/unix/types_netbsd.go | 1 + vendor/golang.org/x/sys/unix/types_openbsd.go | 1 + .../x/sys/unix/ztypes_netbsd_386.go | 1 + .../x/sys/unix/ztypes_netbsd_amd64.go | 1 + .../x/sys/unix/ztypes_netbsd_arm.go | 1 + .../x/sys/unix/ztypes_netbsd_arm64.go | 1 + .../x/sys/unix/ztypes_openbsd_386.go | 1 + .../x/sys/unix/ztypes_openbsd_amd64.go | 1 + .../x/sys/unix/ztypes_openbsd_arm.go | 1 + .../x/sys/unix/ztypes_openbsd_arm64.go | 1 + .../x/sys/windows/syscall_windows.go | 4 +- .../x/sys/windows/zsyscall_windows.go | 2 +- vendor/modules.txt | 8 +- 41 files changed, 2122 insertions(+), 178 deletions(-) create mode 100644 vendor/github.com/anmitsu/go-shlex/.gitignore create mode 100644 vendor/github.com/anmitsu/go-shlex/LICENSE create mode 100644 vendor/github.com/anmitsu/go-shlex/README.md create mode 100644 vendor/github.com/anmitsu/go-shlex/shlex.go create mode 100644 vendor/github.com/gliderlabs/ssh/LICENSE create mode 100644 vendor/github.com/gliderlabs/ssh/README.md create mode 100644 vendor/github.com/gliderlabs/ssh/agent.go create mode 100644 vendor/github.com/gliderlabs/ssh/circle.yml create mode 100644 vendor/github.com/gliderlabs/ssh/conn.go create mode 100644 vendor/github.com/gliderlabs/ssh/context.go create mode 100644 vendor/github.com/gliderlabs/ssh/doc.go create mode 100644 vendor/github.com/gliderlabs/ssh/options.go create mode 100644 vendor/github.com/gliderlabs/ssh/server.go create mode 100644 vendor/github.com/gliderlabs/ssh/session.go create mode 100644 vendor/github.com/gliderlabs/ssh/ssh.go create mode 100644 vendor/github.com/gliderlabs/ssh/tcpip.go create mode 100644 vendor/github.com/gliderlabs/ssh/util.go create mode 100644 vendor/github.com/gliderlabs/ssh/wrap.go diff --git a/go.mod b/go.mod index 22ad85b136..088f987b4d 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 // indirect github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect - github.com/gliderlabs/ssh v0.1.4 // indirect + github.com/gliderlabs/ssh v0.2.2 github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd // indirect github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 @@ -110,11 +110,11 @@ require ( github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 go.etcd.io/bbolt v1.3.2 // indirect golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 - golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 + golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 - golang.org/x/sys v0.0.0-20190618155005-516e3c20635f + golang.org/x/sys v0.0.0-20190620070143-6f217b454f45 golang.org/x/text v0.3.2 - golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a // indirect + golang.org/x/tools v0.0.0-20190620154339-431033348dd0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect diff --git a/go.sum b/go.sum index 80b30fc46e..e074914c8c 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,8 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gliderlabs/ssh v0.1.4 h1:5N8AYXpaQAPy0L7linKa5aI+WRfyYagAhjksVzxh+mI= -github.com/gliderlabs/ssh v0.1.4/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y= @@ -369,8 +369,8 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b h1:lkjdUzSyJ5P1+eal9fxXX9Xg2BTfswsonKUse48C0uE= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h5Hmyb5+VDjEiMufAEAM04= @@ -395,15 +395,15 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqY golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190618155005-516e3c20635f h1:dHNZYIYdq2QuU6w73vZ/DzesPbVlZVYZTtTZmrnsbQ8= -golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190620070143-6f217b454f45 h1:Dl2hc890lrizvUppGbRWhnIh2f8jOTCQpY5IKWRS0oM= +golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a h1:aQmaYPOmKItb96VioBrTlYay5tSNUdKAFEhPCWMeLSM= -golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190620154339-431033348dd0 h1:qUGDNmGEM+ZBtwF9vuzEv+9nQQPL+l/oNBZ+DCDTAyo= +golang.org/x/tools v0.0.0-20190620154339-431033348dd0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/integrations/mssql.ini.tmpl b/integrations/mssql.ini.tmpl index a8e6d332f0..06d9de6107 100644 --- a/integrations/mssql.ini.tmpl +++ b/integrations/mssql.ini.tmpl @@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-mssql OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-mssql/data +BUILTIN_SSH_SERVER_USER = git [mailer] ENABLED = true diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 0c9e6c3ecd..44ca51ff8b 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-mysql OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-mysql/data +BUILTIN_SSH_SERVER_USER = git [mailer] ENABLED = true diff --git a/integrations/mysql8.ini.tmpl b/integrations/mysql8.ini.tmpl index 7006433276..6db3c880ff 100644 --- a/integrations/mysql8.ini.tmpl +++ b/integrations/mysql8.ini.tmpl @@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-mysql8 OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-mysql8/data +BUILTIN_SSH_SERVER_USER = git [mailer] ENABLED = false diff --git a/integrations/pgsql.ini.tmpl b/integrations/pgsql.ini.tmpl index 894a243ba8..e69198c868 100644 --- a/integrations/pgsql.ini.tmpl +++ b/integrations/pgsql.ini.tmpl @@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-pgsql OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-pgsql/data +BUILTIN_SSH_SERVER_USER = git [mailer] ENABLED = true diff --git a/integrations/repo_test.go b/integrations/repo_test.go index 37f163a9fb..b733c9679f 100644 --- a/integrations/repo_test.go +++ b/integrations/repo_test.go @@ -73,7 +73,7 @@ func TestViewRepo1CloneLinkAuthorized(t *testing.T) { assert.Equal(t, setting.AppURL+"user2/repo1.git", link) link, exists = htmlDoc.doc.Find("#repo-clone-ssh").Attr("data-link") assert.True(t, exists, "The template has changed") - sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.RunUser, setting.SSH.Domain, setting.SSH.Port) + sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.BuiltinServerUser, setting.SSH.Domain, setting.SSH.Port) assert.Equal(t, sshURL, link) } diff --git a/integrations/sqlite.ini b/integrations/sqlite.ini index 086081b666..b188406ee9 100644 --- a/integrations/sqlite.ini +++ b/integrations/sqlite.ini @@ -31,6 +31,7 @@ OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-sqlite/data ENABLE_GZIP = true +BUILTIN_SSH_SERVER_USER = git [mailer] ENABLED = true diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index c5251ef23a..1818f33306 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -1,4 +1,3 @@ -// Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2017 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -10,178 +9,157 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" + "fmt" "io" - "io/ioutil" - "net" "os" "os/exec" "path/filepath" "strings" - - "github.com/Unknwon/com" - "golang.org/x/crypto/ssh" + "sync" + "syscall" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + + "github.com/Unknwon/com" + "github.com/gliderlabs/ssh" + gossh "golang.org/x/crypto/ssh" ) -func cleanCommand(cmd string) string { - i := strings.Index(cmd, "git") - if i == -1 { - return cmd - } - return cmd[i:] -} +type contextKey string -func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { - for newChan := range chans { - if newChan.ChannelType() != "session" { - err := newChan.Reject(ssh.UnknownChannelType, "unknown channel type") - if err != nil { - log.Error("Error rejecting channel: %v", err) - } - continue +const giteaKeyID = contextKey("gitea-key-id") + +func getExitStatusFromError(err error) int { + if err == nil { + return 0 + } + + exitErr, ok := err.(*exec.ExitError) + if !ok { + return 1 + } + + waitStatus, ok := exitErr.Sys().(syscall.WaitStatus) + if !ok { + // This is a fallback and should at least let us return something useful + // when running on Windows, even if it isn't completely accurate. + if exitErr.Success() { + return 0 } - ch, reqs, err := newChan.Accept() - if err != nil { - log.Error("Error accepting channel: %v", err) - continue - } - - go func(in <-chan *ssh.Request) { - defer func() { - if err = ch.Close(); err != nil { - log.Error("Close: %v", err) - } - }() - for req := range in { - payload := cleanCommand(string(req.Payload)) - switch req.Type { - case "exec": - cmdName := strings.TrimLeft(payload, "'()") - log.Trace("SSH: Payload: %v", cmdName) - - args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf} - log.Trace("SSH: Arguments: %v", args) - cmd := exec.Command(setting.AppPath, args...) - cmd.Env = append( - os.Environ(), - "SSH_ORIGINAL_COMMAND="+cmdName, - "SKIP_MINWINSVC=1", - ) - - stdout, err := cmd.StdoutPipe() - if err != nil { - log.Error("SSH: StdoutPipe: %v", err) - return - } - stderr, err := cmd.StderrPipe() - if err != nil { - log.Error("SSH: StderrPipe: %v", err) - return - } - input, err := cmd.StdinPipe() - if err != nil { - log.Error("SSH: StdinPipe: %v", err) - return - } - - // FIXME: check timeout - if err = cmd.Start(); err != nil { - log.Error("SSH: Start: %v", err) - return - } - - err = req.Reply(true, nil) - if err != nil { - log.Error("SSH: Reply: %v", err) - } - go func() { - _, err = io.Copy(input, ch) - if err != nil { - log.Error("SSH: Copy: %v", err) - } - }() - _, err = io.Copy(ch, stdout) - if err != nil { - log.Error("SSH: Copy: %v", err) - } - _, err = io.Copy(ch.Stderr(), stderr) - if err != nil { - log.Error("SSH: Copy: %v", err) - } - - if err = cmd.Wait(); err != nil { - log.Error("SSH: Wait: %v", err) - return - } - - _, err = ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) - if err != nil { - log.Error("SSH: SendRequest: %v", err) - } - return - default: - } - } - }(reqs) + return 1 } + + return waitStatus.ExitStatus() } -func listen(config *ssh.ServerConfig, host string, port int) { - listener, err := net.Listen("tcp", host+":"+com.ToStr(port)) +func sessionHandler(session ssh.Session) { + keyID := session.Context().Value(giteaKeyID).(int64) + + command := session.RawCommand() + + log.Trace("SSH: Payload: %v", command) + + args := []string{"serv", "key-" + com.ToStr(keyID), "--config=" + setting.CustomConf} + log.Trace("SSH: Arguments: %v", args) + cmd := exec.Command(setting.AppPath, args...) + cmd.Env = append( + os.Environ(), + "SSH_ORIGINAL_COMMAND="+command, + "SKIP_MINWINSVC=1", + ) + + stdout, err := cmd.StdoutPipe() if err != nil { - log.Fatal("Failed to start SSH server: %v", err) + log.Error("SSH: StdoutPipe: %v", err) + return } - for { - // Once a ServerConfig has been configured, connections can be accepted. - conn, err := listener.Accept() - if err != nil { - log.Error("SSH: Error accepting incoming connection: %v", err) - continue + stderr, err := cmd.StderrPipe() + if err != nil { + log.Error("SSH: StderrPipe: %v", err) + return + } + stdin, err := cmd.StdinPipe() + if err != nil { + log.Error("SSH: StdinPipe: %v", err) + return + } + + wg := &sync.WaitGroup{} + wg.Add(2) + + if err = cmd.Start(); err != nil { + log.Error("SSH: Start: %v", err) + return + } + + go func() { + defer stdin.Close() + if _, err := io.Copy(stdin, session); err != nil { + log.Error("Failed to write session to stdin. %s", err) } + }() - // Before use, a handshake must be performed on the incoming net.Conn. - // It must be handled in a separate goroutine, - // otherwise one user could easily block entire loop. - // For example, user could be asked to trust server key fingerprint and hangs. - go func() { - log.Trace("SSH: Handshaking for %s", conn.RemoteAddr()) - sConn, chans, reqs, err := ssh.NewServerConn(conn, config) - if err != nil { - if err == io.EOF { - log.Warn("SSH: Handshaking with %s was terminated: %v", conn.RemoteAddr(), err) - } else { - log.Error("SSH: Error on handshaking with %s: %v", conn.RemoteAddr(), err) - } - return - } + go func() { + defer wg.Done() + if _, err := io.Copy(session, stdout); err != nil { + log.Error("Failed to write stdout to session. %s", err) + } + }() - log.Trace("SSH: Connection from %s (%s)", sConn.RemoteAddr(), sConn.ClientVersion()) - // The incoming Request channel must be serviced. - go ssh.DiscardRequests(reqs) - go handleServerConn(sConn.Permissions.Extensions["key-id"], chans) - }() + go func() { + defer wg.Done() + if _, err := io.Copy(session.Stderr(), stderr); err != nil { + log.Error("Failed to write stderr to session. %s", err) + } + }() + + // Ensure all the output has been written before we wait on the command + // to exit. + wg.Wait() + + // Wait for the command to exit and log any errors we get + err = cmd.Wait() + if err != nil { + log.Error("SSH: Wait: %v", err) } + + if err := session.Exit(getExitStatusFromError(err)); err != nil { + log.Error("Session failed to exit. %s", err) + } +} + +func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { + if ctx.User() != setting.SSH.BuiltinServerUser { + return false + } + + pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key)))) + if err != nil { + log.Error("SearchPublicKeyByContent: %v", err) + return false + } + + ctx.SetValue(giteaKeyID, pkey.ID) + + return true } // Listen starts a SSH server listens on given port. func Listen(host string, port int, ciphers []string, keyExchanges []string, macs []string) { - config := &ssh.ServerConfig{ - Config: ssh.Config{ - Ciphers: ciphers, - KeyExchanges: keyExchanges, - MACs: macs, - }, - PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { - pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key)))) - if err != nil { - log.Error("SearchPublicKeyByContent: %v", err) - return nil, err - } - return &ssh.Permissions{Extensions: map[string]string{"key-id": com.ToStr(pkey.ID)}}, nil + // TODO: Handle ciphers, keyExchanges, and macs + + srv := ssh.Server{ + Addr: fmt.Sprintf("%s:%d", host, port), + PublicKeyHandler: publicKeyHandler, + Handler: sessionHandler, + + // We need to explicitly disable the PtyCallback so text displays + // properly. + PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool { + return false }, } @@ -197,20 +175,21 @@ func Listen(host string, port int, ciphers []string, keyExchanges []string, macs if err != nil { log.Fatal("Failed to generate private key: %v", err) } - log.Trace("SSH: New private key is generateed: %s", keyPath) + log.Trace("New private key is generated: %s", keyPath) } - privateBytes, err := ioutil.ReadFile(keyPath) + err := srv.SetOption(ssh.HostKeyFile(keyPath)) if err != nil { - log.Fatal("SSH: Failed to load private key") + log.Error("Failed to set Host Key. %s", err) } - private, err := ssh.ParsePrivateKey(privateBytes) - if err != nil { - log.Fatal("SSH: Failed to parse private key") - } - config.AddHostKey(private) - go listen(config, host, port) + go func() { + err := srv.ListenAndServe() + if err != nil { + log.Error("Failed to serve with builtin SSH server. %s", err) + } + }() + } // GenKeyPair make a pair of public and private keys for SSH access. @@ -238,12 +217,12 @@ func GenKeyPair(keyPath string) error { } // generate public key - pub, err := ssh.NewPublicKey(&privateKey.PublicKey) + pub, err := gossh.NewPublicKey(&privateKey.PublicKey) if err != nil { return err } - public := ssh.MarshalAuthorizedKey(pub) + public := gossh.MarshalAuthorizedKey(pub) p, err := os.OpenFile(keyPath+".pub", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err diff --git a/vendor/github.com/anmitsu/go-shlex/.gitignore b/vendor/github.com/anmitsu/go-shlex/.gitignore new file mode 100644 index 0000000000..0b46bb5df1 --- /dev/null +++ b/vendor/github.com/anmitsu/go-shlex/.gitignore @@ -0,0 +1 @@ +shlex.test diff --git a/vendor/github.com/anmitsu/go-shlex/LICENSE b/vendor/github.com/anmitsu/go-shlex/LICENSE new file mode 100644 index 0000000000..4a17268ac0 --- /dev/null +++ b/vendor/github.com/anmitsu/go-shlex/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) anmitsu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/anmitsu/go-shlex/README.md b/vendor/github.com/anmitsu/go-shlex/README.md new file mode 100644 index 0000000000..c4ffe72be1 --- /dev/null +++ b/vendor/github.com/anmitsu/go-shlex/README.md @@ -0,0 +1,38 @@ +# go-shlex + +go-shlex is a library to make a lexical analyzer like Unix shell for +Go. + +## Install + + go get -u "github.com/anmitsu/go-shlex" + +## Usage + +```go +package main + +import ( + "fmt" + "log" + + "github.com/anmitsu/go-shlex" +) + +func main() { + cmd := `cp -Rdp "file name" 'file name2' dir\ name` + words, err := shlex.Split(cmd, true) + if err != nil { + log.Fatal(err) + } + + for _, w := range words { + fmt.Println(w) + } +} +``` + +## Documentation + +http://godoc.org/github.com/anmitsu/go-shlex + diff --git a/vendor/github.com/anmitsu/go-shlex/shlex.go b/vendor/github.com/anmitsu/go-shlex/shlex.go new file mode 100644 index 0000000000..e742c38afc --- /dev/null +++ b/vendor/github.com/anmitsu/go-shlex/shlex.go @@ -0,0 +1,193 @@ +// Package shlex provides a simple lexical analysis like Unix shell. +package shlex + +import ( + "bufio" + "errors" + "io" + "strings" + "unicode" +) + +var ( + ErrNoClosing = errors.New("No closing quotation") + ErrNoEscaped = errors.New("No escaped character") +) + +// Tokenizer is the interface that classifies a token according to +// words, whitespaces, quotations, escapes and escaped quotations. +type Tokenizer interface { + IsWord(rune) bool + IsWhitespace(rune) bool + IsQuote(rune) bool + IsEscape(rune) bool + IsEscapedQuote(rune) bool +} + +// DefaultTokenizer implements a simple tokenizer like Unix shell. +type DefaultTokenizer struct{} + +func (t *DefaultTokenizer) IsWord(r rune) bool { + return r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r) +} +func (t *DefaultTokenizer) IsQuote(r rune) bool { + switch r { + case '\'', '"': + return true + default: + return false + } +} +func (t *DefaultTokenizer) IsWhitespace(r rune) bool { + return unicode.IsSpace(r) +} +func (t *DefaultTokenizer) IsEscape(r rune) bool { + return r == '\\' +} +func (t *DefaultTokenizer) IsEscapedQuote(r rune) bool { + return r == '"' +} + +// Lexer represents a lexical analyzer. +type Lexer struct { + reader *bufio.Reader + tokenizer Tokenizer + posix bool + whitespacesplit bool +} + +// NewLexer creates a new Lexer reading from io.Reader. This Lexer +// has a DefaultTokenizer according to posix and whitespacesplit +// rules. +func NewLexer(r io.Reader, posix, whitespacesplit bool) *Lexer { + return &Lexer{ + reader: bufio.NewReader(r), + tokenizer: &DefaultTokenizer{}, + posix: posix, + whitespacesplit: whitespacesplit, + } +} + +// NewLexerString creates a new Lexer reading from a string. This +// Lexer has a DefaultTokenizer according to posix and whitespacesplit +// rules. +func NewLexerString(s string, posix, whitespacesplit bool) *Lexer { + return NewLexer(strings.NewReader(s), posix, whitespacesplit) +} + +// Split splits a string according to posix or non-posix rules. +func Split(s string, posix bool) ([]string, error) { + return NewLexerString(s, posix, true).Split() +} + +// SetTokenizer sets a Tokenizer. +func (l *Lexer) SetTokenizer(t Tokenizer) { + l.tokenizer = t +} + +func (l *Lexer) Split() ([]string, error) { + result := make([]string, 0) + for { + token, err := l.readToken() + if token != "" { + result = append(result, token) + } + + if err == io.EOF { + break + } else if err != nil { + return result, err + } + } + return result, nil +} + +func (l *Lexer) readToken() (string, error) { + t := l.tokenizer + token := "" + quoted := false + state := ' ' + escapedstate := ' ' +scanning: + for { + next, _, err := l.reader.ReadRune() + if err != nil { + if t.IsQuote(state) { + return token, ErrNoClosing + } else if t.IsEscape(state) { + return token, ErrNoEscaped + } + return token, err + } + + switch { + case t.IsWhitespace(state): + switch { + case t.IsWhitespace(next): + break scanning + case l.posix && t.IsEscape(next): + escapedstate = 'a' + state = next + case t.IsWord(next): + token += string(next) + state = 'a' + case t.IsQuote(next): + if !l.posix { + token += string(next) + } + state = next + default: + token = string(next) + if l.whitespacesplit { + state = 'a' + } else if token != "" || (l.posix && quoted) { + break scanning + } + } + case t.IsQuote(state): + quoted = true + switch { + case next == state: + if !l.posix { + token += string(next) + break scanning + } else { + state = 'a' + } + case l.posix && t.IsEscape(next) && t.IsEscapedQuote(state): + escapedstate = state + state = next + default: + token += string(next) + } + case t.IsEscape(state): + if t.IsQuote(escapedstate) && next != state && next != escapedstate { + token += string(state) + } + token += string(next) + state = escapedstate + case t.IsWord(state): + switch { + case t.IsWhitespace(next): + if token != "" || (l.posix && quoted) { + break scanning + } + case l.posix && t.IsQuote(next): + state = next + case l.posix && t.IsEscape(next): + escapedstate = 'a' + state = next + case t.IsWord(next) || t.IsQuote(next): + token += string(next) + default: + if l.whitespacesplit { + token += string(next) + } else if token != "" { + l.reader.UnreadRune() + break scanning + } + } + } + } + return token, nil +} diff --git a/vendor/github.com/gliderlabs/ssh/LICENSE b/vendor/github.com/gliderlabs/ssh/LICENSE new file mode 100644 index 0000000000..4a03f02a28 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2016 Glider Labs. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Glider Labs nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gliderlabs/ssh/README.md b/vendor/github.com/gliderlabs/ssh/README.md new file mode 100644 index 0000000000..0e976e34f9 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/README.md @@ -0,0 +1,96 @@ +# gliderlabs/ssh + +[![GoDoc](https://godoc.org/github.com/gliderlabs/ssh?status.svg)](https://godoc.org/github.com/gliderlabs/ssh) +[![CircleCI](https://img.shields.io/circleci/project/github/gliderlabs/ssh.svg)](https://circleci.com/gh/gliderlabs/ssh) +[![Go Report Card](https://goreportcard.com/badge/github.com/gliderlabs/ssh)](https://goreportcard.com/report/github.com/gliderlabs/ssh) +[![OpenCollective](https://opencollective.com/ssh/sponsors/badge.svg)](#sponsors) +[![Slack](http://slack.gliderlabs.com/badge.svg)](http://slack.gliderlabs.com) +[![Email Updates](https://img.shields.io/badge/updates-subscribe-yellow.svg)](https://app.convertkit.com/landing_pages/243312) + +> The Glider Labs SSH server package is dope. —[@bradfitz](https://twitter.com/bradfitz), Go team member + +This Go package wraps the [crypto/ssh +package](https://godoc.org/golang.org/x/crypto/ssh) with a higher-level API for +building SSH servers. The goal of the API was to make it as simple as using +[net/http](https://golang.org/pkg/net/http/), so the API is very similar: + +```go + package main + + import ( + "github.com/gliderlabs/ssh" + "io" + "log" + ) + + func main() { + ssh.Handle(func(s ssh.Session) { + io.WriteString(s, "Hello world\n") + }) + + log.Fatal(ssh.ListenAndServe(":2222", nil)) + } + +``` +This package was built by [@progrium](https://twitter.com/progrium) after working on nearly a dozen projects at Glider Labs using SSH and collaborating with [@shazow](https://twitter.com/shazow) (known for [ssh-chat](https://github.com/shazow/ssh-chat)). + +## Examples + +A bunch of great examples are in the `_examples` directory. + +## Usage + +[See GoDoc reference.](https://godoc.org/github.com/gliderlabs/ssh) + +## Contributing + +Pull requests are welcome! However, since this project is very much about API +design, please submit API changes as issues to discuss before submitting PRs. + +Also, you can [join our Slack](http://slack.gliderlabs.com) to discuss as well. + +## Roadmap + +* Non-session channel handlers +* Cleanup callback API +* 1.0 release +* High-level client? + +## Sponsors + +Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/ssh#sponsor)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## License + +BSD diff --git a/vendor/github.com/gliderlabs/ssh/agent.go b/vendor/github.com/gliderlabs/ssh/agent.go new file mode 100644 index 0000000000..d8dcb9a0a4 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/agent.go @@ -0,0 +1,83 @@ +package ssh + +import ( + "io" + "io/ioutil" + "net" + "path" + "sync" + + gossh "golang.org/x/crypto/ssh" +) + +const ( + agentRequestType = "auth-agent-req@openssh.com" + agentChannelType = "auth-agent@openssh.com" + + agentTempDir = "auth-agent" + agentListenFile = "listener.sock" +) + +// contextKeyAgentRequest is an internal context key for storing if the +// client requested agent forwarding +var contextKeyAgentRequest = &contextKey{"auth-agent-req"} + +// SetAgentRequested sets up the session context so that AgentRequested +// returns true. +func SetAgentRequested(ctx Context) { + ctx.SetValue(contextKeyAgentRequest, true) +} + +// AgentRequested returns true if the client requested agent forwarding. +func AgentRequested(sess Session) bool { + return sess.Context().Value(contextKeyAgentRequest) == true +} + +// NewAgentListener sets up a temporary Unix socket that can be communicated +// to the session environment and used for forwarding connections. +func NewAgentListener() (net.Listener, error) { + dir, err := ioutil.TempDir("", agentTempDir) + if err != nil { + return nil, err + } + l, err := net.Listen("unix", path.Join(dir, agentListenFile)) + if err != nil { + return nil, err + } + return l, nil +} + +// ForwardAgentConnections takes connections from a listener to proxy into the +// session on the OpenSSH channel for agent connections. It blocks and services +// connections until the listener stop accepting. +func ForwardAgentConnections(l net.Listener, s Session) { + sshConn := s.Context().Value(ContextKeyConn).(gossh.Conn) + for { + conn, err := l.Accept() + if err != nil { + return + } + go func(conn net.Conn) { + defer conn.Close() + channel, reqs, err := sshConn.OpenChannel(agentChannelType, nil) + if err != nil { + return + } + defer channel.Close() + go gossh.DiscardRequests(reqs) + var wg sync.WaitGroup + wg.Add(2) + go func() { + io.Copy(conn, channel) + conn.(*net.UnixConn).CloseWrite() + wg.Done() + }() + go func() { + io.Copy(channel, conn) + channel.CloseWrite() + wg.Done() + }() + wg.Wait() + }(conn) + } +} diff --git a/vendor/github.com/gliderlabs/ssh/circle.yml b/vendor/github.com/gliderlabs/ssh/circle.yml new file mode 100644 index 0000000000..08616b01c3 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/circle.yml @@ -0,0 +1,26 @@ +version: 2 +jobs: + build-go-latest: + docker: + - image: golang:latest + working_directory: /go/src/github.com/gliderlabs/ssh + steps: + - checkout + - run: go get + - run: go test -v -race + + build-go-1.9: + docker: + - image: golang:1.9 + working_directory: /go/src/github.com/gliderlabs/ssh + steps: + - checkout + - run: go get + - run: go test -v -race + +workflows: + version: 2 + build: + jobs: + - build-go-latest + - build-go-1.9 diff --git a/vendor/github.com/gliderlabs/ssh/conn.go b/vendor/github.com/gliderlabs/ssh/conn.go new file mode 100644 index 0000000000..ebef8845ba --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/conn.go @@ -0,0 +1,55 @@ +package ssh + +import ( + "context" + "net" + "time" +) + +type serverConn struct { + net.Conn + + idleTimeout time.Duration + maxDeadline time.Time + closeCanceler context.CancelFunc +} + +func (c *serverConn) Write(p []byte) (n int, err error) { + c.updateDeadline() + n, err = c.Conn.Write(p) + if _, isNetErr := err.(net.Error); isNetErr && c.closeCanceler != nil { + c.closeCanceler() + } + return +} + +func (c *serverConn) Read(b []byte) (n int, err error) { + c.updateDeadline() + n, err = c.Conn.Read(b) + if _, isNetErr := err.(net.Error); isNetErr && c.closeCanceler != nil { + c.closeCanceler() + } + return +} + +func (c *serverConn) Close() (err error) { + err = c.Conn.Close() + if c.closeCanceler != nil { + c.closeCanceler() + } + return +} + +func (c *serverConn) updateDeadline() { + switch { + case c.idleTimeout > 0: + idleDeadline := time.Now().Add(c.idleTimeout) + if idleDeadline.Unix() < c.maxDeadline.Unix() || c.maxDeadline.IsZero() { + c.Conn.SetDeadline(idleDeadline) + return + } + fallthrough + default: + c.Conn.SetDeadline(c.maxDeadline) + } +} diff --git a/vendor/github.com/gliderlabs/ssh/context.go b/vendor/github.com/gliderlabs/ssh/context.go new file mode 100644 index 0000000000..2f61a40d61 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/context.go @@ -0,0 +1,152 @@ +package ssh + +import ( + "context" + "encoding/hex" + "net" + "sync" + + gossh "golang.org/x/crypto/ssh" +) + +// contextKey is a value for use with context.WithValue. It's used as +// a pointer so it fits in an interface{} without allocation. +type contextKey struct { + name string +} + +var ( + // ContextKeyUser is a context key for use with Contexts in this package. + // The associated value will be of type string. + ContextKeyUser = &contextKey{"user"} + + // ContextKeySessionID is a context key for use with Contexts in this package. + // The associated value will be of type string. + ContextKeySessionID = &contextKey{"session-id"} + + // ContextKeyPermissions is a context key for use with Contexts in this package. + // The associated value will be of type *Permissions. + ContextKeyPermissions = &contextKey{"permissions"} + + // ContextKeyClientVersion is a context key for use with Contexts in this package. + // The associated value will be of type string. + ContextKeyClientVersion = &contextKey{"client-version"} + + // ContextKeyServerVersion is a context key for use with Contexts in this package. + // The associated value will be of type string. + ContextKeyServerVersion = &contextKey{"server-version"} + + // ContextKeyLocalAddr is a context key for use with Contexts in this package. + // The associated value will be of type net.Addr. + ContextKeyLocalAddr = &contextKey{"local-addr"} + + // ContextKeyRemoteAddr is a context key for use with Contexts in this package. + // The associated value will be of type net.Addr. + ContextKeyRemoteAddr = &contextKey{"remote-addr"} + + // ContextKeyServer is a context key for use with Contexts in this package. + // The associated value will be of type *Server. + ContextKeyServer = &contextKey{"ssh-server"} + + // ContextKeyConn is a context key for use with Contexts in this package. + // The associated value will be of type gossh.ServerConn. + ContextKeyConn = &contextKey{"ssh-conn"} + + // ContextKeyPublicKey is a context key for use with Contexts in this package. + // The associated value will be of type PublicKey. + ContextKeyPublicKey = &contextKey{"public-key"} +) + +// Context is a package specific context interface. It exposes connection +// metadata and allows new values to be easily written to it. It's used in +// authentication handlers and callbacks, and its underlying context.Context is +// exposed on Session in the session Handler. A connection-scoped lock is also +// embedded in the context to make it easier to limit operations per-connection. +type Context interface { + context.Context + sync.Locker + + // User returns the username used when establishing the SSH connection. + User() string + + // SessionID returns the session hash. + SessionID() string + + // ClientVersion returns the version reported by the client. + ClientVersion() string + + // ServerVersion returns the version reported by the server. + ServerVersion() string + + // RemoteAddr returns the remote address for this connection. + RemoteAddr() net.Addr + + // LocalAddr returns the local address for this connection. + LocalAddr() net.Addr + + // Permissions returns the Permissions object used for this connection. + Permissions() *Permissions + + // SetValue allows you to easily write new values into the underlying context. + SetValue(key, value interface{}) +} + +type sshContext struct { + context.Context + *sync.Mutex +} + +func newContext(srv *Server) (*sshContext, context.CancelFunc) { + innerCtx, cancel := context.WithCancel(context.Background()) + ctx := &sshContext{innerCtx, &sync.Mutex{}} + ctx.SetValue(ContextKeyServer, srv) + perms := &Permissions{&gossh.Permissions{}} + ctx.SetValue(ContextKeyPermissions, perms) + return ctx, cancel +} + +// this is separate from newContext because we will get ConnMetadata +// at different points so it needs to be applied separately +func applyConnMetadata(ctx Context, conn gossh.ConnMetadata) { + if ctx.Value(ContextKeySessionID) != nil { + return + } + ctx.SetValue(ContextKeySessionID, hex.EncodeToString(conn.SessionID())) + ctx.SetValue(ContextKeyClientVersion, string(conn.ClientVersion())) + ctx.SetValue(ContextKeyServerVersion, string(conn.ServerVersion())) + ctx.SetValue(ContextKeyUser, conn.User()) + ctx.SetValue(ContextKeyLocalAddr, conn.LocalAddr()) + ctx.SetValue(ContextKeyRemoteAddr, conn.RemoteAddr()) +} + +func (ctx *sshContext) SetValue(key, value interface{}) { + ctx.Context = context.WithValue(ctx.Context, key, value) +} + +func (ctx *sshContext) User() string { + return ctx.Value(ContextKeyUser).(string) +} + +func (ctx *sshContext) SessionID() string { + return ctx.Value(ContextKeySessionID).(string) +} + +func (ctx *sshContext) ClientVersion() string { + return ctx.Value(ContextKeyClientVersion).(string) +} + +func (ctx *sshContext) ServerVersion() string { + return ctx.Value(ContextKeyServerVersion).(string) +} + +func (ctx *sshContext) RemoteAddr() net.Addr { + return ctx.Value(ContextKeyRemoteAddr).(net.Addr) +} + +func (ctx *sshContext) LocalAddr() net.Addr { + return ctx.Value(ContextKeyLocalAddr).(net.Addr) +} + +func (ctx *sshContext) Permissions() *Permissions { + return ctx.Value(ContextKeyPermissions).(*Permissions) +} diff --git a/vendor/github.com/gliderlabs/ssh/doc.go b/vendor/github.com/gliderlabs/ssh/doc.go new file mode 100644 index 0000000000..5a10393c2c --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/doc.go @@ -0,0 +1,45 @@ +/* +Package ssh wraps the crypto/ssh package with a higher-level API for building +SSH servers. The goal of the API was to make it as simple as using net/http, so +the API is very similar. + +You should be able to build any SSH server using only this package, which wraps +relevant types and some functions from crypto/ssh. However, you still need to +use crypto/ssh for building SSH clients. + +ListenAndServe starts an SSH server with a given address, handler, and options. The +handler is usually nil, which means to use DefaultHandler. Handle sets DefaultHandler: + + ssh.Handle(func(s ssh.Session) { + io.WriteString(s, "Hello world\n") + }) + + log.Fatal(ssh.ListenAndServe(":2222", nil)) + +If you don't specify a host key, it will generate one every time. This is convenient +except you'll have to deal with clients being confused that the host key is different. +It's a better idea to generate or point to an existing key on your system: + + log.Fatal(ssh.ListenAndServe(":2222", nil, ssh.HostKeyFile("/Users/progrium/.ssh/id_rsa"))) + +Although all options have functional option helpers, another way to control the +server's behavior is by creating a custom Server: + + s := &ssh.Server{ + Addr: ":2222", + Handler: sessionHandler, + PublicKeyHandler: authHandler, + } + s.AddHostKey(hostKeySigner) + + log.Fatal(s.ListenAndServe()) + +This package automatically handles basic SSH requests like setting environment +variables, requesting PTY, and changing window size. These requests are +processed, responded to, and any relevant state is updated. This state is then +exposed to you via the Session interface. + +The one big feature missing from the Session abstraction is signals. This was +started, but not completed. Pull Requests welcome! +*/ +package ssh diff --git a/vendor/github.com/gliderlabs/ssh/options.go b/vendor/github.com/gliderlabs/ssh/options.go new file mode 100644 index 0000000000..af748985be --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/options.go @@ -0,0 +1,77 @@ +package ssh + +import ( + "io/ioutil" + + gossh "golang.org/x/crypto/ssh" +) + +// PasswordAuth returns a functional option that sets PasswordHandler on the server. +func PasswordAuth(fn PasswordHandler) Option { + return func(srv *Server) error { + srv.PasswordHandler = fn + return nil + } +} + +// PublicKeyAuth returns a functional option that sets PublicKeyHandler on the server. +func PublicKeyAuth(fn PublicKeyHandler) Option { + return func(srv *Server) error { + srv.PublicKeyHandler = fn + return nil + } +} + +// HostKeyFile returns a functional option that adds HostSigners to the server +// from a PEM file at filepath. +func HostKeyFile(filepath string) Option { + return func(srv *Server) error { + pemBytes, err := ioutil.ReadFile(filepath) + if err != nil { + return err + } + + signer, err := gossh.ParsePrivateKey(pemBytes) + if err != nil { + return err + } + + srv.AddHostKey(signer) + + return nil + } +} + +// HostKeyPEM returns a functional option that adds HostSigners to the server +// from a PEM file as bytes. +func HostKeyPEM(bytes []byte) Option { + return func(srv *Server) error { + signer, err := gossh.ParsePrivateKey(bytes) + if err != nil { + return err + } + + srv.AddHostKey(signer) + + return nil + } +} + +// NoPty returns a functional option that sets PtyCallback to return false, +// denying PTY requests. +func NoPty() Option { + return func(srv *Server) error { + srv.PtyCallback = func(ctx Context, pty Pty) bool { + return false + } + return nil + } +} + +// WrapConn returns a functional option that sets ConnCallback on the server. +func WrapConn(fn ConnCallback) Option { + return func(srv *Server) error { + srv.ConnCallback = fn + return nil + } +} diff --git a/vendor/github.com/gliderlabs/ssh/server.go b/vendor/github.com/gliderlabs/ssh/server.go new file mode 100644 index 0000000000..9ff09169a7 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/server.go @@ -0,0 +1,394 @@ +package ssh + +import ( + "context" + "errors" + "fmt" + "net" + "sync" + "time" + + gossh "golang.org/x/crypto/ssh" +) + +// ErrServerClosed is returned by the Server's Serve, ListenAndServe, +// and ListenAndServeTLS methods after a call to Shutdown or Close. +var ErrServerClosed = errors.New("ssh: Server closed") + +type RequestHandler func(ctx Context, srv *Server, req *gossh.Request) (ok bool, payload []byte) + +var DefaultRequestHandlers = map[string]RequestHandler{} + +type ChannelHandler func(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context) + +var DefaultChannelHandlers = map[string]ChannelHandler{ + "session": DefaultSessionHandler, +} + +// Server defines parameters for running an SSH server. The zero value for +// Server is a valid configuration. When both PasswordHandler and +// PublicKeyHandler are nil, no client authentication is performed. +type Server struct { + Addr string // TCP address to listen on, ":22" if empty + Handler Handler // handler to invoke, ssh.DefaultHandler if nil + HostSigners []Signer // private keys for the host key, must have at least one + Version string // server version to be sent before the initial handshake + + KeyboardInteractiveHandler KeyboardInteractiveHandler // keyboard-interactive authentication handler + PasswordHandler PasswordHandler // password authentication handler + PublicKeyHandler PublicKeyHandler // public key authentication handler + PtyCallback PtyCallback // callback for allowing PTY sessions, allows all if nil + ConnCallback ConnCallback // optional callback for wrapping net.Conn before handling + LocalPortForwardingCallback LocalPortForwardingCallback // callback for allowing local port forwarding, denies all if nil + ReversePortForwardingCallback ReversePortForwardingCallback // callback for allowing reverse port forwarding, denies all if nil + ServerConfigCallback ServerConfigCallback // callback for configuring detailed SSH options + SessionRequestCallback SessionRequestCallback // callback for allowing or denying SSH sessions + + IdleTimeout time.Duration // connection timeout when no activity, none if empty + MaxTimeout time.Duration // absolute connection timeout, none if empty + + // ChannelHandlers allow overriding the built-in session handlers or provide + // extensions to the protocol, such as tcpip forwarding. By default only the + // "session" handler is enabled. + ChannelHandlers map[string]ChannelHandler + + // RequestHandlers allow overriding the server-level request handlers or + // provide extensions to the protocol, such as tcpip forwarding. By default + // no handlers are enabled. + RequestHandlers map[string]RequestHandler + + listenerWg sync.WaitGroup + mu sync.Mutex + listeners map[net.Listener]struct{} + conns map[*gossh.ServerConn]struct{} + connWg sync.WaitGroup + doneChan chan struct{} +} + +func (srv *Server) ensureHostSigner() error { + if len(srv.HostSigners) == 0 { + signer, err := generateSigner() + if err != nil { + return err + } + srv.HostSigners = append(srv.HostSigners, signer) + } + return nil +} + +func (srv *Server) ensureHandlers() { + srv.mu.Lock() + defer srv.mu.Unlock() + if srv.RequestHandlers == nil { + srv.RequestHandlers = map[string]RequestHandler{} + for k, v := range DefaultRequestHandlers { + srv.RequestHandlers[k] = v + } + } + if srv.ChannelHandlers == nil { + srv.ChannelHandlers = map[string]ChannelHandler{} + for k, v := range DefaultChannelHandlers { + srv.ChannelHandlers[k] = v + } + } +} + +func (srv *Server) config(ctx Context) *gossh.ServerConfig { + var config *gossh.ServerConfig + if srv.ServerConfigCallback == nil { + config = &gossh.ServerConfig{} + } else { + config = srv.ServerConfigCallback(ctx) + } + for _, signer := range srv.HostSigners { + config.AddHostKey(signer) + } + if srv.PasswordHandler == nil && srv.PublicKeyHandler == nil { + config.NoClientAuth = true + } + if srv.Version != "" { + config.ServerVersion = "SSH-2.0-" + srv.Version + } + if srv.PasswordHandler != nil { + config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) { + applyConnMetadata(ctx, conn) + if ok := srv.PasswordHandler(ctx, string(password)); !ok { + return ctx.Permissions().Permissions, fmt.Errorf("permission denied") + } + return ctx.Permissions().Permissions, nil + } + } + if srv.PublicKeyHandler != nil { + config.PublicKeyCallback = func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) { + applyConnMetadata(ctx, conn) + if ok := srv.PublicKeyHandler(ctx, key); !ok { + return ctx.Permissions().Permissions, fmt.Errorf("permission denied") + } + ctx.SetValue(ContextKeyPublicKey, key) + return ctx.Permissions().Permissions, nil + } + } + if srv.KeyboardInteractiveHandler != nil { + config.KeyboardInteractiveCallback = func(conn gossh.ConnMetadata, challenger gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) { + if ok := srv.KeyboardInteractiveHandler(ctx, challenger); !ok { + return ctx.Permissions().Permissions, fmt.Errorf("permission denied") + } + return ctx.Permissions().Permissions, nil + } + } + return config +} + +// Handle sets the Handler for the server. +func (srv *Server) Handle(fn Handler) { + srv.Handler = fn +} + +// Close immediately closes all active listeners and all active +// connections. +// +// Close returns any error returned from closing the Server's +// underlying Listener(s). +func (srv *Server) Close() error { + srv.mu.Lock() + defer srv.mu.Unlock() + srv.closeDoneChanLocked() + err := srv.closeListenersLocked() + for c := range srv.conns { + c.Close() + delete(srv.conns, c) + } + return err +} + +// Shutdown gracefully shuts down the server without interrupting any +// active connections. Shutdown works by first closing all open +// listeners, and then waiting indefinitely for connections to close. +// If the provided context expires before the shutdown is complete, +// then the context's error is returned. +func (srv *Server) Shutdown(ctx context.Context) error { + srv.mu.Lock() + lnerr := srv.closeListenersLocked() + srv.closeDoneChanLocked() + srv.mu.Unlock() + + finished := make(chan struct{}, 1) + go func() { + srv.listenerWg.Wait() + srv.connWg.Wait() + finished <- struct{}{} + }() + + select { + case <-ctx.Done(): + return ctx.Err() + case <-finished: + return lnerr + } +} + +// Serve accepts incoming connections on the Listener l, creating a new +// connection goroutine for each. The connection goroutines read requests and then +// calls srv.Handler to handle sessions. +// +// Serve always returns a non-nil error. +func (srv *Server) Serve(l net.Listener) error { + srv.ensureHandlers() + defer l.Close() + if err := srv.ensureHostSigner(); err != nil { + return err + } + if srv.Handler == nil { + srv.Handler = DefaultHandler + } + var tempDelay time.Duration + + srv.trackListener(l, true) + defer srv.trackListener(l, false) + for { + conn, e := l.Accept() + if e != nil { + select { + case <-srv.getDoneChan(): + return ErrServerClosed + default: + } + if ne, ok := e.(net.Error); ok && ne.Temporary() { + if tempDelay == 0 { + tempDelay = 5 * time.Millisecond + } else { + tempDelay *= 2 + } + if max := 1 * time.Second; tempDelay > max { + tempDelay = max + } + time.Sleep(tempDelay) + continue + } + return e + } + go srv.handleConn(conn) + } +} + +func (srv *Server) handleConn(newConn net.Conn) { + if srv.ConnCallback != nil { + cbConn := srv.ConnCallback(newConn) + if cbConn == nil { + newConn.Close() + return + } + newConn = cbConn + } + ctx, cancel := newContext(srv) + conn := &serverConn{ + Conn: newConn, + idleTimeout: srv.IdleTimeout, + closeCanceler: cancel, + } + if srv.MaxTimeout > 0 { + conn.maxDeadline = time.Now().Add(srv.MaxTimeout) + } + defer conn.Close() + sshConn, chans, reqs, err := gossh.NewServerConn(conn, srv.config(ctx)) + if err != nil { + // TODO: trigger event callback + return + } + + srv.trackConn(sshConn, true) + defer srv.trackConn(sshConn, false) + + ctx.SetValue(ContextKeyConn, sshConn) + applyConnMetadata(ctx, sshConn) + //go gossh.DiscardRequests(reqs) + go srv.handleRequests(ctx, reqs) + for ch := range chans { + handler := srv.ChannelHandlers[ch.ChannelType()] + if handler == nil { + handler = srv.ChannelHandlers["default"] + } + if handler == nil { + ch.Reject(gossh.UnknownChannelType, "unsupported channel type") + continue + } + go handler(srv, sshConn, ch, ctx) + } +} + +func (srv *Server) handleRequests(ctx Context, in <-chan *gossh.Request) { + for req := range in { + handler := srv.RequestHandlers[req.Type] + if handler == nil { + handler = srv.RequestHandlers["default"] + } + if handler == nil { + req.Reply(false, nil) + continue + } + /*reqCtx, cancel := context.WithCancel(ctx) + defer cancel() */ + ret, payload := handler(ctx, srv, req) + req.Reply(ret, payload) + } +} + +// ListenAndServe listens on the TCP network address srv.Addr and then calls +// Serve to handle incoming connections. If srv.Addr is blank, ":22" is used. +// ListenAndServe always returns a non-nil error. +func (srv *Server) ListenAndServe() error { + addr := srv.Addr + if addr == "" { + addr = ":22" + } + ln, err := net.Listen("tcp", addr) + if err != nil { + return err + } + return srv.Serve(ln) +} + +// AddHostKey adds a private key as a host key. If an existing host key exists +// with the same algorithm, it is overwritten. Each server config must have at +// least one host key. +func (srv *Server) AddHostKey(key Signer) { + // these are later added via AddHostKey on ServerConfig, which performs the + // check for one of every algorithm. + srv.HostSigners = append(srv.HostSigners, key) +} + +// SetOption runs a functional option against the server. +func (srv *Server) SetOption(option Option) error { + return option(srv) +} + +func (srv *Server) getDoneChan() <-chan struct{} { + srv.mu.Lock() + defer srv.mu.Unlock() + return srv.getDoneChanLocked() +} + +func (srv *Server) getDoneChanLocked() chan struct{} { + if srv.doneChan == nil { + srv.doneChan = make(chan struct{}) + } + return srv.doneChan +} + +func (srv *Server) closeDoneChanLocked() { + ch := srv.getDoneChanLocked() + select { + case <-ch: + // Already closed. Don't close again. + default: + // Safe to close here. We're the only closer, guarded + // by srv.mu. + close(ch) + } +} + +func (srv *Server) closeListenersLocked() error { + var err error + for ln := range srv.listeners { + if cerr := ln.Close(); cerr != nil && err == nil { + err = cerr + } + delete(srv.listeners, ln) + } + return err +} + +func (srv *Server) trackListener(ln net.Listener, add bool) { + srv.mu.Lock() + defer srv.mu.Unlock() + if srv.listeners == nil { + srv.listeners = make(map[net.Listener]struct{}) + } + if add { + // If the *Server is being reused after a previous + // Close or Shutdown, reset its doneChan: + if len(srv.listeners) == 0 && len(srv.conns) == 0 { + srv.doneChan = nil + } + srv.listeners[ln] = struct{}{} + srv.listenerWg.Add(1) + } else { + delete(srv.listeners, ln) + srv.listenerWg.Done() + } +} + +func (srv *Server) trackConn(c *gossh.ServerConn, add bool) { + srv.mu.Lock() + defer srv.mu.Unlock() + if srv.conns == nil { + srv.conns = make(map[*gossh.ServerConn]struct{}) + } + if add { + srv.conns[c] = struct{}{} + srv.connWg.Add(1) + } else { + delete(srv.conns, c) + srv.connWg.Done() + } +} diff --git a/vendor/github.com/gliderlabs/ssh/session.go b/vendor/github.com/gliderlabs/ssh/session.go new file mode 100644 index 0000000000..6c77d6c8a7 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/session.go @@ -0,0 +1,308 @@ +package ssh + +import ( + "bytes" + "context" + "errors" + "fmt" + "net" + "sync" + + "github.com/anmitsu/go-shlex" + gossh "golang.org/x/crypto/ssh" +) + +// Session provides access to information about an SSH session and methods +// to read and write to the SSH channel with an embedded Channel interface from +// cypto/ssh. +// +// When Command() returns an empty slice, the user requested a shell. Otherwise +// the user is performing an exec with those command arguments. +// +// TODO: Signals +type Session interface { + gossh.Channel + + // User returns the username used when establishing the SSH connection. + User() string + + // RemoteAddr returns the net.Addr of the client side of the connection. + RemoteAddr() net.Addr + + // LocalAddr returns the net.Addr of the server side of the connection. + LocalAddr() net.Addr + + // Environ returns a copy of strings representing the environment set by the + // user for this session, in the form "key=value". + Environ() []string + + // Exit sends an exit status and then closes the session. + Exit(code int) error + + // Command returns a shell parsed slice of arguments that were provided by the + // user. Shell parsing splits the command string according to POSIX shell rules, + // which considers quoting not just whitespace. + Command() []string + + // RawCommand returns the exact command that was provided by the user. + RawCommand() string + + // PublicKey returns the PublicKey used to authenticate. If a public key was not + // used it will return nil. + PublicKey() PublicKey + + // Context returns the connection's context. The returned context is always + // non-nil and holds the same data as the Context passed into auth + // handlers and callbacks. + // + // The context is canceled when the client's connection closes or I/O + // operation fails. + Context() context.Context + + // Permissions returns a copy of the Permissions object that was available for + // setup in the auth handlers via the Context. + Permissions() Permissions + + // Pty returns PTY information, a channel of window size changes, and a boolean + // of whether or not a PTY was accepted for this session. + Pty() (Pty, <-chan Window, bool) + + // Signals registers a channel to receive signals sent from the client. The + // channel must handle signal sends or it will block the SSH request loop. + // Registering nil will unregister the channel from signal sends. During the + // time no channel is registered signals are buffered up to a reasonable amount. + // If there are buffered signals when a channel is registered, they will be + // sent in order on the channel immediately after registering. + Signals(c chan<- Signal) +} + +// maxSigBufSize is how many signals will be buffered +// when there is no signal channel specified +const maxSigBufSize = 128 + +func DefaultSessionHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context) { + ch, reqs, err := newChan.Accept() + if err != nil { + // TODO: trigger event callback + return + } + sess := &session{ + Channel: ch, + conn: conn, + handler: srv.Handler, + ptyCb: srv.PtyCallback, + sessReqCb: srv.SessionRequestCallback, + ctx: ctx, + } + sess.handleRequests(reqs) +} + +type session struct { + sync.Mutex + gossh.Channel + conn *gossh.ServerConn + handler Handler + handled bool + exited bool + pty *Pty + winch chan Window + env []string + ptyCb PtyCallback + sessReqCb SessionRequestCallback + rawCmd string + ctx Context + sigCh chan<- Signal + sigBuf []Signal +} + +func (sess *session) Write(p []byte) (n int, err error) { + if sess.pty != nil { + m := len(p) + // normalize \n to \r\n when pty is accepted. + // this is a hardcoded shortcut since we don't support terminal modes. + p = bytes.Replace(p, []byte{'\n'}, []byte{'\r', '\n'}, -1) + p = bytes.Replace(p, []byte{'\r', '\r', '\n'}, []byte{'\r', '\n'}, -1) + n, err = sess.Channel.Write(p) + if n > m { + n = m + } + return + } + return sess.Channel.Write(p) +} + +func (sess *session) PublicKey() PublicKey { + sessionkey := sess.ctx.Value(ContextKeyPublicKey) + if sessionkey == nil { + return nil + } + return sessionkey.(PublicKey) +} + +func (sess *session) Permissions() Permissions { + // use context permissions because its properly + // wrapped and easier to dereference + perms := sess.ctx.Value(ContextKeyPermissions).(*Permissions) + return *perms +} + +func (sess *session) Context() context.Context { + return sess.ctx +} + +func (sess *session) Exit(code int) error { + sess.Lock() + defer sess.Unlock() + if sess.exited { + return errors.New("Session.Exit called multiple times") + } + sess.exited = true + + status := struct{ Status uint32 }{uint32(code)} + _, err := sess.SendRequest("exit-status", false, gossh.Marshal(&status)) + if err != nil { + return err + } + return sess.Close() +} + +func (sess *session) User() string { + return sess.conn.User() +} + +func (sess *session) RemoteAddr() net.Addr { + return sess.conn.RemoteAddr() +} + +func (sess *session) LocalAddr() net.Addr { + return sess.conn.LocalAddr() +} + +func (sess *session) Environ() []string { + return append([]string(nil), sess.env...) +} + +func (sess *session) RawCommand() string { + return sess.rawCmd +} + +func (sess *session) Command() []string { + cmd, _ := shlex.Split(sess.rawCmd, true) + return append([]string(nil), cmd...) +} + +func (sess *session) Pty() (Pty, <-chan Window, bool) { + if sess.pty != nil { + return *sess.pty, sess.winch, true + } + return Pty{}, sess.winch, false +} + +func (sess *session) Signals(c chan<- Signal) { + sess.Lock() + defer sess.Unlock() + sess.sigCh = c + if len(sess.sigBuf) > 0 { + go func() { + for _, sig := range sess.sigBuf { + sess.sigCh <- sig + } + }() + } +} + +func (sess *session) handleRequests(reqs <-chan *gossh.Request) { + for req := range reqs { + switch req.Type { + case "shell", "exec": + if sess.handled { + req.Reply(false, nil) + continue + } + + var payload = struct{ Value string }{} + gossh.Unmarshal(req.Payload, &payload) + sess.rawCmd = payload.Value + + // If there's a session policy callback, we need to confirm before + // accepting the session. + if sess.sessReqCb != nil && !sess.sessReqCb(sess, req.Type) { + sess.rawCmd = "" + req.Reply(false, nil) + continue + } + + sess.handled = true + req.Reply(true, nil) + + go func() { + sess.handler(sess) + sess.Exit(0) + }() + case "env": + if sess.handled { + req.Reply(false, nil) + continue + } + var kv struct{ Key, Value string } + gossh.Unmarshal(req.Payload, &kv) + sess.env = append(sess.env, fmt.Sprintf("%s=%s", kv.Key, kv.Value)) + req.Reply(true, nil) + case "signal": + var payload struct{ Signal string } + gossh.Unmarshal(req.Payload, &payload) + sess.Lock() + if sess.sigCh != nil { + sess.sigCh <- Signal(payload.Signal) + } else { + if len(sess.sigBuf) < maxSigBufSize { + sess.sigBuf = append(sess.sigBuf, Signal(payload.Signal)) + } + } + sess.Unlock() + case "pty-req": + if sess.handled || sess.pty != nil { + req.Reply(false, nil) + continue + } + ptyReq, ok := parsePtyRequest(req.Payload) + if !ok { + req.Reply(false, nil) + continue + } + if sess.ptyCb != nil { + ok := sess.ptyCb(sess.ctx, ptyReq) + if !ok { + req.Reply(false, nil) + continue + } + } + sess.pty = &ptyReq + sess.winch = make(chan Window, 1) + sess.winch <- ptyReq.Window + defer func() { + // when reqs is closed + close(sess.winch) + }() + req.Reply(ok, nil) + case "window-change": + if sess.pty == nil { + req.Reply(false, nil) + continue + } + win, ok := parseWinchRequest(req.Payload) + if ok { + sess.pty.Window = win + sess.winch <- win + } + req.Reply(ok, nil) + case agentRequestType: + // TODO: option/callback to allow agent forwarding + SetAgentRequested(sess.ctx) + req.Reply(true, nil) + default: + // TODO: debug log + req.Reply(false, nil) + } + } +} diff --git a/vendor/github.com/gliderlabs/ssh/ssh.go b/vendor/github.com/gliderlabs/ssh/ssh.go new file mode 100644 index 0000000000..f5a935a984 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/ssh.go @@ -0,0 +1,123 @@ +package ssh + +import ( + "crypto/subtle" + "net" + + gossh "golang.org/x/crypto/ssh" +) + +type Signal string + +// POSIX signals as listed in RFC 4254 Section 6.10. +const ( + SIGABRT Signal = "ABRT" + SIGALRM Signal = "ALRM" + SIGFPE Signal = "FPE" + SIGHUP Signal = "HUP" + SIGILL Signal = "ILL" + SIGINT Signal = "INT" + SIGKILL Signal = "KILL" + SIGPIPE Signal = "PIPE" + SIGQUIT Signal = "QUIT" + SIGSEGV Signal = "SEGV" + SIGTERM Signal = "TERM" + SIGUSR1 Signal = "USR1" + SIGUSR2 Signal = "USR2" +) + +// DefaultHandler is the default Handler used by Serve. +var DefaultHandler Handler + +// Option is a functional option handler for Server. +type Option func(*Server) error + +// Handler is a callback for handling established SSH sessions. +type Handler func(Session) + +// PublicKeyHandler is a callback for performing public key authentication. +type PublicKeyHandler func(ctx Context, key PublicKey) bool + +// PasswordHandler is a callback for performing password authentication. +type PasswordHandler func(ctx Context, password string) bool + +// KeyboardInteractiveHandler is a callback for performing keyboard-interactive authentication. +type KeyboardInteractiveHandler func(ctx Context, challenger gossh.KeyboardInteractiveChallenge) bool + +// PtyCallback is a hook for allowing PTY sessions. +type PtyCallback func(ctx Context, pty Pty) bool + +// SessionRequestCallback is a callback for allowing or denying SSH sessions. +type SessionRequestCallback func(sess Session, requestType string) bool + +// ConnCallback is a hook for new connections before handling. +// It allows wrapping for timeouts and limiting by returning +// the net.Conn that will be used as the underlying connection. +type ConnCallback func(conn net.Conn) net.Conn + +// LocalPortForwardingCallback is a hook for allowing port forwarding +type LocalPortForwardingCallback func(ctx Context, destinationHost string, destinationPort uint32) bool + +// ReversePortForwardingCallback is a hook for allowing reverse port forwarding +type ReversePortForwardingCallback func(ctx Context, bindHost string, bindPort uint32) bool + +// ServerConfigCallback is a hook for creating custom default server configs +type ServerConfigCallback func(ctx Context) *gossh.ServerConfig + +// Window represents the size of a PTY window. +type Window struct { + Width int + Height int +} + +// Pty represents a PTY request and configuration. +type Pty struct { + Term string + Window Window + // HELP WANTED: terminal modes! +} + +// Serve accepts incoming SSH connections on the listener l, creating a new +// connection goroutine for each. The connection goroutines read requests and +// then calls handler to handle sessions. Handler is typically nil, in which +// case the DefaultHandler is used. +func Serve(l net.Listener, handler Handler, options ...Option) error { + srv := &Server{Handler: handler} + for _, option := range options { + if err := srv.SetOption(option); err != nil { + return err + } + } + return srv.Serve(l) +} + +// ListenAndServe listens on the TCP network address addr and then calls Serve +// with handler to handle sessions on incoming connections. Handler is typically +// nil, in which case the DefaultHandler is used. +func ListenAndServe(addr string, handler Handler, options ...Option) error { + srv := &Server{Addr: addr, Handler: handler} + for _, option := range options { + if err := srv.SetOption(option); err != nil { + return err + } + } + return srv.ListenAndServe() +} + +// Handle registers the handler as the DefaultHandler. +func Handle(handler Handler) { + DefaultHandler = handler +} + +// KeysEqual is constant time compare of the keys to avoid timing attacks. +func KeysEqual(ak, bk PublicKey) bool { + + //avoid panic if one of the keys is nil, return false instead + if ak == nil || bk == nil { + return false + } + + a := ak.Marshal() + b := bk.Marshal() + return (len(a) == len(b) && subtle.ConstantTimeCompare(a, b) == 1) +} diff --git a/vendor/github.com/gliderlabs/ssh/tcpip.go b/vendor/github.com/gliderlabs/ssh/tcpip.go new file mode 100644 index 0000000000..335fda6575 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/tcpip.go @@ -0,0 +1,193 @@ +package ssh + +import ( + "io" + "log" + "net" + "strconv" + "sync" + + gossh "golang.org/x/crypto/ssh" +) + +const ( + forwardedTCPChannelType = "forwarded-tcpip" +) + +// direct-tcpip data struct as specified in RFC4254, Section 7.2 +type localForwardChannelData struct { + DestAddr string + DestPort uint32 + + OriginAddr string + OriginPort uint32 +} + +// DirectTCPIPHandler can be enabled by adding it to the server's +// ChannelHandlers under direct-tcpip. +func DirectTCPIPHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context) { + d := localForwardChannelData{} + if err := gossh.Unmarshal(newChan.ExtraData(), &d); err != nil { + newChan.Reject(gossh.ConnectionFailed, "error parsing forward data: "+err.Error()) + return + } + + if srv.LocalPortForwardingCallback == nil || !srv.LocalPortForwardingCallback(ctx, d.DestAddr, d.DestPort) { + newChan.Reject(gossh.Prohibited, "port forwarding is disabled") + return + } + + dest := net.JoinHostPort(d.DestAddr, strconv.FormatInt(int64(d.DestPort), 10)) + + var dialer net.Dialer + dconn, err := dialer.DialContext(ctx, "tcp", dest) + if err != nil { + newChan.Reject(gossh.ConnectionFailed, err.Error()) + return + } + + ch, reqs, err := newChan.Accept() + if err != nil { + dconn.Close() + return + } + go gossh.DiscardRequests(reqs) + + go func() { + defer ch.Close() + defer dconn.Close() + io.Copy(ch, dconn) + }() + go func() { + defer ch.Close() + defer dconn.Close() + io.Copy(dconn, ch) + }() +} + +type remoteForwardRequest struct { + BindAddr string + BindPort uint32 +} + +type remoteForwardSuccess struct { + BindPort uint32 +} + +type remoteForwardCancelRequest struct { + BindAddr string + BindPort uint32 +} + +type remoteForwardChannelData struct { + DestAddr string + DestPort uint32 + OriginAddr string + OriginPort uint32 +} + +// ForwardedTCPHandler can be enabled by creating a ForwardedTCPHandler and +// adding the HandleSSHRequest callback to the server's RequestHandlers under +// tcpip-forward and cancel-tcpip-forward. +type ForwardedTCPHandler struct { + forwards map[string]net.Listener + sync.Mutex +} + +func (h *ForwardedTCPHandler) HandleSSHRequest(ctx Context, srv *Server, req *gossh.Request) (bool, []byte) { + h.Lock() + if h.forwards == nil { + h.forwards = make(map[string]net.Listener) + } + h.Unlock() + conn := ctx.Value(ContextKeyConn).(*gossh.ServerConn) + switch req.Type { + case "tcpip-forward": + var reqPayload remoteForwardRequest + if err := gossh.Unmarshal(req.Payload, &reqPayload); err != nil { + // TODO: log parse failure + return false, []byte{} + } + if srv.ReversePortForwardingCallback == nil || !srv.ReversePortForwardingCallback(ctx, reqPayload.BindAddr, reqPayload.BindPort) { + return false, []byte("port forwarding is disabled") + } + addr := net.JoinHostPort(reqPayload.BindAddr, strconv.Itoa(int(reqPayload.BindPort))) + ln, err := net.Listen("tcp", addr) + if err != nil { + // TODO: log listen failure + return false, []byte{} + } + _, destPortStr, _ := net.SplitHostPort(ln.Addr().String()) + destPort, _ := strconv.Atoi(destPortStr) + h.Lock() + h.forwards[addr] = ln + h.Unlock() + go func() { + <-ctx.Done() + h.Lock() + ln, ok := h.forwards[addr] + h.Unlock() + if ok { + ln.Close() + } + }() + go func() { + for { + c, err := ln.Accept() + if err != nil { + // TODO: log accept failure + break + } + originAddr, orignPortStr, _ := net.SplitHostPort(c.RemoteAddr().String()) + originPort, _ := strconv.Atoi(orignPortStr) + payload := gossh.Marshal(&remoteForwardChannelData{ + DestAddr: reqPayload.BindAddr, + DestPort: uint32(destPort), + OriginAddr: originAddr, + OriginPort: uint32(originPort), + }) + go func() { + ch, reqs, err := conn.OpenChannel(forwardedTCPChannelType, payload) + if err != nil { + // TODO: log failure to open channel + log.Println(err) + c.Close() + return + } + go gossh.DiscardRequests(reqs) + go func() { + defer ch.Close() + defer c.Close() + io.Copy(ch, c) + }() + go func() { + defer ch.Close() + defer c.Close() + io.Copy(c, ch) + }() + }() + } + h.Lock() + delete(h.forwards, addr) + h.Unlock() + }() + return true, gossh.Marshal(&remoteForwardSuccess{uint32(destPort)}) + + case "cancel-tcpip-forward": + var reqPayload remoteForwardCancelRequest + if err := gossh.Unmarshal(req.Payload, &reqPayload); err != nil { + // TODO: log parse failure + return false, []byte{} + } + addr := net.JoinHostPort(reqPayload.BindAddr, strconv.Itoa(int(reqPayload.BindPort))) + h.Lock() + ln, ok := h.forwards[addr] + h.Unlock() + if ok { + ln.Close() + } + return true, nil + default: + return false, nil + } +} diff --git a/vendor/github.com/gliderlabs/ssh/util.go b/vendor/github.com/gliderlabs/ssh/util.go new file mode 100644 index 0000000000..015a44ecc0 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/util.go @@ -0,0 +1,83 @@ +package ssh + +import ( + "crypto/rand" + "crypto/rsa" + "encoding/binary" + + "golang.org/x/crypto/ssh" +) + +func generateSigner() (ssh.Signer, error) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, err + } + return ssh.NewSignerFromKey(key) +} + +func parsePtyRequest(s []byte) (pty Pty, ok bool) { + term, s, ok := parseString(s) + if !ok { + return + } + width32, s, ok := parseUint32(s) + if !ok { + return + } + height32, _, ok := parseUint32(s) + if !ok { + return + } + pty = Pty{ + Term: term, + Window: Window{ + Width: int(width32), + Height: int(height32), + }, + } + return +} + +func parseWinchRequest(s []byte) (win Window, ok bool) { + width32, s, ok := parseUint32(s) + if width32 < 1 { + ok = false + } + if !ok { + return + } + height32, _, ok := parseUint32(s) + if height32 < 1 { + ok = false + } + if !ok { + return + } + win = Window{ + Width: int(width32), + Height: int(height32), + } + return +} + +func parseString(in []byte) (out string, rest []byte, ok bool) { + if len(in) < 4 { + return + } + length := binary.BigEndian.Uint32(in) + if uint32(len(in)) < 4+length { + return + } + out = string(in[4 : 4+length]) + rest = in[4+length:] + ok = true + return +} + +func parseUint32(in []byte) (uint32, []byte, bool) { + if len(in) < 4 { + return 0, nil, false + } + return binary.BigEndian.Uint32(in), in[4:], true +} diff --git a/vendor/github.com/gliderlabs/ssh/wrap.go b/vendor/github.com/gliderlabs/ssh/wrap.go new file mode 100644 index 0000000000..d1f2b161e6 --- /dev/null +++ b/vendor/github.com/gliderlabs/ssh/wrap.go @@ -0,0 +1,33 @@ +package ssh + +import gossh "golang.org/x/crypto/ssh" + +// PublicKey is an abstraction of different types of public keys. +type PublicKey interface { + gossh.PublicKey +} + +// The Permissions type holds fine-grained permissions that are specific to a +// user or a specific authentication method for a user. Permissions, except for +// "source-address", must be enforced in the server application layer, after +// successful authentication. +type Permissions struct { + *gossh.Permissions +} + +// A Signer can create signatures that verify against a public key. +type Signer interface { + gossh.Signer +} + +// ParseAuthorizedKey parses a public key from an authorized_keys file used in +// OpenSSH according to the sshd(8) manual page. +func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { + return gossh.ParseAuthorizedKey(in) +} + +// ParsePublicKey parses an SSH public key formatted for use in +// the SSH wire protocol according to RFC 4253, section 6.6. +func ParsePublicKey(in []byte) (out PublicKey, err error) { + return gossh.ParsePublicKey(in) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index c92545ea51..f5c1b8800e 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -13,7 +13,6 @@ package unix import ( "encoding/binary" - "net" "runtime" "syscall" "unsafe" @@ -765,7 +764,7 @@ const px_proto_oe = 0 type SockaddrPPPoE struct { SID uint16 - Remote net.HardwareAddr + Remote []byte Dev string raw RawSockaddrPPPoX } @@ -916,7 +915,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { } sa := &SockaddrPPPoE{ SID: binary.BigEndian.Uint16(pp[6:8]), - Remote: net.HardwareAddr(pp[8:14]), + Remote: pp[8:14], } for i := 14; i < 14+IFNAMSIZ; i++ { if pp[i] == 0 { diff --git a/vendor/golang.org/x/sys/unix/types_netbsd.go b/vendor/golang.org/x/sys/unix/types_netbsd.go index 2dd4f9542c..4a96d72c37 100644 --- a/vendor/golang.org/x/sys/unix/types_netbsd.go +++ b/vendor/golang.org/x/sys/unix/types_netbsd.go @@ -254,6 +254,7 @@ type Ptmget C.struct_ptmget const ( AT_FDCWD = C.AT_FDCWD + AT_SYMLINK_FOLLOW = C.AT_SYMLINK_FOLLOW AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW ) diff --git a/vendor/golang.org/x/sys/unix/types_openbsd.go b/vendor/golang.org/x/sys/unix/types_openbsd.go index 8aafbe4469..775cb57dc8 100644 --- a/vendor/golang.org/x/sys/unix/types_openbsd.go +++ b/vendor/golang.org/x/sys/unix/types_openbsd.go @@ -241,6 +241,7 @@ type Winsize C.struct_winsize const ( AT_FDCWD = C.AT_FDCWD + AT_SYMLINK_FOLLOW = C.AT_SYMLINK_FOLLOW AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go index a2268b4f62..86736ab6e7 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go @@ -411,6 +411,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go index 59e1da0a6a..3427811f98 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go @@ -418,6 +418,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go index 1f1f0f3819..399f37a434 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go @@ -416,6 +416,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go index 8dca204a9c..32f0c15d98 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go @@ -418,6 +418,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go index 900fb44622..61ea0019a2 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go @@ -436,6 +436,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go index 028fa78d74..87a493f68f 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go @@ -436,6 +436,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go index b45d5eedff..d80836efab 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go @@ -437,6 +437,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go index fa369a32a2..4e158746f1 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go @@ -430,6 +430,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index be8c50f253..b23050924f 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -294,7 +294,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) = ole32.CLSIDFromString //sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2 //sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid -//sys coTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree +//sys CoTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree //sys rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion // syscall interface implementation for other packages @@ -1302,7 +1302,7 @@ func (t Token) KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, e if err != nil { return "", err } - defer coTaskMemFree(unsafe.Pointer(p)) + defer CoTaskMemFree(unsafe.Pointer(p)) return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil } diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 9e43e966cf..d461bed98a 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -2517,7 +2517,7 @@ func coCreateGuid(pguid *GUID) (ret error) { return } -func coTaskMemFree(address unsafe.Pointer) { +func CoTaskMemFree(address unsafe.Pointer) { syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0) return } diff --git a/vendor/modules.txt b/vendor/modules.txt index d9da4be69d..91397a577b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -15,6 +15,8 @@ github.com/Unknwon/i18n github.com/Unknwon/paginater # github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 github.com/andybalholm/cascadia +# github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 +github.com/anmitsu/go-shlex # github.com/beorn7/perks v1.0.0 github.com/beorn7/perks/quantile # github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3 @@ -112,6 +114,8 @@ github.com/facebookgo/grace/gracenet github.com/facebookgo/httpdown # github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 github.com/facebookgo/stats +# github.com/gliderlabs/ssh v0.2.2 +github.com/gliderlabs/ssh # github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd github.com/glycerine/go-unsnap-stream # github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 @@ -353,7 +357,7 @@ golang.org/x/crypto/cast5 golang.org/x/crypto/openpgp/elgamal golang.org/x/crypto/ssh/knownhosts golang.org/x/crypto/ssh/agent -# golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 +# golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b golang.org/x/net/html/charset golang.org/x/net/html golang.org/x/net/html/atom @@ -365,7 +369,7 @@ golang.org/x/net/internal/socks # golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sys v0.0.0-20190618155005-516e3c20635f +# golang.org/x/sys v0.0.0-20190620070143-6f217b454f45 golang.org/x/sys/windows golang.org/x/sys/windows/svc golang.org/x/sys/unix From b282d4e1216964eae54a7b5d10c2ec2feb88a11e Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 7 Jul 2019 01:30:14 +0000 Subject: [PATCH 194/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_nl-NL.ini | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index c97c72cbef..ecbe980bc8 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -87,6 +87,7 @@ user=Gebruikersnaam password=Wachtwoord db_name=Database naam ssl_mode=SSL +charset=Karakterset path=Pad sqlite_helper=Bestandspad voor de SQLite3-database.
      Vul een volledig pad in als je GItea als een service uitvoert. err_empty_db_path=SQLite3 database pad mag niet leeg zijn. @@ -213,7 +214,11 @@ resent_limit_prompt=Sorry, je hebt te snel na elkaar een aanvraag gedaan voor ee has_unconfirmed_mail=Beste %s, u heeft een onbevestigd e-mailadres (%s). Als u nog geen bevestiging heeft ontvangen, of u een nieuwe aanvraag wilt doen, klik dan op de onderstaande knop. resend_mail=Klik hier om uw activatie mail nog een keer te verzenden email_not_associate=Dit emailadres is niet gekoppeld aan een account. +send_reset_mail=Stuur account herstel e-mail +reset_password=Account herstel invalid_code=Uw bevestigingscode is ongeldig of is verlopen. +reset_password_helper=Account herstellen +reset_password_wrong_user=U bent ingelogd als %s, maar de account herstel link is voor %s password_too_short=De lengte van uw wachtwoord moet tenminste %d karakters zijn. non_local_account=Non-lokale gebruikers mogen hun wachtwoord niet wijzigen via de webinterface. verify=Verifiëren @@ -236,10 +241,14 @@ openid_register_title=Nieuw account aanmaken openid_register_desc=De gekozen OpenID-URI is onbekend. Koppel het aan een nieuw account hier. openid_signin_desc=Geef uw OpenID-URI. Bijvoorbeeld: https://anne.me, bob.openid.org.cn of gnusocial.net/carry. email_domain_blacklisted=Je kan je niet registreren met dit e-mailadres. +authorize_application=Autoriseer applicatie +authorize_application_created_by=Deze applicatie is gemaakt door %s. +authorization_failed=Autorisatie mislukt [mail] activate_account=Activeer uw account activate_email=Verifieer uw e-mailadres +reset_password=Account herstellen register_success=Registratie succesvol register_notify=Welkom bij Gitea @@ -317,6 +326,7 @@ following=Volgt follow=Volg unfollow=Niet meer volgen heatmap.loading=Heatmap wordt geladen… +user_bio=Biografie form.name_reserved=De gebruikersnaam '%s' is gereserveerd. form.name_pattern_not_allowed=Het patroon '%s' is niet toegestaan in een gebruikersnaam. @@ -419,6 +429,7 @@ add_gpg_key_success=De GPG-sleutel '%s' is toegevoegd. delete_key=Verwijder ssh_key_deletion=Verwijder SSH-sleutel gpg_key_deletion=Verwijder GPG-sleutel +ssh_key_deletion_desc=Als je een SSH-sleutel verwijdert, heb er geen toegang meer mee. Doorgaan? gpg_key_deletion_desc=Als je een GPG-sleutel verwijdert, kunnen hiermee ondertekende commits niet meer geverifieerd worden. Doorgaan? ssh_key_deletion_success=De SSH-sleutel is verwijderd. gpg_key_deletion_success=De GPG-sleutel is verwijderd. @@ -452,7 +463,17 @@ access_token_deletion=Verwijder toegangstoken access_token_deletion_desc=Als je een token verwijdert, heeft de applicatie die hem gebruikt geen toegang meer tot je account. Doorgaan? delete_token_success=De token is verwijderd. Applicaties die hem gebruiken, verliezen toegang tot je account. +remove_oauth2_application_success=De applicatie is verwijderd. +create_oauth2_application_button=Maak applicatie +oauth2_application_name=Applicatie naam +oauth2_type_web=Web (bijv. Node.JS, Tomcat, Go) +oauth2_type_native=Native (bijv. Mobiel, Desktop, Browser) +save_application=Opslaan +oauth2_client_id=Client-ID +oauth2_application_edit=Wijzig +revoke_key=Intrekken +revoke_oauth2_grant=Toegang intrekken twofa_desc=Tweefactorauthenticatie verbetert de beveiliging van je account. twofa_is_enrolled=Je account is momenteel ingeschreven voor two-factor authenticatie. @@ -472,7 +493,12 @@ u2f_register_key=Voeg beveiligingssleutel toe u2f_nickname=Gebruikersnaam u2f_delete_key=Verwijder beveiligingssleutel +manage_account_links=Gekoppelde accounts beheren +manage_account_links_desc=Deze externe accounts zijn gekoppeld aan je Gitea-account. +account_links_not_available=Er zijn momenteel geen externe accounts aan je Gitea-account gelinkt. remove_account_link=Gekoppeld account verwijderen +remove_account_link_desc=Als je een gekoppeld account verwijdert, verliest dit account toegang tot je Gitea-account. Doorgaan? +remove_account_link_success=Het gekoppelde account is verwijderd. orgs_none=U bent geen lid van een organisatie. repos_none=U bezit geen repositories @@ -480,12 +506,16 @@ repos_none=U bezit geen repositories delete_account=Verwijder uw account confirm_delete_account=Bevestig verwijdering delete_account_title=Verwijder gebruikers account +delete_account_desc=Weet je zeker dat je dit gebruikersaccount permanent wil verwijderen? [repo] owner=Eigenaar repo_name=Naam van repository +repo_name_helper=Goede repository-namen zijn kort, makkelijk te onthouden en uniek. visibility=Zichtbaarheid visibility_helper=Maak repository privé +visibility_helper_forced=De sitebeheerder verplicht alle repositories om privé te zijn. +visibility_fork_helper=(Verandering van deze waarde zal van invloed zijn op alle forks) fork_repo=Repository forken fork_from=Afsplitsing van repo_desc=Omschrijving @@ -558,6 +588,7 @@ editor.edit_file=Bewerk bestand editor.preview_changes=Voorbeeld tonen editor.edit_this_file=Bewerk bestand editor.delete_this_file=Verwijder bestand +editor.file_delete_success=Bestand '%s' is verwijderd. editor.name_your_file=Bestandsnaam… editor.or=of editor.cancel_lower=Annuleer @@ -569,12 +600,17 @@ editor.commit_message_desc=Voeg een optionele uitgebreide omschrijving toe… editor.create_new_branch=Maak een nieuwe branch voor deze commit en start van een pull-aanvraag. editor.new_branch_name_desc=Nieuwe branch naam… editor.cancel=Annuleer +editor.filename_cannot_be_empty=Bestandsnaam mag niet leeg zijn. editor.branch_already_exists=Branch '%s' bestaat al in deze repository. +editor.file_already_exists=Een bestand met de naam '%s' bestaat al in deze repository. editor.no_changes_to_show=Er zijn geen wijzigingen om weer te geven. editor.fail_to_update_file=Update/maken van bestand '%s' is mislukt: %v editor.add_subdir=Een map toevoegen… +editor.unable_to_upload_files=Uploaden van bestand '%s' is mislukt: %v editor.upload_files_to_dir=Bestanden uploaden naar '%s' +editor.cannot_commit_to_protected_branch=Kan niet committen naar de beveiligde branch '%s'. +commits.desc=Bekijk de broncode-wijzigingsgeschiedenis. commits.commits=Commits commits.search=Zoek commits… commits.find=Zoek @@ -587,8 +623,10 @@ commits.newer=Nieuwer commits.signed_by=Getekend door commits.gpg_key_id=GPG sleutel-ID +ext_issues=Ext. issues issues.new=Nieuw probleem +issues.new.title_empty=Titel kan niet leeg zijn issues.new.labels=Labels issues.new.no_label=Geen label issues.new.clear_labels=Verwijder labels @@ -612,6 +650,7 @@ issues.label_templates.use=Label Set gebruiken issues.change_milestone_at='mijlpaal bewerkt van %s %s %s' issues.remove_milestone_at=' %s is verwijderd uit de %s mijlpaal' issues.deleted_milestone=` (verwijderd)` +issues.self_assign_at=`heeft dit %s aan zichzelf toegewezen` issues.add_assignee_at=`was toegekend door %s %s` issues.change_title_at='titel aangepast van %s naar %s %s' issues.open_tab=%d Open @@ -646,6 +685,7 @@ issues.action_milestone_no_select=Geen mijlpaal issues.action_assignee=Toegewezene issues.action_assignee_no_select=Geen verantwoordelijke issues.opened_by=%[1]s werd geopend door %[3]s +pulls.merged_by_fake=samengevoegd %[1]s door %[2]s issues.opened_by_fake=%[1]s werd geopend door %[2]s issues.previous=Vorige issues.next=Volgende @@ -666,6 +706,7 @@ issues.commit_ref_at=`verwees naar dit probleem vanuit commit Log in om deel te nemen aan deze discussie. issues.edit=Bewerken issues.cancel=Annuleren issues.save=Opslaan @@ -678,6 +719,7 @@ issues.label_edit=Bewerken issues.label_delete=Verwijder issues.label_modify=Label bewerken issues.label_deletion=Verwijder label +issues.label_deletion_desc=Als je een label verwijdert, wordt hij van alle issues verwijderd. Doorgaan? issues.label_deletion_success=Het label is verwijderd. issues.label.filter_sort.alphabetically=Alfabetisch issues.label.filter_sort.reverse_alphabetically=Omgekeerd alfabetisch @@ -688,6 +730,11 @@ issues.attachment.open_tab=`Klik om "%s" in een nieuw tabblad te bekijken` issues.attachment.download=`Klik om "%s" te downloaden` issues.subscribe=Abonneren issues.unsubscribe=Uitschrijven +issues.lock=Gesprek vergrendelen +issues.lock_confirm=Vergrendel +issues.unlock_confirm=Ontgrendelen +issues.lock.reason=Reden voor vergrendeling +issues.comment_on_locked=Je kunt geen commentaar geven op een vergrendeld probleem. issues.tracker=Tijdregistratie issues.start_tracking_short=Start issues.start_tracking=Start tijdregistratie @@ -701,18 +748,25 @@ issues.add_time_cancel=Annuleren issues.add_time_history=`heeft besteedde tijd toegevoegd: %s` issues.add_time_hours=Uren issues.add_time_minutes=Minuten +issues.add_time_sum_to_small=Geen tijd opgegeven. issues.cancel_tracking=Annuleren issues.cancel_tracking_history=`tijd bijhouden geannuleerd: %s` issues.time_spent_total=Totaal besteedde tijd issues.time_spent_from_all_authors=`Totaal besteedde tijd: %s` issues.due_date=Vervaldatum +issues.error_modifying_due_date=Deadline aanpassen mislukt. +issues.error_removing_due_date=Deadline verwijderen mislukt. issues.due_date_form=jjjj-mm-dd issues.due_date_form_add=Vervaldatum toevoegen issues.due_date_form_edit=Bewerk issues.due_date_form_remove=Verwijder +issues.due_date_not_writer=Je hebt schrijftoegang in deze repository nodig om de deadline van een kwestie aan te passen. issues.due_date_not_set=Geen vervaldatum ingesteld. issues.due_date_overdue=Over tijd +issues.due_date_invalid=De deadline is ongeldig of buiten bereik. Gebruik het formaat 'jjjj-mm-dd'. issues.dependency.title=Afhankelijkheden +issues.dependency.issue_no_dependencies=Deze kwestie heeft momenteel geen afhankelijkheden. +issues.dependency.add=Voeg afhankelijkheid toe… issues.dependency.cancel=Annuleer issues.dependency.remove=Verwijder issues.dependency.remove_info=Verwijder afhankelijkheid @@ -756,18 +810,27 @@ milestones.title=Titel milestones.desc=Beschrijving milestones.due_date=Vervaldatum (optioneel) milestones.clear=Leegmaken +milestones.create_success=De mijlpaal '%s' is aangemaakt. milestones.edit=Bewerk mijlpaal milestones.cancel=Annuleer +milestones.modify=Mijlpaal bijwerken +milestones.edit_success=Mijlpaal '%s' is bijgewerkt. milestones.deletion=Mijlpaal verwijderen +milestones.deletion_desc=Als je een mijlpaal verwijdert, wordt hij van alle gerelateerde kwesties verwijderd. Doorgaan? +milestones.deletion_success=De mijlpaal is verwijderd. +milestones.filter_sort.closest_due_date=Dichtstbijzijnde deadline +milestones.filter_sort.furthest_due_date=Verste deadline milestones.filter_sort.least_complete=Minst compleet milestones.filter_sort.most_complete=Meest compleet milestones.filter_sort.most_issues=Meeste problemen milestones.filter_sort.least_issues=Minste problemen ext_wiki=Ext. wiki +ext_wiki.desc=Koppelen aan een externe wiki. wiki=Wiki wiki.welcome=Welkom op de wiki. +wiki.create_first_page=Maak de eerste pagina wiki.page=Pagina wiki.filter_page=Filter pagina wiki.new_page=Pagina @@ -777,7 +840,9 @@ wiki.last_commit_info=%s heeft deze pagina aangepast %s wiki.edit_page_button=Bewerken wiki.new_page_button=Nieuwe pagina wiki.delete_page_button=Verwijder pagina +wiki.delete_page_notice_1=Het verwijderen van wiki-pagina '%s' kan niet ongedaan gemaakt worden. Doorgaan? wiki.page_already_exists=Er bestaat al een wiki-pagina met deze naam. +wiki.reserved_page=De wiki-paginanaam '%s' is gereserveerd. wiki.pages=Pagina’s wiki.last_updated=Laatst bijgewerkt: %s @@ -808,11 +873,15 @@ activity.closed_issue_label=Gesloten activity.new_issues_count_1=Nieuw probleem activity.new_issues_count_n=Nieuwe problemen activity.new_issue_label=Geopend +activity.title.unresolved_conv_1=%d open conversatie +activity.title.unresolved_conv_n=%d open conversaties activity.unresolved_conv_label=Open activity.title.releases_1=%d Release activity.title.releases_n=%d Releases activity.title.releases_published_by=%s gepubliceerd door %s activity.published_release_label=Gepubliceerd +activity.git_stats_files_changed_1=is veranderd +activity.git_stats_and_deletions=en search=Zoek search.search_repo=Zoek repository From 75d44143863e90a7aeff30a3f40128f144df94dd Mon Sep 17 00:00:00 2001 From: Christopher Thomas Date: Sun, 7 Jul 2019 03:57:53 +0200 Subject: [PATCH 195/220] Implement the ability to change the ssh port to match what is in the gitea config (#7286) * - rearrange the templates to make it more logical because now ssh_config is a template - implemented the updating of the port to the same as the port sent to the gitea config * change the filename back --- docker/root/etc/s6/openssh/setup | 7 +++++++ docker/root/etc/{ssh => templates}/sshd_config | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) rename docker/root/etc/{ssh => templates}/sshd_config (97%) diff --git a/docker/root/etc/s6/openssh/setup b/docker/root/etc/s6/openssh/setup index f8ef816a95..10d195b74f 100755 --- a/docker/root/etc/s6/openssh/setup +++ b/docker/root/etc/s6/openssh/setup @@ -24,6 +24,13 @@ if [ ! -f /data/ssh/ssh_host_ecdsa_key ]; then ssh-keygen -t ecdsa -b 256 -f /data/ssh/ssh_host_ecdsa_key -N "" > /dev/null fi +if [ -d /etc/ssh ]; then + SSH_PORT=${SSH_PORT:-"22"} \ + envsubst < /etc/templates/sshd_config > /etc/ssh/sshd_config + + chmod 0644 /etc/ssh/sshd_config +fi + chown root:root /data/ssh/* chmod 0700 /data/ssh chmod 0600 /data/ssh/* diff --git a/docker/root/etc/ssh/sshd_config b/docker/root/etc/templates/sshd_config similarity index 97% rename from docker/root/etc/ssh/sshd_config rename to docker/root/etc/templates/sshd_config index 6af082c419..ba92e236e1 100644 --- a/docker/root/etc/ssh/sshd_config +++ b/docker/root/etc/templates/sshd_config @@ -1,4 +1,4 @@ -Port 22 +Port ${SSH_PORT} Protocol 2 AddressFamily any From f369788347167a47a8fc162e086b92048ff0a43f Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 7 Jul 2019 04:25:05 +0200 Subject: [PATCH 196/220] Refactor filetype is not allowed errors (#7309) --- modules/upload/filetype.go | 49 +++++++++++++++++++++++ routers/api/v1/repo/release_attachment.go | 20 ++------- routers/repo/attachment.go | 19 ++------- routers/repo/editor.go | 17 ++------ routers/repo/issue.go | 2 - 5 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 modules/upload/filetype.go diff --git a/modules/upload/filetype.go b/modules/upload/filetype.go new file mode 100644 index 0000000000..1ec7324ed3 --- /dev/null +++ b/modules/upload/filetype.go @@ -0,0 +1,49 @@ +// Copyright 2019 The Gitea 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 upload + +import ( + "fmt" + "net/http" + "strings" + + "code.gitea.io/gitea/modules/log" +) + +// ErrFileTypeForbidden not allowed file type error +type ErrFileTypeForbidden struct { + Type string +} + +// IsErrFileTypeForbidden checks if an error is a ErrFileTypeForbidden. +func IsErrFileTypeForbidden(err error) bool { + _, ok := err.(ErrFileTypeForbidden) + return ok +} + +func (err ErrFileTypeForbidden) Error() string { + return fmt.Sprintf("File type is not allowed: %s", err.Type) +} + +// VerifyAllowedContentType validates a file is allowed to be uploaded. +func VerifyAllowedContentType(buf []byte, allowedTypes []string) error { + fileType := http.DetectContentType(buf) + + allowed := false + for _, t := range allowedTypes { + t := strings.Trim(t, " ") + if t == "*/*" || t == fileType { + allowed = true + break + } + } + + if !allowed { + log.Info("Attachment with type %s blocked from upload", fileType) + return ErrFileTypeForbidden{Type: fileType} + } + + return nil +} diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index f85787bc59..d0eb3d4ae1 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -5,13 +5,12 @@ package repo import ( - "errors" - "net/http" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/upload" api "code.gitea.io/gitea/modules/structs" ) @@ -177,20 +176,9 @@ func CreateReleaseAttachment(ctx *context.APIContext) { } // Check if the filetype is allowed by the settings - fileType := http.DetectContentType(buf) - - allowedTypes := strings.Split(setting.AttachmentAllowedTypes, ",") - allowed := false - for _, t := range allowedTypes { - t := strings.Trim(t, " ") - if t == "*/*" || t == fileType { - allowed = true - break - } - } - - if !allowed { - ctx.Error(400, "DetectContentType", errors.New("File type is not allowed")) + err = upload.VerifyAllowedContentType(buf, strings.Split(setting.AttachmentAllowedTypes, ",")) + if err != nil { + ctx.Error(400, "DetectContentType", err) return } diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 8913e63015..a07a2a8ace 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -6,13 +6,13 @@ package repo import ( "fmt" - "net/http" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/upload" ) func renderAttachmentSettings(ctx *context.Context) { @@ -42,21 +42,10 @@ func UploadAttachment(ctx *context.Context) { if n > 0 { buf = buf[:n] } - fileType := http.DetectContentType(buf) - allowedTypes := strings.Split(setting.AttachmentAllowedTypes, ",") - allowed := false - for _, t := range allowedTypes { - t := strings.Trim(t, " ") - if t == "*/*" || t == fileType { - allowed = true - break - } - } - - if !allowed { - log.Info("Attachment with type %s blocked from upload", fileType) - ctx.Error(400, ErrFileTypeForbidden.Error()) + err = upload.VerifyAllowedContentType(buf, strings.Split(setting.AttachmentAllowedTypes, ",")) + if err != nil { + ctx.Error(400, err.Error()) return } diff --git a/routers/repo/editor.go b/routers/repo/editor.go index 062ecfebf7..f3327017e5 100644 --- a/routers/repo/editor.go +++ b/routers/repo/editor.go @@ -7,7 +7,6 @@ package repo import ( "fmt" "io/ioutil" - "net/http" "path" "strings" @@ -20,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/repofiles" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" ) @@ -594,20 +594,11 @@ func UploadFileToServer(ctx *context.Context) { if n > 0 { buf = buf[:n] } - fileType := http.DetectContentType(buf) if len(setting.Repository.Upload.AllowedTypes) > 0 { - allowed := false - for _, t := range setting.Repository.Upload.AllowedTypes { - t := strings.Trim(t, " ") - if t == "*/*" || t == fileType { - allowed = true - break - } - } - - if !allowed { - ctx.Error(400, ErrFileTypeForbidden.Error()) + err = upload.VerifyAllowedContentType(buf, setting.Repository.Upload.AllowedTypes) + if err != nil { + ctx.Error(400, err.Error()) return } } diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 3904d29532..72e0357e6c 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -41,8 +41,6 @@ const ( ) var ( - // ErrFileTypeForbidden not allowed file type error - ErrFileTypeForbidden = errors.New("File type is not allowed") // ErrTooManyFiles upload too many files ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded") // IssueTemplateCandidates issue templates From 87404d7c0b0ff42be73398c86f5356959dc7b632 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 7 Jul 2019 11:00:41 +0800 Subject: [PATCH 197/220] Use vendors when go generate (#7340) * use vendors when go generate * update docs about golang minimal requirement from 1.9 to 1.11 * fix build --- .drone.yml | 6 ++++-- Makefile | 2 +- docs/content/doc/advanced/hacking-on-gitea.en-us.md | 2 +- docs/content/doc/installation/from-source.en-us.md | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.drone.yml b/.drone.yml index 9c07599940..086b5cd2b5 100644 --- a/.drone.yml +++ b/.drone.yml @@ -63,9 +63,11 @@ steps: - name: build-without-gcc pull: always - image: golang:1.10 # this step is kept as the lowest version of golang that we support + image: golang:1.11 # this step is kept as the lowest version of golang that we support + environment: + GO111MODULE: on commands: - - go build -o gitea_no_gcc # test if build succeeds without the sqlite tag + - go build -mod=vendor -o gitea_no_gcc # test if build succeeds without the sqlite tag - name: build pull: always diff --git a/Makefile b/Makefile index 796a0e3b53..2c6a6ef72e 100644 --- a/Makefile +++ b/Makefile @@ -97,7 +97,7 @@ vet: .PHONY: generate generate: - GO111MODULE=on $(GO) generate $(PACKAGES) + GO111MODULE=on $(GO) generate -mod=vendor $(PACKAGES) .PHONY: generate-swagger generate-swagger: diff --git a/docs/content/doc/advanced/hacking-on-gitea.en-us.md b/docs/content/doc/advanced/hacking-on-gitea.en-us.md index d04cdfca5b..ef29051e7e 100644 --- a/docs/content/doc/advanced/hacking-on-gitea.en-us.md +++ b/docs/content/doc/advanced/hacking-on-gitea.en-us.md @@ -32,7 +32,7 @@ necessary. To be able to use these you must have the `"$GOPATH"/bin` directory on the executable path. If you don't add the go bin directory to the executable path you will have to manage this yourself. -**Note 2**: Go version 1.9 or higher is required; however, it is important +**Note 2**: Go version 1.11 or higher is required; however, it is important to note that our continuous integration will check that the formatting of the source code is not changed by `gofmt` using `make fmt-check`. Unfortunately, the results of `gofmt` can differ by the version of `go`. It is therefore diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md index ce5915cc3f..cf6d42802e 100644 --- a/docs/content/doc/installation/from-source.en-us.md +++ b/docs/content/doc/installation/from-source.en-us.md @@ -27,7 +27,7 @@ necessary. To be able to use these, you must have the `"$GOPATH/bin"` directory on the executable path. If you don't add the go bin directory to the executable path, you will have to manage this yourself. -**Note 2**: Go version 1.9 or higher is required. However, it is recommended to +**Note 2**: Go version 1.11 or higher is required. However, it is recommended to obtain the same version as our continuous integration, see the advice given in Hacking on Gitea From ed676f91b31f54d02bf096d4830483a96e1fd309 Mon Sep 17 00:00:00 2001 From: Cherrg Date: Sun, 7 Jul 2019 05:53:02 +0200 Subject: [PATCH 198/220] dark theme scrollbars (#7269) --- public/css/theme-arc-green.css | 6 ++++++ public/less/themes/arc-green.less | 36 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index b48e22b41e..a3a7204009 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -12,6 +12,12 @@ .repository .ui.segment.sub-menu .list .item a{color:#dbdbdb} .ui.horizontal.segments>.segment{background-color:#383c4a} body{background:#383c4a;color:#9e9e9e} +*{scrollbar-width:thin;scrollbar-color:#87ab63 rgba(255,255,255,.1)} +::-webkit-scrollbar{-webkit-appearance:none!important;width:10px!important;height:10px!important} +::-webkit-scrollbar-track{border-radius:0!important;background:rgba(255,255,255,.1)!important} +::-webkit-scrollbar-thumb{cursor:pointer!important;border-radius:5px!important;transition:color .2s ease!important;background:#87ab63!important} +::-webkit-scrollbar-thumb:window-inactive{background:#87ab63!important} +::-webkit-scrollbar-thumb:hover{background:#87ab63!important} a{color:#87ab63} a:hover{color:#a0cc75} .ui.card>.extra a:not(.ui):hover,.ui.cards>.card>.extra a:not(.ui):hover{color:#a0cc75} diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index cde5b5e7f5..ebe63c65fa 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -85,6 +85,42 @@ body { color: #9e9e9e; } +/* firefox scroll bars */ + +* { + scrollbar-width: thin; + scrollbar-color: #87ab63 rgba(255, 255, 255, 0.1); +} + +/* webkit scrollbars */ + +::-webkit-scrollbar { + -webkit-appearance: none !important; + width: 10px !important; + height: 10px !important; +} + +::-webkit-scrollbar-track { + border-radius: 0 !important; + background: rgba(255, 255, 255, 0.1) !important; +} + +::-webkit-scrollbar-thumb { + cursor: pointer !important; + border-radius: 5px !important; + -webkit-transition: color 0.2s ease !important; + transition: color 0.2s ease !important; + background: #87ab63 !important; +} + +::-webkit-scrollbar-thumb:window-inactive { + background: #87ab63 !important; +} + +::-webkit-scrollbar-thumb:hover { + background: #87ab63 !important; +} + a { color: #87ab63; } From 1b85b248e42a9d45d4dc278d399ddab3edcedfdb Mon Sep 17 00:00:00 2001 From: Cherrg Date: Sun, 7 Jul 2019 06:22:04 +0200 Subject: [PATCH 199/220] wiki - editor - add buttons 'inline code', 'empty checkbox', 'checked checkbox' (#7243) * wiki - editor - add buttons 'inline code', 'add empty checkbox', 'add checked checkbox' affects #5436 Signed-off-by: Michael Gnehr * add missing 'set focus' after insert with buttons Signed-off-by: Michael Gnehr * consistent usage of let/const in added code --- public/js/index.js | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index 22e4f9d419..ef8a1093ad 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1158,7 +1158,40 @@ function initWikiForm() { spellChecker: false, toolbar: ["bold", "italic", "strikethrough", "|", "heading-1", "heading-2", "heading-3", "heading-bigger", "heading-smaller", "|", - "code", "quote", "|", + { + name: "code-inline", + action: function(e){ + let cm = e.codemirror; + let selection = cm.getSelection(); + cm.replaceSelection("`" + selection + "`"); + if (!selection) { + let cursorPos = cm.getCursor(); + cm.setCursor(cursorPos.line, cursorPos.ch - 1); + } + cm.focus(); + }, + className: "fa fa-angle-right", + title: "Add Inline Code", + },"code", "quote", "|", { + name: "checkbox-empty", + action: function(e){ + let cm = e.codemirror; + cm.replaceSelection("\n- [ ] " + cm.getSelection()); + cm.focus(); + }, + className: "fa fa-square-o", + title: "Add Checkbox (empty)", + }, + { + name: "checkbox-checked", + action: function(e){ + let cm = e.codemirror; + cm.replaceSelection("\n- [x] " + cm.getSelection()); + cm.focus(); + }, + className: "fa fa-check-square-o", + title: "Add Checkbox (checked)", + }, "|", "unordered-list", "ordered-list", "|", "link", "image", "table", "horizontal-rule", "|", "clean-block", "preview", "fullscreen"] From 8d9d6aa903baf3662fa31bceb489291564a873d1 Mon Sep 17 00:00:00 2001 From: EpicCoder Date: Sun, 7 Jul 2019 08:01:01 +0200 Subject: [PATCH 200/220] Add additional password hash algorithms (closes #5859) (#6023) --- custom/conf/app.ini.sample | 2 + .../doc/advanced/config-cheat-sheet.en-us.md | 1 + models/login_source.go | 10 + models/user.go | 48 +- models/user_test.go | 32 +- modules/setting/setting.go | 2 + vendor/golang.org/x/crypto/argon2/argon2.go | 285 +++++++ vendor/golang.org/x/crypto/argon2/blake2b.go | 53 ++ .../x/crypto/argon2/blamka_amd64.go | 60 ++ .../golang.org/x/crypto/argon2/blamka_amd64.s | 243 ++++++ .../x/crypto/argon2/blamka_generic.go | 163 ++++ .../golang.org/x/crypto/argon2/blamka_ref.go | 15 + vendor/golang.org/x/crypto/blake2b/blake2b.go | 289 +++++++ .../x/crypto/blake2b/blake2bAVX2_amd64.go | 37 + .../x/crypto/blake2b/blake2bAVX2_amd64.s | 750 ++++++++++++++++++ .../x/crypto/blake2b/blake2b_amd64.go | 24 + .../x/crypto/blake2b/blake2b_amd64.s | 281 +++++++ .../x/crypto/blake2b/blake2b_generic.go | 182 +++++ .../x/crypto/blake2b/blake2b_ref.go | 11 + vendor/golang.org/x/crypto/blake2b/blake2x.go | 177 +++++ .../golang.org/x/crypto/blake2b/register.go | 32 + vendor/golang.org/x/crypto/scrypt/scrypt.go | 213 +++++ vendor/modules.txt | 5 +- 23 files changed, 2895 insertions(+), 20 deletions(-) create mode 100644 vendor/golang.org/x/crypto/argon2/argon2.go create mode 100644 vendor/golang.org/x/crypto/argon2/blake2b.go create mode 100644 vendor/golang.org/x/crypto/argon2/blamka_amd64.go create mode 100644 vendor/golang.org/x/crypto/argon2/blamka_amd64.s create mode 100644 vendor/golang.org/x/crypto/argon2/blamka_generic.go create mode 100644 vendor/golang.org/x/crypto/argon2/blamka_ref.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b_generic.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b_ref.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2x.go create mode 100644 vendor/golang.org/x/crypto/blake2b/register.go create mode 100644 vendor/golang.org/x/crypto/scrypt/scrypt.go diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index a674984a25..89c12c42bf 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -319,6 +319,8 @@ MIN_PASSWORD_LENGTH = 6 IMPORT_LOCAL_PATHS = false ; Set to true to prevent all users (including admin) from creating custom git hooks DISABLE_GIT_HOOKS = false +; Password Hash algorithm, either "pbkdf2", "argon2", "scrypt" or "bcrypt" +PASSWORD_HASH_ALGO = pbkdf2 [openid] ; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 11dbfc5d09..128e01b90a 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -197,6 +197,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server. - `INTERNAL_TOKEN`: **\**: Secret used to validate communication within Gitea binary. - `INTERNAL_TOKEN_URI`: ****: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`) +- `PASSWORD_HASH_ALGO`: **pbkdf2**: The hash algorithm to use \[pbkdf2, argon2, scrypt, bcrypt\]. ## OpenID (`openid`) diff --git a/models/login_source.go b/models/login_source.go index 626c232772..26544588c1 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/auth/oauth2" "code.gitea.io/gitea/modules/auth/pam" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -665,6 +666,15 @@ func UserSignIn(username, password string) (*User, error) { switch user.LoginType { case LoginNoType, LoginPlain, LoginOAuth2: if user.IsPasswordSet() && user.ValidatePassword(password) { + + // Update password hash if server password hash algorithm have changed + if user.PasswdHashAlgo != setting.PasswordHashAlgo { + user.HashPassword(password) + if err := UpdateUserCols(user, "passwd", "passwd_hash_algo"); err != nil { + return nil, err + } + } + // WARN: DON'T check user.IsActive, that will be checked on reqSign so that // user could be hint to resend confirm email. if user.ProhibitLogin { diff --git a/models/user.go b/models/user.go index aa392b1ea9..fc0dfee187 100644 --- a/models/user.go +++ b/models/user.go @@ -33,7 +33,10 @@ import ( "github.com/Unknwon/com" "github.com/go-xorm/xorm" + "golang.org/x/crypto/argon2" + "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/pbkdf2" + "golang.org/x/crypto/scrypt" "golang.org/x/crypto/ssh" "xorm.io/builder" "xorm.io/core" @@ -50,6 +53,13 @@ const ( UserTypeOrganization ) +const ( + algoBcrypt = "bcrypt" + algoScrypt = "scrypt" + algoArgon2 = "argon2" + algoPbkdf2 = "pbkdf2" +) + const syncExternalUsers = "sync_external_users" var ( @@ -82,6 +92,7 @@ type User struct { Email string `xorm:"NOT NULL"` KeepEmailPrivate bool Passwd string `xorm:"NOT NULL"` + PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'pbkdf2'"` // MustChangePassword is an attribute that determines if a user // is to change his/her password after registration. @@ -430,25 +441,48 @@ func (u *User) NewGitSig() *git.Signature { } } -func hashPassword(passwd, salt string) string { - tempPasswd := pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New) +func hashPassword(passwd, salt, algo string) string { + var tempPasswd []byte + + switch algo { + case algoBcrypt: + tempPasswd, _ = bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost) + return string(tempPasswd) + case algoScrypt: + tempPasswd, _ = scrypt.Key([]byte(passwd), []byte(salt), 65536, 16, 2, 50) + case algoArgon2: + tempPasswd = argon2.IDKey([]byte(passwd), []byte(salt), 2, 65536, 8, 50) + case algoPbkdf2: + fallthrough + default: + tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New) + } + return fmt.Sprintf("%x", tempPasswd) } -// HashPassword hashes a password using PBKDF. +// HashPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO. func (u *User) HashPassword(passwd string) { - u.Passwd = hashPassword(passwd, u.Salt) + u.PasswdHashAlgo = setting.PasswordHashAlgo + u.Passwd = hashPassword(passwd, u.Salt, setting.PasswordHashAlgo) } // ValidatePassword checks if given password matches the one belongs to the user. func (u *User) ValidatePassword(passwd string) bool { - tempHash := hashPassword(passwd, u.Salt) - return subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1 + tempHash := hashPassword(passwd, u.Salt, u.PasswdHashAlgo) + + if u.PasswdHashAlgo != algoBcrypt && subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1 { + return true + } + if u.PasswdHashAlgo == algoBcrypt && bcrypt.CompareHashAndPassword([]byte(u.Passwd), []byte(passwd)) == nil { + return true + } + return false } // IsPasswordSet checks if the password is set or left empty func (u *User) IsPasswordSet() bool { - return !u.ValidatePassword("") + return len(u.Passwd) > 0 } // UploadAvatar saves custom avatar for user. diff --git a/models/user_test.go b/models/user_test.go index 6af9752c9b..10420a143f 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -147,21 +147,29 @@ func TestHashPasswordDeterministic(t *testing.T) { b := make([]byte, 16) rand.Read(b) u := &User{Salt: string(b)} - for i := 0; i < 50; i++ { - // generate a random password - rand.Read(b) - pass := string(b) + algos := []string{"pbkdf2", "argon2", "scrypt", "bcrypt"} + for j := 0; j < len(algos); j++ { + u.PasswdHashAlgo = algos[j] + for i := 0; i < 50; i++ { + // generate a random password + rand.Read(b) + pass := string(b) - // save the current password in the user - hash it and store the result - u.HashPassword(pass) - r1 := u.Passwd + // save the current password in the user - hash it and store the result + u.HashPassword(pass) + r1 := u.Passwd - // run again - u.HashPassword(pass) - r2 := u.Passwd + // run again + u.HashPassword(pass) + r2 := u.Passwd - // assert equal (given the same salt+pass, the same result is produced) - assert.Equal(t, r1, r2) + // assert equal (given the same salt+pass, the same result is produced) except bcrypt + if u.PasswdHashAlgo == "bcrypt" { + assert.NotEqual(t, r1, r2) + } else { + assert.Equal(t, r1, r2) + } + } } } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 43a61aa7fa..7201f0619d 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -154,6 +154,7 @@ var ( MinPasswordLength int ImportLocalPaths bool DisableGitHooks bool + PasswordHashAlgo string // Database settings UseSQLite3 bool @@ -779,6 +780,7 @@ func NewContext() { MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6) ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(false) + PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2") InternalToken = loadInternalToken(sec) IterateBufferSize = Cfg.Section("database").Key("ITERATE_BUFFER_SIZE").MustInt(50) LogSQL = Cfg.Section("database").Key("LOG_SQL").MustBool(true) diff --git a/vendor/golang.org/x/crypto/argon2/argon2.go b/vendor/golang.org/x/crypto/argon2/argon2.go new file mode 100644 index 0000000000..b423feaea9 --- /dev/null +++ b/vendor/golang.org/x/crypto/argon2/argon2.go @@ -0,0 +1,285 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package argon2 implements the key derivation function Argon2. +// Argon2 was selected as the winner of the Password Hashing Competition and can +// be used to derive cryptographic keys from passwords. +// +// For a detailed specification of Argon2 see [1]. +// +// If you aren't sure which function you need, use Argon2id (IDKey) and +// the parameter recommendations for your scenario. +// +// +// Argon2i +// +// Argon2i (implemented by Key) is the side-channel resistant version of Argon2. +// It uses data-independent memory access, which is preferred for password +// hashing and password-based key derivation. Argon2i requires more passes over +// memory than Argon2id to protect from trade-off attacks. The recommended +// parameters (taken from [2]) for non-interactive operations are time=3 and to +// use the maximum available memory. +// +// +// Argon2id +// +// Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining +// Argon2i and Argon2d. It uses data-independent memory access for the first +// half of the first iteration over the memory and data-dependent memory access +// for the rest. Argon2id is side-channel resistant and provides better brute- +// force cost savings due to time-memory tradeoffs than Argon2i. The recommended +// parameters for non-interactive operations (taken from [2]) are time=1 and to +// use the maximum available memory. +// +// [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf +// [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3 +package argon2 + +import ( + "encoding/binary" + "sync" + + "golang.org/x/crypto/blake2b" +) + +// The Argon2 version implemented by this package. +const Version = 0x13 + +const ( + argon2d = iota + argon2i + argon2id +) + +// Key derives a key from the password, salt, and cost parameters using Argon2i +// returning a byte slice of length keyLen that can be used as cryptographic +// key. The CPU cost and parallelism degree must be greater than zero. +// +// For example, you can get a derived key for e.g. AES-256 (which needs a +// 32-byte key) by doing: +// +// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32) +// +// The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number. +// If using that amount of memory (32 MB) is not possible in some contexts then +// the time parameter can be increased to compensate. +// +// The time parameter specifies the number of passes over the memory and the +// memory parameter specifies the size of the memory in KiB. For example +// memory=32*1024 sets the memory cost to ~32 MB. The number of threads can be +// adjusted to the number of available CPUs. The cost parameters should be +// increased as memory latency and CPU parallelism increases. Remember to get a +// good random salt. +func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte { + return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen) +} + +// IDKey derives a key from the password, salt, and cost parameters using +// Argon2id returning a byte slice of length keyLen that can be used as +// cryptographic key. The CPU cost and parallelism degree must be greater than +// zero. +// +// For example, you can get a derived key for e.g. AES-256 (which needs a +// 32-byte key) by doing: +// +// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32) +// +// The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number. +// If using that amount of memory (64 MB) is not possible in some contexts then +// the time parameter can be increased to compensate. +// +// The time parameter specifies the number of passes over the memory and the +// memory parameter specifies the size of the memory in KiB. For example +// memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be +// adjusted to the numbers of available CPUs. The cost parameters should be +// increased as memory latency and CPU parallelism increases. Remember to get a +// good random salt. +func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte { + return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen) +} + +func deriveKey(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []byte { + if time < 1 { + panic("argon2: number of rounds too small") + } + if threads < 1 { + panic("argon2: parallelism degree too low") + } + h0 := initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode) + + memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads)) + if memory < 2*syncPoints*uint32(threads) { + memory = 2 * syncPoints * uint32(threads) + } + B := initBlocks(&h0, memory, uint32(threads)) + processBlocks(B, time, memory, uint32(threads), mode) + return extractKey(B, memory, uint32(threads), keyLen) +} + +const ( + blockLength = 128 + syncPoints = 4 +) + +type block [blockLength]uint64 + +func initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte { + var ( + h0 [blake2b.Size + 8]byte + params [24]byte + tmp [4]byte + ) + + b2, _ := blake2b.New512(nil) + binary.LittleEndian.PutUint32(params[0:4], threads) + binary.LittleEndian.PutUint32(params[4:8], keyLen) + binary.LittleEndian.PutUint32(params[8:12], memory) + binary.LittleEndian.PutUint32(params[12:16], time) + binary.LittleEndian.PutUint32(params[16:20], uint32(Version)) + binary.LittleEndian.PutUint32(params[20:24], uint32(mode)) + b2.Write(params[:]) + binary.LittleEndian.PutUint32(tmp[:], uint32(len(password))) + b2.Write(tmp[:]) + b2.Write(password) + binary.LittleEndian.PutUint32(tmp[:], uint32(len(salt))) + b2.Write(tmp[:]) + b2.Write(salt) + binary.LittleEndian.PutUint32(tmp[:], uint32(len(key))) + b2.Write(tmp[:]) + b2.Write(key) + binary.LittleEndian.PutUint32(tmp[:], uint32(len(data))) + b2.Write(tmp[:]) + b2.Write(data) + b2.Sum(h0[:0]) + return h0 +} + +func initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []block { + var block0 [1024]byte + B := make([]block, memory) + for lane := uint32(0); lane < threads; lane++ { + j := lane * (memory / threads) + binary.LittleEndian.PutUint32(h0[blake2b.Size+4:], lane) + + binary.LittleEndian.PutUint32(h0[blake2b.Size:], 0) + blake2bHash(block0[:], h0[:]) + for i := range B[j+0] { + B[j+0][i] = binary.LittleEndian.Uint64(block0[i*8:]) + } + + binary.LittleEndian.PutUint32(h0[blake2b.Size:], 1) + blake2bHash(block0[:], h0[:]) + for i := range B[j+1] { + B[j+1][i] = binary.LittleEndian.Uint64(block0[i*8:]) + } + } + return B +} + +func processBlocks(B []block, time, memory, threads uint32, mode int) { + lanes := memory / threads + segments := lanes / syncPoints + + processSegment := func(n, slice, lane uint32, wg *sync.WaitGroup) { + var addresses, in, zero block + if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) { + in[0] = uint64(n) + in[1] = uint64(lane) + in[2] = uint64(slice) + in[3] = uint64(memory) + in[4] = uint64(time) + in[5] = uint64(mode) + } + + index := uint32(0) + if n == 0 && slice == 0 { + index = 2 // we have already generated the first two blocks + if mode == argon2i || mode == argon2id { + in[6]++ + processBlock(&addresses, &in, &zero) + processBlock(&addresses, &addresses, &zero) + } + } + + offset := lane*lanes + slice*segments + index + var random uint64 + for index < segments { + prev := offset - 1 + if index == 0 && slice == 0 { + prev += lanes // last block in lane + } + if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) { + if index%blockLength == 0 { + in[6]++ + processBlock(&addresses, &in, &zero) + processBlock(&addresses, &addresses, &zero) + } + random = addresses[index%blockLength] + } else { + random = B[prev][0] + } + newOffset := indexAlpha(random, lanes, segments, threads, n, slice, lane, index) + processBlockXOR(&B[offset], &B[prev], &B[newOffset]) + index, offset = index+1, offset+1 + } + wg.Done() + } + + for n := uint32(0); n < time; n++ { + for slice := uint32(0); slice < syncPoints; slice++ { + var wg sync.WaitGroup + for lane := uint32(0); lane < threads; lane++ { + wg.Add(1) + go processSegment(n, slice, lane, &wg) + } + wg.Wait() + } + } + +} + +func extractKey(B []block, memory, threads, keyLen uint32) []byte { + lanes := memory / threads + for lane := uint32(0); lane < threads-1; lane++ { + for i, v := range B[(lane*lanes)+lanes-1] { + B[memory-1][i] ^= v + } + } + + var block [1024]byte + for i, v := range B[memory-1] { + binary.LittleEndian.PutUint64(block[i*8:], v) + } + key := make([]byte, keyLen) + blake2bHash(key, block[:]) + return key +} + +func indexAlpha(rand uint64, lanes, segments, threads, n, slice, lane, index uint32) uint32 { + refLane := uint32(rand>>32) % threads + if n == 0 && slice == 0 { + refLane = lane + } + m, s := 3*segments, ((slice+1)%syncPoints)*segments + if lane == refLane { + m += index + } + if n == 0 { + m, s = slice*segments, 0 + if slice == 0 || lane == refLane { + m += index + } + } + if index == 0 || lane == refLane { + m-- + } + return phi(rand, uint64(m), uint64(s), refLane, lanes) +} + +func phi(rand, m, s uint64, lane, lanes uint32) uint32 { + p := rand & 0xFFFFFFFF + p = (p * p) >> 32 + p = (p * m) >> 32 + return lane*lanes + uint32((s+m-(p+1))%uint64(lanes)) +} diff --git a/vendor/golang.org/x/crypto/argon2/blake2b.go b/vendor/golang.org/x/crypto/argon2/blake2b.go new file mode 100644 index 0000000000..10f46948dc --- /dev/null +++ b/vendor/golang.org/x/crypto/argon2/blake2b.go @@ -0,0 +1,53 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package argon2 + +import ( + "encoding/binary" + "hash" + + "golang.org/x/crypto/blake2b" +) + +// blake2bHash computes an arbitrary long hash value of in +// and writes the hash to out. +func blake2bHash(out []byte, in []byte) { + var b2 hash.Hash + if n := len(out); n < blake2b.Size { + b2, _ = blake2b.New(n, nil) + } else { + b2, _ = blake2b.New512(nil) + } + + var buffer [blake2b.Size]byte + binary.LittleEndian.PutUint32(buffer[:4], uint32(len(out))) + b2.Write(buffer[:4]) + b2.Write(in) + + if len(out) <= blake2b.Size { + b2.Sum(out[:0]) + return + } + + outLen := len(out) + b2.Sum(buffer[:0]) + b2.Reset() + copy(out, buffer[:32]) + out = out[32:] + for len(out) > blake2b.Size { + b2.Write(buffer[:]) + b2.Sum(buffer[:0]) + copy(out, buffer[:32]) + out = out[32:] + b2.Reset() + } + + if outLen%blake2b.Size > 0 { // outLen > 64 + r := ((outLen + 31) / 32) - 2 // ⌈τ /32⌉-2 + b2, _ = blake2b.New(outLen-32*r, nil) + } + b2.Write(buffer[:]) + b2.Sum(out[:0]) +} diff --git a/vendor/golang.org/x/crypto/argon2/blamka_amd64.go b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go new file mode 100644 index 0000000000..2fc1ec0312 --- /dev/null +++ b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go @@ -0,0 +1,60 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +package argon2 + +import "golang.org/x/sys/cpu" + +func init() { + useSSE4 = cpu.X86.HasSSE41 +} + +//go:noescape +func mixBlocksSSE2(out, a, b, c *block) + +//go:noescape +func xorBlocksSSE2(out, a, b, c *block) + +//go:noescape +func blamkaSSE4(b *block) + +func processBlockSSE(out, in1, in2 *block, xor bool) { + var t block + mixBlocksSSE2(&t, in1, in2, &t) + if useSSE4 { + blamkaSSE4(&t) + } else { + for i := 0; i < blockLength; i += 16 { + blamkaGeneric( + &t[i+0], &t[i+1], &t[i+2], &t[i+3], + &t[i+4], &t[i+5], &t[i+6], &t[i+7], + &t[i+8], &t[i+9], &t[i+10], &t[i+11], + &t[i+12], &t[i+13], &t[i+14], &t[i+15], + ) + } + for i := 0; i < blockLength/8; i += 2 { + blamkaGeneric( + &t[i], &t[i+1], &t[16+i], &t[16+i+1], + &t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1], + &t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1], + &t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1], + ) + } + } + if xor { + xorBlocksSSE2(out, in1, in2, &t) + } else { + mixBlocksSSE2(out, in1, in2, &t) + } +} + +func processBlock(out, in1, in2 *block) { + processBlockSSE(out, in1, in2, false) +} + +func processBlockXOR(out, in1, in2 *block) { + processBlockSSE(out, in1, in2, true) +} diff --git a/vendor/golang.org/x/crypto/argon2/blamka_amd64.s b/vendor/golang.org/x/crypto/argon2/blamka_amd64.s new file mode 100644 index 0000000000..74a6e7332a --- /dev/null +++ b/vendor/golang.org/x/crypto/argon2/blamka_amd64.s @@ -0,0 +1,243 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA ·c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·c40<>(SB), (NOPTR+RODATA), $16 + +DATA ·c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·c48<>(SB), (NOPTR+RODATA), $16 + +#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v6, t1; \ + PUNPCKLQDQ v6, t2; \ + PUNPCKHQDQ v7, v6; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ v7, t2; \ + MOVO t1, v7; \ + MOVO v2, t1; \ + PUNPCKHQDQ t2, v7; \ + PUNPCKLQDQ v3, t2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v3 + +#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v2, t1; \ + PUNPCKLQDQ v2, t2; \ + PUNPCKHQDQ v3, v2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ v3, t2; \ + MOVO t1, v3; \ + MOVO v6, t1; \ + PUNPCKHQDQ t2, v3; \ + PUNPCKLQDQ v7, t2; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v7 + +#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, t0, c40, c48) \ + MOVO v0, t0; \ + PMULULQ v2, t0; \ + PADDQ v2, v0; \ + PADDQ t0, v0; \ + PADDQ t0, v0; \ + PXOR v0, v6; \ + PSHUFD $0xB1, v6, v6; \ + MOVO v4, t0; \ + PMULULQ v6, t0; \ + PADDQ v6, v4; \ + PADDQ t0, v4; \ + PADDQ t0, v4; \ + PXOR v4, v2; \ + PSHUFB c40, v2; \ + MOVO v0, t0; \ + PMULULQ v2, t0; \ + PADDQ v2, v0; \ + PADDQ t0, v0; \ + PADDQ t0, v0; \ + PXOR v0, v6; \ + PSHUFB c48, v6; \ + MOVO v4, t0; \ + PMULULQ v6, t0; \ + PADDQ v6, v4; \ + PADDQ t0, v4; \ + PADDQ t0, v4; \ + PXOR v4, v2; \ + MOVO v2, t0; \ + PADDQ v2, t0; \ + PSRLQ $63, v2; \ + PXOR t0, v2; \ + MOVO v1, t0; \ + PMULULQ v3, t0; \ + PADDQ v3, v1; \ + PADDQ t0, v1; \ + PADDQ t0, v1; \ + PXOR v1, v7; \ + PSHUFD $0xB1, v7, v7; \ + MOVO v5, t0; \ + PMULULQ v7, t0; \ + PADDQ v7, v5; \ + PADDQ t0, v5; \ + PADDQ t0, v5; \ + PXOR v5, v3; \ + PSHUFB c40, v3; \ + MOVO v1, t0; \ + PMULULQ v3, t0; \ + PADDQ v3, v1; \ + PADDQ t0, v1; \ + PADDQ t0, v1; \ + PXOR v1, v7; \ + PSHUFB c48, v7; \ + MOVO v5, t0; \ + PMULULQ v7, t0; \ + PADDQ v7, v5; \ + PADDQ t0, v5; \ + PADDQ t0, v5; \ + PXOR v5, v3; \ + MOVO v3, t0; \ + PADDQ v3, t0; \ + PSRLQ $63, v3; \ + PXOR t0, v3 + +#define LOAD_MSG_0(block, off) \ + MOVOU 8*(off+0)(block), X0; \ + MOVOU 8*(off+2)(block), X1; \ + MOVOU 8*(off+4)(block), X2; \ + MOVOU 8*(off+6)(block), X3; \ + MOVOU 8*(off+8)(block), X4; \ + MOVOU 8*(off+10)(block), X5; \ + MOVOU 8*(off+12)(block), X6; \ + MOVOU 8*(off+14)(block), X7 + +#define STORE_MSG_0(block, off) \ + MOVOU X0, 8*(off+0)(block); \ + MOVOU X1, 8*(off+2)(block); \ + MOVOU X2, 8*(off+4)(block); \ + MOVOU X3, 8*(off+6)(block); \ + MOVOU X4, 8*(off+8)(block); \ + MOVOU X5, 8*(off+10)(block); \ + MOVOU X6, 8*(off+12)(block); \ + MOVOU X7, 8*(off+14)(block) + +#define LOAD_MSG_1(block, off) \ + MOVOU 8*off+0*8(block), X0; \ + MOVOU 8*off+16*8(block), X1; \ + MOVOU 8*off+32*8(block), X2; \ + MOVOU 8*off+48*8(block), X3; \ + MOVOU 8*off+64*8(block), X4; \ + MOVOU 8*off+80*8(block), X5; \ + MOVOU 8*off+96*8(block), X6; \ + MOVOU 8*off+112*8(block), X7 + +#define STORE_MSG_1(block, off) \ + MOVOU X0, 8*off+0*8(block); \ + MOVOU X1, 8*off+16*8(block); \ + MOVOU X2, 8*off+32*8(block); \ + MOVOU X3, 8*off+48*8(block); \ + MOVOU X4, 8*off+64*8(block); \ + MOVOU X5, 8*off+80*8(block); \ + MOVOU X6, 8*off+96*8(block); \ + MOVOU X7, 8*off+112*8(block) + +#define BLAMKA_ROUND_0(block, off, t0, t1, c40, c48) \ + LOAD_MSG_0(block, off); \ + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ + SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1); \ + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1); \ + STORE_MSG_0(block, off) + +#define BLAMKA_ROUND_1(block, off, t0, t1, c40, c48) \ + LOAD_MSG_1(block, off); \ + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ + SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1); \ + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1); \ + STORE_MSG_1(block, off) + +// func blamkaSSE4(b *block) +TEXT ·blamkaSSE4(SB), 4, $0-8 + MOVQ b+0(FP), AX + + MOVOU ·c40<>(SB), X10 + MOVOU ·c48<>(SB), X11 + + BLAMKA_ROUND_0(AX, 0, X8, X9, X10, X11) + BLAMKA_ROUND_0(AX, 16, X8, X9, X10, X11) + BLAMKA_ROUND_0(AX, 32, X8, X9, X10, X11) + BLAMKA_ROUND_0(AX, 48, X8, X9, X10, X11) + BLAMKA_ROUND_0(AX, 64, X8, X9, X10, X11) + BLAMKA_ROUND_0(AX, 80, X8, X9, X10, X11) + BLAMKA_ROUND_0(AX, 96, X8, X9, X10, X11) + BLAMKA_ROUND_0(AX, 112, X8, X9, X10, X11) + + BLAMKA_ROUND_1(AX, 0, X8, X9, X10, X11) + BLAMKA_ROUND_1(AX, 2, X8, X9, X10, X11) + BLAMKA_ROUND_1(AX, 4, X8, X9, X10, X11) + BLAMKA_ROUND_1(AX, 6, X8, X9, X10, X11) + BLAMKA_ROUND_1(AX, 8, X8, X9, X10, X11) + BLAMKA_ROUND_1(AX, 10, X8, X9, X10, X11) + BLAMKA_ROUND_1(AX, 12, X8, X9, X10, X11) + BLAMKA_ROUND_1(AX, 14, X8, X9, X10, X11) + RET + +// func mixBlocksSSE2(out, a, b, c *block) +TEXT ·mixBlocksSSE2(SB), 4, $0-32 + MOVQ out+0(FP), DX + MOVQ a+8(FP), AX + MOVQ b+16(FP), BX + MOVQ a+24(FP), CX + MOVQ $128, BP + +loop: + MOVOU 0(AX), X0 + MOVOU 0(BX), X1 + MOVOU 0(CX), X2 + PXOR X1, X0 + PXOR X2, X0 + MOVOU X0, 0(DX) + ADDQ $16, AX + ADDQ $16, BX + ADDQ $16, CX + ADDQ $16, DX + SUBQ $2, BP + JA loop + RET + +// func xorBlocksSSE2(out, a, b, c *block) +TEXT ·xorBlocksSSE2(SB), 4, $0-32 + MOVQ out+0(FP), DX + MOVQ a+8(FP), AX + MOVQ b+16(FP), BX + MOVQ a+24(FP), CX + MOVQ $128, BP + +loop: + MOVOU 0(AX), X0 + MOVOU 0(BX), X1 + MOVOU 0(CX), X2 + MOVOU 0(DX), X3 + PXOR X1, X0 + PXOR X2, X0 + PXOR X3, X0 + MOVOU X0, 0(DX) + ADDQ $16, AX + ADDQ $16, BX + ADDQ $16, CX + ADDQ $16, DX + SUBQ $2, BP + JA loop + RET diff --git a/vendor/golang.org/x/crypto/argon2/blamka_generic.go b/vendor/golang.org/x/crypto/argon2/blamka_generic.go new file mode 100644 index 0000000000..a481b2243f --- /dev/null +++ b/vendor/golang.org/x/crypto/argon2/blamka_generic.go @@ -0,0 +1,163 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package argon2 + +var useSSE4 bool + +func processBlockGeneric(out, in1, in2 *block, xor bool) { + var t block + for i := range t { + t[i] = in1[i] ^ in2[i] + } + for i := 0; i < blockLength; i += 16 { + blamkaGeneric( + &t[i+0], &t[i+1], &t[i+2], &t[i+3], + &t[i+4], &t[i+5], &t[i+6], &t[i+7], + &t[i+8], &t[i+9], &t[i+10], &t[i+11], + &t[i+12], &t[i+13], &t[i+14], &t[i+15], + ) + } + for i := 0; i < blockLength/8; i += 2 { + blamkaGeneric( + &t[i], &t[i+1], &t[16+i], &t[16+i+1], + &t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1], + &t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1], + &t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1], + ) + } + if xor { + for i := range t { + out[i] ^= in1[i] ^ in2[i] ^ t[i] + } + } else { + for i := range t { + out[i] = in1[i] ^ in2[i] ^ t[i] + } + } +} + +func blamkaGeneric(t00, t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15 *uint64) { + v00, v01, v02, v03 := *t00, *t01, *t02, *t03 + v04, v05, v06, v07 := *t04, *t05, *t06, *t07 + v08, v09, v10, v11 := *t08, *t09, *t10, *t11 + v12, v13, v14, v15 := *t12, *t13, *t14, *t15 + + v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04)) + v12 ^= v00 + v12 = v12>>32 | v12<<32 + v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12)) + v04 ^= v08 + v04 = v04>>24 | v04<<40 + + v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04)) + v12 ^= v00 + v12 = v12>>16 | v12<<48 + v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12)) + v04 ^= v08 + v04 = v04>>63 | v04<<1 + + v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05)) + v13 ^= v01 + v13 = v13>>32 | v13<<32 + v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13)) + v05 ^= v09 + v05 = v05>>24 | v05<<40 + + v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05)) + v13 ^= v01 + v13 = v13>>16 | v13<<48 + v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13)) + v05 ^= v09 + v05 = v05>>63 | v05<<1 + + v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06)) + v14 ^= v02 + v14 = v14>>32 | v14<<32 + v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14)) + v06 ^= v10 + v06 = v06>>24 | v06<<40 + + v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06)) + v14 ^= v02 + v14 = v14>>16 | v14<<48 + v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14)) + v06 ^= v10 + v06 = v06>>63 | v06<<1 + + v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07)) + v15 ^= v03 + v15 = v15>>32 | v15<<32 + v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15)) + v07 ^= v11 + v07 = v07>>24 | v07<<40 + + v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07)) + v15 ^= v03 + v15 = v15>>16 | v15<<48 + v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15)) + v07 ^= v11 + v07 = v07>>63 | v07<<1 + + v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05)) + v15 ^= v00 + v15 = v15>>32 | v15<<32 + v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15)) + v05 ^= v10 + v05 = v05>>24 | v05<<40 + + v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05)) + v15 ^= v00 + v15 = v15>>16 | v15<<48 + v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15)) + v05 ^= v10 + v05 = v05>>63 | v05<<1 + + v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06)) + v12 ^= v01 + v12 = v12>>32 | v12<<32 + v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12)) + v06 ^= v11 + v06 = v06>>24 | v06<<40 + + v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06)) + v12 ^= v01 + v12 = v12>>16 | v12<<48 + v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12)) + v06 ^= v11 + v06 = v06>>63 | v06<<1 + + v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07)) + v13 ^= v02 + v13 = v13>>32 | v13<<32 + v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13)) + v07 ^= v08 + v07 = v07>>24 | v07<<40 + + v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07)) + v13 ^= v02 + v13 = v13>>16 | v13<<48 + v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13)) + v07 ^= v08 + v07 = v07>>63 | v07<<1 + + v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04)) + v14 ^= v03 + v14 = v14>>32 | v14<<32 + v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14)) + v04 ^= v09 + v04 = v04>>24 | v04<<40 + + v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04)) + v14 ^= v03 + v14 = v14>>16 | v14<<48 + v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14)) + v04 ^= v09 + v04 = v04>>63 | v04<<1 + + *t00, *t01, *t02, *t03 = v00, v01, v02, v03 + *t04, *t05, *t06, *t07 = v04, v05, v06, v07 + *t08, *t09, *t10, *t11 = v08, v09, v10, v11 + *t12, *t13, *t14, *t15 = v12, v13, v14, v15 +} diff --git a/vendor/golang.org/x/crypto/argon2/blamka_ref.go b/vendor/golang.org/x/crypto/argon2/blamka_ref.go new file mode 100644 index 0000000000..baf7b551da --- /dev/null +++ b/vendor/golang.org/x/crypto/argon2/blamka_ref.go @@ -0,0 +1,15 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !amd64 appengine gccgo + +package argon2 + +func processBlock(out, in1, in2 *block) { + processBlockGeneric(out, in1, in2, false) +} + +func processBlockXOR(out, in1, in2 *block) { + processBlockGeneric(out, in1, in2, true) +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b.go b/vendor/golang.org/x/crypto/blake2b/blake2b.go new file mode 100644 index 0000000000..c160e1a4e3 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b.go @@ -0,0 +1,289 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 +// and the extendable output function (XOF) BLAKE2Xb. +// +// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf +// and for BLAKE2Xb see https://blake2.net/blake2x.pdf +// +// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512). +// If you need a secret-key MAC (message authentication code), use the New512 +// function with a non-nil key. +// +// BLAKE2X is a construction to compute hash values larger than 64 bytes. It +// can produce hash values between 0 and 4 GiB. +package blake2b + +import ( + "encoding/binary" + "errors" + "hash" +) + +const ( + // The blocksize of BLAKE2b in bytes. + BlockSize = 128 + // The hash size of BLAKE2b-512 in bytes. + Size = 64 + // The hash size of BLAKE2b-384 in bytes. + Size384 = 48 + // The hash size of BLAKE2b-256 in bytes. + Size256 = 32 +) + +var ( + useAVX2 bool + useAVX bool + useSSE4 bool +) + +var ( + errKeySize = errors.New("blake2b: invalid key size") + errHashSize = errors.New("blake2b: invalid hash size") +) + +var iv = [8]uint64{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +} + +// Sum512 returns the BLAKE2b-512 checksum of the data. +func Sum512(data []byte) [Size]byte { + var sum [Size]byte + checkSum(&sum, Size, data) + return sum +} + +// Sum384 returns the BLAKE2b-384 checksum of the data. +func Sum384(data []byte) [Size384]byte { + var sum [Size]byte + var sum384 [Size384]byte + checkSum(&sum, Size384, data) + copy(sum384[:], sum[:Size384]) + return sum384 +} + +// Sum256 returns the BLAKE2b-256 checksum of the data. +func Sum256(data []byte) [Size256]byte { + var sum [Size]byte + var sum256 [Size256]byte + checkSum(&sum, Size256, data) + copy(sum256[:], sum[:Size256]) + return sum256 +} + +// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil +// key turns the hash into a MAC. The key must be between zero and 64 bytes long. +func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) } + +// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil +// key turns the hash into a MAC. The key must be between zero and 64 bytes long. +func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) } + +// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil +// key turns the hash into a MAC. The key must be between zero and 64 bytes long. +func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) } + +// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length. +// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long. +// The hash size can be a value between 1 and 64 but it is highly recommended to use +// values equal or greater than: +// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). +// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long). +// When the key is nil, the returned hash.Hash implements BinaryMarshaler +// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. +func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) } + +func newDigest(hashSize int, key []byte) (*digest, error) { + if hashSize < 1 || hashSize > Size { + return nil, errHashSize + } + if len(key) > Size { + return nil, errKeySize + } + d := &digest{ + size: hashSize, + keyLen: len(key), + } + copy(d.key[:], key) + d.Reset() + return d, nil +} + +func checkSum(sum *[Size]byte, hashSize int, data []byte) { + h := iv + h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24) + var c [2]uint64 + + if length := len(data); length > BlockSize { + n := length &^ (BlockSize - 1) + if length == n { + n -= BlockSize + } + hashBlocks(&h, &c, 0, data[:n]) + data = data[n:] + } + + var block [BlockSize]byte + offset := copy(block[:], data) + remaining := uint64(BlockSize - offset) + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) + + for i, v := range h[:(hashSize+7)/8] { + binary.LittleEndian.PutUint64(sum[8*i:], v) + } +} + +type digest struct { + h [8]uint64 + c [2]uint64 + size int + block [BlockSize]byte + offset int + + key [BlockSize]byte + keyLen int +} + +const ( + magic = "b2b" + marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + if d.keyLen != 0 { + return nil, errors.New("crypto/blake2b: cannot marshal MACs") + } + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + for i := 0; i < 8; i++ { + b = appendUint64(b, d.h[i]) + } + b = appendUint64(b, d.c[0]) + b = appendUint64(b, d.c[1]) + // Maximum value for size is 64 + b = append(b, byte(d.size)) + b = append(b, d.block[:]...) + b = append(b, byte(d.offset)) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("crypto/blake2b: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/blake2b: invalid hash state size") + } + b = b[len(magic):] + for i := 0; i < 8; i++ { + b, d.h[i] = consumeUint64(b) + } + b, d.c[0] = consumeUint64(b) + b, d.c[1] = consumeUint64(b) + d.size = int(b[0]) + b = b[1:] + copy(d.block[:], b[:BlockSize]) + b = b[BlockSize:] + d.offset = int(b[0]) + return nil +} + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Size() int { return d.size } + +func (d *digest) Reset() { + d.h = iv + d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24) + d.offset, d.c[0], d.c[1] = 0, 0, 0 + if d.keyLen > 0 { + d.block = d.key + d.offset = BlockSize + } +} + +func (d *digest) Write(p []byte) (n int, err error) { + n = len(p) + + if d.offset > 0 { + remaining := BlockSize - d.offset + if n <= remaining { + d.offset += copy(d.block[d.offset:], p) + return + } + copy(d.block[d.offset:], p[:remaining]) + hashBlocks(&d.h, &d.c, 0, d.block[:]) + d.offset = 0 + p = p[remaining:] + } + + if length := len(p); length > BlockSize { + nn := length &^ (BlockSize - 1) + if length == nn { + nn -= BlockSize + } + hashBlocks(&d.h, &d.c, 0, p[:nn]) + p = p[nn:] + } + + if len(p) > 0 { + d.offset += copy(d.block[:], p) + } + + return +} + +func (d *digest) Sum(sum []byte) []byte { + var hash [Size]byte + d.finalize(&hash) + return append(sum, hash[:d.size]...) +} + +func (d *digest) finalize(hash *[Size]byte) { + var block [BlockSize]byte + copy(block[:], d.block[:d.offset]) + remaining := uint64(BlockSize - d.offset) + + c := d.c + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + h := d.h + hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) + + for i, v := range h { + binary.LittleEndian.PutUint64(hash[8*i:], v) + } +} + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + binary.BigEndian.PutUint64(a[:], x) + return append(b, a[:]...) +} + +func appendUint32(b []byte, x uint32) []byte { + var a [4]byte + binary.BigEndian.PutUint32(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + x := binary.BigEndian.Uint64(b) + return b[8:], x +} + +func consumeUint32(b []byte) ([]byte, uint32) { + x := binary.BigEndian.Uint32(b) + return b[4:], x +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go new file mode 100644 index 0000000000..4d31dd0fdc --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go @@ -0,0 +1,37 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7,amd64,!gccgo,!appengine + +package blake2b + +import "golang.org/x/sys/cpu" + +func init() { + useAVX2 = cpu.X86.HasAVX2 + useAVX = cpu.X86.HasAVX + useSSE4 = cpu.X86.HasSSE41 +} + +//go:noescape +func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +//go:noescape +func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +//go:noescape +func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + switch { + case useAVX2: + hashBlocksAVX2(h, c, flag, blocks) + case useAVX: + hashBlocksAVX(h, c, flag, blocks) + case useSSE4: + hashBlocksSSE4(h, c, flag, blocks) + default: + hashBlocksGeneric(h, c, flag, blocks) + } +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s new file mode 100644 index 0000000000..5593b1b3dc --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s @@ -0,0 +1,750 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7,amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16 + +#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39 +#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93 +#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e +#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93 +#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39 + +#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \ + VPADDQ m0, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFD $-79, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPSHUFB c40, Y1, Y1; \ + VPADDQ m1, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFB c48, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPADDQ Y1, Y1, t; \ + VPSRLQ $63, Y1, Y1; \ + VPXOR t, Y1, Y1; \ + VPERMQ_0x39_Y1_Y1; \ + VPERMQ_0x4E_Y2_Y2; \ + VPERMQ_0x93_Y3_Y3; \ + VPADDQ m2, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFD $-79, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPSHUFB c40, Y1, Y1; \ + VPADDQ m3, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFB c48, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPADDQ Y1, Y1, t; \ + VPSRLQ $63, Y1, Y1; \ + VPXOR t, Y1, Y1; \ + VPERMQ_0x39_Y3_Y3; \ + VPERMQ_0x4E_Y2_Y2; \ + VPERMQ_0x93_Y1_Y1 + +#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E +#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26 +#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E +#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36 +#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E + +#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n +#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n +#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n +#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n +#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n + +#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01 +#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01 +#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01 +#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01 +#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01 + +#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01 + +#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8 +#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01 + +// load msg: Y12 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \ + VMOVQ_SI_X12(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X12(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y12, Y12 + +// load msg: Y13 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \ + VMOVQ_SI_X13(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X13(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y13, Y13 + +// load msg: Y14 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \ + VMOVQ_SI_X14(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X14(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y14, Y14 + +// load msg: Y15 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \ + VMOVQ_SI_X15(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X15(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \ + VMOVQ_SI_X12_0; \ + VMOVQ_SI_X11(4*8); \ + VPINSRQ_1_SI_X12(2*8); \ + VPINSRQ_1_SI_X11(6*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \ + LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \ + LOAD_MSG_AVX2_Y15(9, 11, 13, 15) + +#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \ + LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \ + LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \ + VMOVQ_SI_X11(11*8); \ + VPSHUFD $0x4E, 0*8(SI), X14; \ + VPINSRQ_1_SI_X11(5*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + LOAD_MSG_AVX2_Y15(12, 2, 7, 3) + +#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \ + VMOVQ_SI_X11(5*8); \ + VMOVDQU 11*8(SI), X12; \ + VPINSRQ_1_SI_X11(15*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + VMOVQ_SI_X13(8*8); \ + VMOVQ_SI_X11(2*8); \ + VPINSRQ_1_SI_X13_0; \ + VPINSRQ_1_SI_X11(13*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \ + LOAD_MSG_AVX2_Y15(14, 6, 1, 4) + +#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \ + LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \ + LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \ + LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \ + VMOVQ_SI_X15(6*8); \ + VMOVQ_SI_X11_0; \ + VPINSRQ_1_SI_X15(10*8); \ + VPINSRQ_1_SI_X11(8*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \ + LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \ + VMOVQ_SI_X13_0; \ + VMOVQ_SI_X11(4*8); \ + VPINSRQ_1_SI_X13(7*8); \ + VPINSRQ_1_SI_X11(15*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \ + LOAD_MSG_AVX2_Y15(1, 12, 8, 13) + +#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X11_0; \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X11(8*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \ + LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \ + LOAD_MSG_AVX2_Y15(13, 5, 14, 9) + +#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \ + LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \ + LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \ + VMOVQ_SI_X14_0; \ + VPSHUFD $0x4E, 8*8(SI), X11; \ + VPINSRQ_1_SI_X14(6*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + LOAD_MSG_AVX2_Y15(7, 3, 2, 11) + +#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \ + LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \ + LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \ + LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \ + VMOVQ_SI_X15_0; \ + VMOVQ_SI_X11(6*8); \ + VPINSRQ_1_SI_X15(4*8); \ + VPINSRQ_1_SI_X11(10*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \ + VMOVQ_SI_X12(6*8); \ + VMOVQ_SI_X11(11*8); \ + VPINSRQ_1_SI_X12(14*8); \ + VPINSRQ_1_SI_X11_0; \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \ + VMOVQ_SI_X11(1*8); \ + VMOVDQU 12*8(SI), X14; \ + VPINSRQ_1_SI_X11(10*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + VMOVQ_SI_X15(2*8); \ + VMOVDQU 4*8(SI), X11; \ + VPINSRQ_1_SI_X15(7*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \ + LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \ + VMOVQ_SI_X13(2*8); \ + VPSHUFD $0x4E, 5*8(SI), X11; \ + VPINSRQ_1_SI_X13(4*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \ + VMOVQ_SI_X15(11*8); \ + VMOVQ_SI_X11(12*8); \ + VPINSRQ_1_SI_X15(14*8); \ + VPINSRQ_1_SI_X11_0; \ + VINSERTI128 $1, X11, Y15, Y15 + +// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksAVX2(SB), 4, $320-48 // frame size = 288 + 32 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, DX + MOVQ SP, R9 + ADDQ $31, R9 + ANDQ $~31, R9 + MOVQ R9, SP + + MOVQ CX, 16(SP) + XORQ CX, CX + MOVQ CX, 24(SP) + + VMOVDQU ·AVX2_c40<>(SB), Y4 + VMOVDQU ·AVX2_c48<>(SB), Y5 + + VMOVDQU 0(AX), Y8 + VMOVDQU 32(AX), Y9 + VMOVDQU ·AVX2_iv0<>(SB), Y6 + VMOVDQU ·AVX2_iv1<>(SB), Y7 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + MOVQ R9, 8(SP) + +loop: + ADDQ $128, R8 + MOVQ R8, 0(SP) + CMPQ R8, $128 + JGE noinc + INCQ R9 + MOVQ R9, 8(SP) + +noinc: + VMOVDQA Y8, Y0 + VMOVDQA Y9, Y1 + VMOVDQA Y6, Y2 + VPXOR 0(SP), Y7, Y3 + + LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() + VMOVDQA Y12, 32(SP) + VMOVDQA Y13, 64(SP) + VMOVDQA Y14, 96(SP) + VMOVDQA Y15, 128(SP) + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() + VMOVDQA Y12, 160(SP) + VMOVDQA Y13, 192(SP) + VMOVDQA Y14, 224(SP) + VMOVDQA Y15, 256(SP) + + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + + ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5) + ROUND_AVX2(160(SP), 192(SP), 224(SP), 256(SP), Y10, Y4, Y5) + + VPXOR Y0, Y8, Y8 + VPXOR Y1, Y9, Y9 + VPXOR Y2, Y8, Y8 + VPXOR Y3, Y9, Y9 + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + + VMOVDQU Y8, 0(AX) + VMOVDQU Y9, 32(AX) + VZEROUPPER + + MOVQ DX, SP + RET + +#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA +#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB +#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF +#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD +#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE + +#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7 +#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF +#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7 +#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF +#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7 +#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7 +#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF +#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF + +#define SHUFFLE_AVX() \ + VMOVDQA X6, X13; \ + VMOVDQA X2, X14; \ + VMOVDQA X4, X6; \ + VPUNPCKLQDQ_X13_X13_X15; \ + VMOVDQA X5, X4; \ + VMOVDQA X6, X5; \ + VPUNPCKHQDQ_X15_X7_X6; \ + VPUNPCKLQDQ_X7_X7_X15; \ + VPUNPCKHQDQ_X15_X13_X7; \ + VPUNPCKLQDQ_X3_X3_X15; \ + VPUNPCKHQDQ_X15_X2_X2; \ + VPUNPCKLQDQ_X14_X14_X15; \ + VPUNPCKHQDQ_X15_X3_X3; \ + +#define SHUFFLE_AVX_INV() \ + VMOVDQA X2, X13; \ + VMOVDQA X4, X14; \ + VPUNPCKLQDQ_X2_X2_X15; \ + VMOVDQA X5, X4; \ + VPUNPCKHQDQ_X15_X3_X2; \ + VMOVDQA X14, X5; \ + VPUNPCKLQDQ_X3_X3_X15; \ + VMOVDQA X6, X14; \ + VPUNPCKHQDQ_X15_X13_X3; \ + VPUNPCKLQDQ_X7_X7_X15; \ + VPUNPCKHQDQ_X15_X6_X6; \ + VPUNPCKLQDQ_X14_X14_X15; \ + VPUNPCKHQDQ_X15_X7_X7; \ + +#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ + VPADDQ m0, v0, v0; \ + VPADDQ v2, v0, v0; \ + VPADDQ m1, v1, v1; \ + VPADDQ v3, v1, v1; \ + VPXOR v0, v6, v6; \ + VPXOR v1, v7, v7; \ + VPSHUFD $-79, v6, v6; \ + VPSHUFD $-79, v7, v7; \ + VPADDQ v6, v4, v4; \ + VPADDQ v7, v5, v5; \ + VPXOR v4, v2, v2; \ + VPXOR v5, v3, v3; \ + VPSHUFB c40, v2, v2; \ + VPSHUFB c40, v3, v3; \ + VPADDQ m2, v0, v0; \ + VPADDQ v2, v0, v0; \ + VPADDQ m3, v1, v1; \ + VPADDQ v3, v1, v1; \ + VPXOR v0, v6, v6; \ + VPXOR v1, v7, v7; \ + VPSHUFB c48, v6, v6; \ + VPSHUFB c48, v7, v7; \ + VPADDQ v6, v4, v4; \ + VPADDQ v7, v5, v5; \ + VPXOR v4, v2, v2; \ + VPXOR v5, v3, v3; \ + VPADDQ v2, v2, t0; \ + VPSRLQ $63, v2, v2; \ + VPXOR t0, v2, v2; \ + VPADDQ v3, v3, t0; \ + VPSRLQ $63, v3, v3; \ + VPXOR t0, v3, v3 + +// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7) +// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0 +#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \ + VMOVQ_SI_X12(i0*8); \ + VMOVQ_SI_X13(i2*8); \ + VMOVQ_SI_X14(i4*8); \ + VMOVQ_SI_X15(i6*8); \ + VPINSRQ_1_SI_X12(i1*8); \ + VPINSRQ_1_SI_X13(i3*8); \ + VPINSRQ_1_SI_X14(i5*8); \ + VPINSRQ_1_SI_X15(i7*8) + +// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7) +#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \ + VMOVQ_SI_X12_0; \ + VMOVQ_SI_X13(4*8); \ + VMOVQ_SI_X14(1*8); \ + VMOVQ_SI_X15(5*8); \ + VPINSRQ_1_SI_X12(2*8); \ + VPINSRQ_1_SI_X13(6*8); \ + VPINSRQ_1_SI_X14(3*8); \ + VPINSRQ_1_SI_X15(7*8) + +// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3) +#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \ + VPSHUFD $0x4E, 0*8(SI), X12; \ + VMOVQ_SI_X13(11*8); \ + VMOVQ_SI_X14(12*8); \ + VMOVQ_SI_X15(7*8); \ + VPINSRQ_1_SI_X13(5*8); \ + VPINSRQ_1_SI_X14(2*8); \ + VPINSRQ_1_SI_X15(3*8) + +// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13) +#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \ + VMOVDQU 11*8(SI), X12; \ + VMOVQ_SI_X13(5*8); \ + VMOVQ_SI_X14(8*8); \ + VMOVQ_SI_X15(2*8); \ + VPINSRQ_1_SI_X13(15*8); \ + VPINSRQ_1_SI_X14_0; \ + VPINSRQ_1_SI_X15(13*8) + +// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8) +#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X13(4*8); \ + VMOVQ_SI_X14(6*8); \ + VMOVQ_SI_X15_0; \ + VPINSRQ_1_SI_X12(5*8); \ + VPINSRQ_1_SI_X13(15*8); \ + VPINSRQ_1_SI_X14(10*8); \ + VPINSRQ_1_SI_X15(8*8) + +// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15) +#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \ + VMOVQ_SI_X12(9*8); \ + VMOVQ_SI_X13(2*8); \ + VMOVQ_SI_X14_0; \ + VMOVQ_SI_X15(4*8); \ + VPINSRQ_1_SI_X12(5*8); \ + VPINSRQ_1_SI_X13(10*8); \ + VPINSRQ_1_SI_X14(7*8); \ + VPINSRQ_1_SI_X15(15*8) + +// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3) +#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X13_0; \ + VMOVQ_SI_X14(12*8); \ + VMOVQ_SI_X15(11*8); \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X13(8*8); \ + VPINSRQ_1_SI_X14(10*8); \ + VPINSRQ_1_SI_X15(3*8) + +// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11) +#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \ + MOVQ 0*8(SI), X12; \ + VPSHUFD $0x4E, 8*8(SI), X13; \ + MOVQ 7*8(SI), X14; \ + MOVQ 2*8(SI), X15; \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X14(3*8); \ + VPINSRQ_1_SI_X15(11*8) + +// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8) +#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \ + MOVQ 6*8(SI), X12; \ + MOVQ 11*8(SI), X13; \ + MOVQ 15*8(SI), X14; \ + MOVQ 3*8(SI), X15; \ + VPINSRQ_1_SI_X12(14*8); \ + VPINSRQ_1_SI_X13_0; \ + VPINSRQ_1_SI_X14(9*8); \ + VPINSRQ_1_SI_X15(8*8) + +// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10) +#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \ + MOVQ 5*8(SI), X12; \ + MOVQ 8*8(SI), X13; \ + MOVQ 0*8(SI), X14; \ + MOVQ 6*8(SI), X15; \ + VPINSRQ_1_SI_X12(15*8); \ + VPINSRQ_1_SI_X13(2*8); \ + VPINSRQ_1_SI_X14(4*8); \ + VPINSRQ_1_SI_X15(10*8) + +// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5) +#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \ + VMOVDQU 12*8(SI), X12; \ + MOVQ 1*8(SI), X13; \ + MOVQ 2*8(SI), X14; \ + VPINSRQ_1_SI_X13(10*8); \ + VPINSRQ_1_SI_X14(7*8); \ + VMOVDQU 4*8(SI), X15 + +// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0) +#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \ + MOVQ 15*8(SI), X12; \ + MOVQ 3*8(SI), X13; \ + MOVQ 11*8(SI), X14; \ + MOVQ 12*8(SI), X15; \ + VPINSRQ_1_SI_X12(9*8); \ + VPINSRQ_1_SI_X13(13*8); \ + VPINSRQ_1_SI_X14(14*8); \ + VPINSRQ_1_SI_X15_0 + +// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, BP + MOVQ SP, R9 + ADDQ $15, R9 + ANDQ $~15, R9 + MOVQ R9, SP + + VMOVDQU ·AVX_c40<>(SB), X0 + VMOVDQU ·AVX_c48<>(SB), X1 + VMOVDQA X0, X8 + VMOVDQA X1, X9 + + VMOVDQU ·AVX_iv3<>(SB), X0 + VMOVDQA X0, 0(SP) + XORQ CX, 0(SP) // 0(SP) = ·AVX_iv3 ^ (CX || 0) + + VMOVDQU 0(AX), X10 + VMOVDQU 16(AX), X11 + VMOVDQU 32(AX), X2 + VMOVDQU 48(AX), X3 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + +loop: + ADDQ $128, R8 + CMPQ R8, $128 + JGE noinc + INCQ R9 + +noinc: + VMOVQ_R8_X15 + VPINSRQ_1_R9_X15 + + VMOVDQA X10, X0 + VMOVDQA X11, X1 + VMOVDQU ·AVX_iv0<>(SB), X4 + VMOVDQU ·AVX_iv1<>(SB), X5 + VMOVDQU ·AVX_iv2<>(SB), X6 + + VPXOR X15, X6, X6 + VMOVDQA 0(SP), X7 + + LOAD_MSG_AVX_0_2_4_6_1_3_5_7() + VMOVDQA X12, 16(SP) + VMOVDQA X13, 32(SP) + VMOVDQA X14, 48(SP) + VMOVDQA X15, 64(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15) + VMOVDQA X12, 80(SP) + VMOVDQA X13, 96(SP) + VMOVDQA X14, 112(SP) + VMOVDQA X15, 128(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6) + VMOVDQA X12, 144(SP) + VMOVDQA X13, 160(SP) + VMOVDQA X14, 176(SP) + VMOVDQA X15, 192(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_1_0_11_5_12_2_7_3() + VMOVDQA X12, 208(SP) + VMOVDQA X13, 224(SP) + VMOVDQA X14, 240(SP) + VMOVDQA X15, 256(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_11_12_5_15_8_0_2_13() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_2_5_4_15_6_10_0_8() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_9_5_2_10_0_7_4_15() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_2_6_0_8_12_10_11_3() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_0_6_9_8_7_3_2_11() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_5_15_8_2_0_4_6_10() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_6_14_11_0_15_9_3_8() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_12_13_1_10_2_7_4_5() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_15_9_3_13_11_14_12_0() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X15, X8, X9) + SHUFFLE_AVX() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X15, X8, X9) + SHUFFLE_AVX_INV() + + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X15, X8, X9) + SHUFFLE_AVX() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X15, X8, X9) + SHUFFLE_AVX_INV() + + VMOVDQU 32(AX), X14 + VMOVDQU 48(AX), X15 + VPXOR X0, X10, X10 + VPXOR X1, X11, X11 + VPXOR X2, X14, X14 + VPXOR X3, X15, X15 + VPXOR X4, X10, X10 + VPXOR X5, X11, X11 + VPXOR X6, X14, X2 + VPXOR X7, X15, X3 + VMOVDQU X2, 32(AX) + VMOVDQU X3, 48(AX) + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + VMOVDQU X10, 0(AX) + VMOVDQU X11, 16(AX) + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + VZEROUPPER + + MOVQ BP, SP + RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go new file mode 100644 index 0000000000..30e2fcd581 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go @@ -0,0 +1,24 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.7,amd64,!gccgo,!appengine + +package blake2b + +import "golang.org/x/sys/cpu" + +func init() { + useSSE4 = cpu.X86.HasSSE41 +} + +//go:noescape +func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + if useSSE4 { + hashBlocksSSE4(h, c, flag, blocks) + } else { + hashBlocksGeneric(h, c, flag, blocks) + } +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s new file mode 100644 index 0000000000..578e947b3b --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s @@ -0,0 +1,281 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b +DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b +DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 +GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16 + +DATA ·c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·c40<>(SB), (NOPTR+RODATA), $16 + +DATA ·c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·c48<>(SB), (NOPTR+RODATA), $16 + +#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v6, t1; \ + PUNPCKLQDQ v6, t2; \ + PUNPCKHQDQ v7, v6; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ v7, t2; \ + MOVO t1, v7; \ + MOVO v2, t1; \ + PUNPCKHQDQ t2, v7; \ + PUNPCKLQDQ v3, t2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v3 + +#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v2, t1; \ + PUNPCKLQDQ v2, t2; \ + PUNPCKHQDQ v3, v2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ v3, t2; \ + MOVO t1, v3; \ + MOVO v6, t1; \ + PUNPCKHQDQ t2, v3; \ + PUNPCKLQDQ v7, t2; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v7 + +#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ + PADDQ m0, v0; \ + PADDQ m1, v1; \ + PADDQ v2, v0; \ + PADDQ v3, v1; \ + PXOR v0, v6; \ + PXOR v1, v7; \ + PSHUFD $0xB1, v6, v6; \ + PSHUFD $0xB1, v7, v7; \ + PADDQ v6, v4; \ + PADDQ v7, v5; \ + PXOR v4, v2; \ + PXOR v5, v3; \ + PSHUFB c40, v2; \ + PSHUFB c40, v3; \ + PADDQ m2, v0; \ + PADDQ m3, v1; \ + PADDQ v2, v0; \ + PADDQ v3, v1; \ + PXOR v0, v6; \ + PXOR v1, v7; \ + PSHUFB c48, v6; \ + PSHUFB c48, v7; \ + PADDQ v6, v4; \ + PADDQ v7, v5; \ + PXOR v4, v2; \ + PXOR v5, v3; \ + MOVOU v2, t0; \ + PADDQ v2, t0; \ + PSRLQ $63, v2; \ + PXOR t0, v2; \ + MOVOU v3, t0; \ + PADDQ v3, t0; \ + PSRLQ $63, v3; \ + PXOR t0, v3 + +#define LOAD_MSG(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7) \ + MOVQ i0*8(src), m0; \ + PINSRQ $1, i1*8(src), m0; \ + MOVQ i2*8(src), m1; \ + PINSRQ $1, i3*8(src), m1; \ + MOVQ i4*8(src), m2; \ + PINSRQ $1, i5*8(src), m2; \ + MOVQ i6*8(src), m3; \ + PINSRQ $1, i7*8(src), m3 + +// func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksSSE4(SB), 4, $288-48 // frame size = 272 + 16 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, BP + MOVQ SP, R9 + ADDQ $15, R9 + ANDQ $~15, R9 + MOVQ R9, SP + + MOVOU ·iv3<>(SB), X0 + MOVO X0, 0(SP) + XORQ CX, 0(SP) // 0(SP) = ·iv3 ^ (CX || 0) + + MOVOU ·c40<>(SB), X13 + MOVOU ·c48<>(SB), X14 + + MOVOU 0(AX), X12 + MOVOU 16(AX), X15 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + +loop: + ADDQ $128, R8 + CMPQ R8, $128 + JGE noinc + INCQ R9 + +noinc: + MOVQ R8, X8 + PINSRQ $1, R9, X8 + + MOVO X12, X0 + MOVO X15, X1 + MOVOU 32(AX), X2 + MOVOU 48(AX), X3 + MOVOU ·iv0<>(SB), X4 + MOVOU ·iv1<>(SB), X5 + MOVOU ·iv2<>(SB), X6 + + PXOR X8, X6 + MOVO 0(SP), X7 + + LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7) + MOVO X8, 16(SP) + MOVO X9, 32(SP) + MOVO X10, 48(SP) + MOVO X11, 64(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15) + MOVO X8, 80(SP) + MOVO X9, 96(SP) + MOVO X10, 112(SP) + MOVO X11, 128(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6) + MOVO X8, 144(SP) + MOVO X9, 160(SP) + MOVO X10, 176(SP) + MOVO X11, 192(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3) + MOVO X8, 208(SP) + MOVO X9, 224(SP) + MOVO X10, 240(SP) + MOVO X11, 256(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + MOVOU 32(AX), X10 + MOVOU 48(AX), X11 + PXOR X0, X12 + PXOR X1, X15 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X15 + PXOR X6, X10 + PXOR X7, X11 + MOVOU X10, 32(AX) + MOVOU X11, 48(AX) + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + MOVOU X12, 0(AX) + MOVOU X15, 16(AX) + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + + MOVQ BP, SP + RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go b/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go new file mode 100644 index 0000000000..3168a8aa3c --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go @@ -0,0 +1,182 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2b + +import ( + "encoding/binary" + "math/bits" +) + +// the precomputed values for BLAKE2b +// there are 12 16-byte arrays - one for each round +// the entries are calculated from the sigma constants. +var precomputed = [12][16]byte{ + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, + {11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4}, + {7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8}, + {9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13}, + {2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9}, + {12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11}, + {13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10}, + {6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5}, + {10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0}, + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, // equal to the first + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, // equal to the second +} + +func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + var m [16]uint64 + c0, c1 := c[0], c[1] + + for i := 0; i < len(blocks); { + c0 += BlockSize + if c0 < BlockSize { + c1++ + } + + v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7] + v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7] + v12 ^= c0 + v13 ^= c1 + v14 ^= flag + + for j := range m { + m[j] = binary.LittleEndian.Uint64(blocks[i:]) + i += 8 + } + + for j := range precomputed { + s := &(precomputed[j]) + + v0 += m[s[0]] + v0 += v4 + v12 ^= v0 + v12 = bits.RotateLeft64(v12, -32) + v8 += v12 + v4 ^= v8 + v4 = bits.RotateLeft64(v4, -24) + v1 += m[s[1]] + v1 += v5 + v13 ^= v1 + v13 = bits.RotateLeft64(v13, -32) + v9 += v13 + v5 ^= v9 + v5 = bits.RotateLeft64(v5, -24) + v2 += m[s[2]] + v2 += v6 + v14 ^= v2 + v14 = bits.RotateLeft64(v14, -32) + v10 += v14 + v6 ^= v10 + v6 = bits.RotateLeft64(v6, -24) + v3 += m[s[3]] + v3 += v7 + v15 ^= v3 + v15 = bits.RotateLeft64(v15, -32) + v11 += v15 + v7 ^= v11 + v7 = bits.RotateLeft64(v7, -24) + + v0 += m[s[4]] + v0 += v4 + v12 ^= v0 + v12 = bits.RotateLeft64(v12, -16) + v8 += v12 + v4 ^= v8 + v4 = bits.RotateLeft64(v4, -63) + v1 += m[s[5]] + v1 += v5 + v13 ^= v1 + v13 = bits.RotateLeft64(v13, -16) + v9 += v13 + v5 ^= v9 + v5 = bits.RotateLeft64(v5, -63) + v2 += m[s[6]] + v2 += v6 + v14 ^= v2 + v14 = bits.RotateLeft64(v14, -16) + v10 += v14 + v6 ^= v10 + v6 = bits.RotateLeft64(v6, -63) + v3 += m[s[7]] + v3 += v7 + v15 ^= v3 + v15 = bits.RotateLeft64(v15, -16) + v11 += v15 + v7 ^= v11 + v7 = bits.RotateLeft64(v7, -63) + + v0 += m[s[8]] + v0 += v5 + v15 ^= v0 + v15 = bits.RotateLeft64(v15, -32) + v10 += v15 + v5 ^= v10 + v5 = bits.RotateLeft64(v5, -24) + v1 += m[s[9]] + v1 += v6 + v12 ^= v1 + v12 = bits.RotateLeft64(v12, -32) + v11 += v12 + v6 ^= v11 + v6 = bits.RotateLeft64(v6, -24) + v2 += m[s[10]] + v2 += v7 + v13 ^= v2 + v13 = bits.RotateLeft64(v13, -32) + v8 += v13 + v7 ^= v8 + v7 = bits.RotateLeft64(v7, -24) + v3 += m[s[11]] + v3 += v4 + v14 ^= v3 + v14 = bits.RotateLeft64(v14, -32) + v9 += v14 + v4 ^= v9 + v4 = bits.RotateLeft64(v4, -24) + + v0 += m[s[12]] + v0 += v5 + v15 ^= v0 + v15 = bits.RotateLeft64(v15, -16) + v10 += v15 + v5 ^= v10 + v5 = bits.RotateLeft64(v5, -63) + v1 += m[s[13]] + v1 += v6 + v12 ^= v1 + v12 = bits.RotateLeft64(v12, -16) + v11 += v12 + v6 ^= v11 + v6 = bits.RotateLeft64(v6, -63) + v2 += m[s[14]] + v2 += v7 + v13 ^= v2 + v13 = bits.RotateLeft64(v13, -16) + v8 += v13 + v7 ^= v8 + v7 = bits.RotateLeft64(v7, -63) + v3 += m[s[15]] + v3 += v4 + v14 ^= v3 + v14 = bits.RotateLeft64(v14, -16) + v9 += v14 + v4 ^= v9 + v4 = bits.RotateLeft64(v4, -63) + + } + + h[0] ^= v0 ^ v8 + h[1] ^= v1 ^ v9 + h[2] ^= v2 ^ v10 + h[3] ^= v3 ^ v11 + h[4] ^= v4 ^ v12 + h[5] ^= v5 ^ v13 + h[6] ^= v6 ^ v14 + h[7] ^= v7 ^ v15 + } + c[0], c[1] = c0, c1 +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go new file mode 100644 index 0000000000..da156a1ba6 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !amd64 appengine gccgo + +package blake2b + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + hashBlocksGeneric(h, c, flag, blocks) +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2x.go b/vendor/golang.org/x/crypto/blake2b/blake2x.go new file mode 100644 index 0000000000..52c414db0e --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2x.go @@ -0,0 +1,177 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2b + +import ( + "encoding/binary" + "errors" + "io" +) + +// XOF defines the interface to hash functions that +// support arbitrary-length output. +type XOF interface { + // Write absorbs more data into the hash's state. It panics if called + // after Read. + io.Writer + + // Read reads more output from the hash. It returns io.EOF if the limit + // has been reached. + io.Reader + + // Clone returns a copy of the XOF in its current state. + Clone() XOF + + // Reset resets the XOF to its initial state. + Reset() +} + +// OutputLengthUnknown can be used as the size argument to NewXOF to indicate +// the length of the output is not known in advance. +const OutputLengthUnknown = 0 + +// magicUnknownOutputLength is a magic value for the output size that indicates +// an unknown number of output bytes. +const magicUnknownOutputLength = (1 << 32) - 1 + +// maxOutputLength is the absolute maximum number of bytes to produce when the +// number of output bytes is unknown. +const maxOutputLength = (1 << 32) * 64 + +// NewXOF creates a new variable-output-length hash. The hash either produce a +// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes +// (size == OutputLengthUnknown). In the latter case, an absolute limit of +// 256GiB applies. +// +// A non-nil key turns the hash into a MAC. The key must between +// zero and 32 bytes long. +func NewXOF(size uint32, key []byte) (XOF, error) { + if len(key) > Size { + return nil, errKeySize + } + if size == magicUnknownOutputLength { + // 2^32-1 indicates an unknown number of bytes and thus isn't a + // valid length. + return nil, errors.New("blake2b: XOF length too large") + } + if size == OutputLengthUnknown { + size = magicUnknownOutputLength + } + x := &xof{ + d: digest{ + size: Size, + keyLen: len(key), + }, + length: size, + } + copy(x.d.key[:], key) + x.Reset() + return x, nil +} + +type xof struct { + d digest + length uint32 + remaining uint64 + cfg, root, block [Size]byte + offset int + nodeOffset uint32 + readMode bool +} + +func (x *xof) Write(p []byte) (n int, err error) { + if x.readMode { + panic("blake2b: write to XOF after read") + } + return x.d.Write(p) +} + +func (x *xof) Clone() XOF { + clone := *x + return &clone +} + +func (x *xof) Reset() { + x.cfg[0] = byte(Size) + binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length + binary.LittleEndian.PutUint32(x.cfg[12:], x.length) // XOF length + x.cfg[17] = byte(Size) // inner hash size + + x.d.Reset() + x.d.h[1] ^= uint64(x.length) << 32 + + x.remaining = uint64(x.length) + if x.remaining == magicUnknownOutputLength { + x.remaining = maxOutputLength + } + x.offset, x.nodeOffset = 0, 0 + x.readMode = false +} + +func (x *xof) Read(p []byte) (n int, err error) { + if !x.readMode { + x.d.finalize(&x.root) + x.readMode = true + } + + if x.remaining == 0 { + return 0, io.EOF + } + + n = len(p) + if uint64(n) > x.remaining { + n = int(x.remaining) + p = p[:n] + } + + if x.offset > 0 { + blockRemaining := Size - x.offset + if n < blockRemaining { + x.offset += copy(p, x.block[x.offset:]) + x.remaining -= uint64(n) + return + } + copy(p, x.block[x.offset:]) + p = p[blockRemaining:] + x.offset = 0 + x.remaining -= uint64(blockRemaining) + } + + for len(p) >= Size { + binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) + x.nodeOffset++ + + x.d.initConfig(&x.cfg) + x.d.Write(x.root[:]) + x.d.finalize(&x.block) + + copy(p, x.block[:]) + p = p[Size:] + x.remaining -= uint64(Size) + } + + if todo := len(p); todo > 0 { + if x.remaining < uint64(Size) { + x.cfg[0] = byte(x.remaining) + } + binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) + x.nodeOffset++ + + x.d.initConfig(&x.cfg) + x.d.Write(x.root[:]) + x.d.finalize(&x.block) + + x.offset = copy(p, x.block[:todo]) + x.remaining -= uint64(todo) + } + return +} + +func (d *digest) initConfig(cfg *[Size]byte) { + d.offset, d.c[0], d.c[1] = 0, 0, 0 + for i := range d.h { + d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:]) + } +} diff --git a/vendor/golang.org/x/crypto/blake2b/register.go b/vendor/golang.org/x/crypto/blake2b/register.go new file mode 100644 index 0000000000..efd689af4b --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/register.go @@ -0,0 +1,32 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.9 + +package blake2b + +import ( + "crypto" + "hash" +) + +func init() { + newHash256 := func() hash.Hash { + h, _ := New256(nil) + return h + } + newHash384 := func() hash.Hash { + h, _ := New384(nil) + return h + } + + newHash512 := func() hash.Hash { + h, _ := New512(nil) + return h + } + + crypto.RegisterHash(crypto.BLAKE2b_256, newHash256) + crypto.RegisterHash(crypto.BLAKE2b_384, newHash384) + crypto.RegisterHash(crypto.BLAKE2b_512, newHash512) +} diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go new file mode 100644 index 0000000000..2f81fe4148 --- /dev/null +++ b/vendor/golang.org/x/crypto/scrypt/scrypt.go @@ -0,0 +1,213 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package scrypt implements the scrypt key derivation function as defined in +// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard +// Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf). +package scrypt // import "golang.org/x/crypto/scrypt" + +import ( + "crypto/sha256" + "errors" + "math/bits" + + "golang.org/x/crypto/pbkdf2" +) + +const maxInt = int(^uint(0) >> 1) + +// blockCopy copies n numbers from src into dst. +func blockCopy(dst, src []uint32, n int) { + copy(dst, src[:n]) +} + +// blockXOR XORs numbers from dst with n numbers from src. +func blockXOR(dst, src []uint32, n int) { + for i, v := range src[:n] { + dst[i] ^= v + } +} + +// salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in, +// and puts the result into both tmp and out. +func salsaXOR(tmp *[16]uint32, in, out []uint32) { + w0 := tmp[0] ^ in[0] + w1 := tmp[1] ^ in[1] + w2 := tmp[2] ^ in[2] + w3 := tmp[3] ^ in[3] + w4 := tmp[4] ^ in[4] + w5 := tmp[5] ^ in[5] + w6 := tmp[6] ^ in[6] + w7 := tmp[7] ^ in[7] + w8 := tmp[8] ^ in[8] + w9 := tmp[9] ^ in[9] + w10 := tmp[10] ^ in[10] + w11 := tmp[11] ^ in[11] + w12 := tmp[12] ^ in[12] + w13 := tmp[13] ^ in[13] + w14 := tmp[14] ^ in[14] + w15 := tmp[15] ^ in[15] + + x0, x1, x2, x3, x4, x5, x6, x7, x8 := w0, w1, w2, w3, w4, w5, w6, w7, w8 + x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15 + + for i := 0; i < 8; i += 2 { + x4 ^= bits.RotateLeft32(x0+x12, 7) + x8 ^= bits.RotateLeft32(x4+x0, 9) + x12 ^= bits.RotateLeft32(x8+x4, 13) + x0 ^= bits.RotateLeft32(x12+x8, 18) + + x9 ^= bits.RotateLeft32(x5+x1, 7) + x13 ^= bits.RotateLeft32(x9+x5, 9) + x1 ^= bits.RotateLeft32(x13+x9, 13) + x5 ^= bits.RotateLeft32(x1+x13, 18) + + x14 ^= bits.RotateLeft32(x10+x6, 7) + x2 ^= bits.RotateLeft32(x14+x10, 9) + x6 ^= bits.RotateLeft32(x2+x14, 13) + x10 ^= bits.RotateLeft32(x6+x2, 18) + + x3 ^= bits.RotateLeft32(x15+x11, 7) + x7 ^= bits.RotateLeft32(x3+x15, 9) + x11 ^= bits.RotateLeft32(x7+x3, 13) + x15 ^= bits.RotateLeft32(x11+x7, 18) + + x1 ^= bits.RotateLeft32(x0+x3, 7) + x2 ^= bits.RotateLeft32(x1+x0, 9) + x3 ^= bits.RotateLeft32(x2+x1, 13) + x0 ^= bits.RotateLeft32(x3+x2, 18) + + x6 ^= bits.RotateLeft32(x5+x4, 7) + x7 ^= bits.RotateLeft32(x6+x5, 9) + x4 ^= bits.RotateLeft32(x7+x6, 13) + x5 ^= bits.RotateLeft32(x4+x7, 18) + + x11 ^= bits.RotateLeft32(x10+x9, 7) + x8 ^= bits.RotateLeft32(x11+x10, 9) + x9 ^= bits.RotateLeft32(x8+x11, 13) + x10 ^= bits.RotateLeft32(x9+x8, 18) + + x12 ^= bits.RotateLeft32(x15+x14, 7) + x13 ^= bits.RotateLeft32(x12+x15, 9) + x14 ^= bits.RotateLeft32(x13+x12, 13) + x15 ^= bits.RotateLeft32(x14+x13, 18) + } + x0 += w0 + x1 += w1 + x2 += w2 + x3 += w3 + x4 += w4 + x5 += w5 + x6 += w6 + x7 += w7 + x8 += w8 + x9 += w9 + x10 += w10 + x11 += w11 + x12 += w12 + x13 += w13 + x14 += w14 + x15 += w15 + + out[0], tmp[0] = x0, x0 + out[1], tmp[1] = x1, x1 + out[2], tmp[2] = x2, x2 + out[3], tmp[3] = x3, x3 + out[4], tmp[4] = x4, x4 + out[5], tmp[5] = x5, x5 + out[6], tmp[6] = x6, x6 + out[7], tmp[7] = x7, x7 + out[8], tmp[8] = x8, x8 + out[9], tmp[9] = x9, x9 + out[10], tmp[10] = x10, x10 + out[11], tmp[11] = x11, x11 + out[12], tmp[12] = x12, x12 + out[13], tmp[13] = x13, x13 + out[14], tmp[14] = x14, x14 + out[15], tmp[15] = x15, x15 +} + +func blockMix(tmp *[16]uint32, in, out []uint32, r int) { + blockCopy(tmp[:], in[(2*r-1)*16:], 16) + for i := 0; i < 2*r; i += 2 { + salsaXOR(tmp, in[i*16:], out[i*8:]) + salsaXOR(tmp, in[i*16+16:], out[i*8+r*16:]) + } +} + +func integer(b []uint32, r int) uint64 { + j := (2*r - 1) * 16 + return uint64(b[j]) | uint64(b[j+1])<<32 +} + +func smix(b []byte, r, N int, v, xy []uint32) { + var tmp [16]uint32 + x := xy + y := xy[32*r:] + + j := 0 + for i := 0; i < 32*r; i++ { + x[i] = uint32(b[j]) | uint32(b[j+1])<<8 | uint32(b[j+2])<<16 | uint32(b[j+3])<<24 + j += 4 + } + for i := 0; i < N; i += 2 { + blockCopy(v[i*(32*r):], x, 32*r) + blockMix(&tmp, x, y, r) + + blockCopy(v[(i+1)*(32*r):], y, 32*r) + blockMix(&tmp, y, x, r) + } + for i := 0; i < N; i += 2 { + j := int(integer(x, r) & uint64(N-1)) + blockXOR(x, v[j*(32*r):], 32*r) + blockMix(&tmp, x, y, r) + + j = int(integer(y, r) & uint64(N-1)) + blockXOR(y, v[j*(32*r):], 32*r) + blockMix(&tmp, y, x, r) + } + j = 0 + for _, v := range x[:32*r] { + b[j+0] = byte(v >> 0) + b[j+1] = byte(v >> 8) + b[j+2] = byte(v >> 16) + b[j+3] = byte(v >> 24) + j += 4 + } +} + +// Key derives a key from the password, salt, and cost parameters, returning +// a byte slice of length keyLen that can be used as cryptographic key. +// +// N is a CPU/memory cost parameter, which must be a power of two greater than 1. +// r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the +// limits, the function returns a nil byte slice and an error. +// +// For example, you can get a derived key for e.g. AES-256 (which needs a +// 32-byte key) by doing: +// +// dk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) +// +// The recommended parameters for interactive logins as of 2017 are N=32768, r=8 +// and p=1. The parameters N, r, and p should be increased as memory latency and +// CPU parallelism increases; consider setting N to the highest power of 2 you +// can derive within 100 milliseconds. Remember to get a good random salt. +func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) { + if N <= 1 || N&(N-1) != 0 { + return nil, errors.New("scrypt: N must be > 1 and a power of 2") + } + if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r { + return nil, errors.New("scrypt: parameters are too large") + } + + xy := make([]uint32, 64*r) + v := make([]uint32, 32*N*r) + b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New) + + for i := 0; i < p; i++ { + smix(b[i*128*r:], r, N, v, xy) + } + + return pbkdf2.Key(password, b, 1, keyLen, sha256.New), nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 91397a577b..539a57697f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -336,12 +336,15 @@ github.com/xanzy/ssh-agent github.com/yohcop/openid-go # golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 golang.org/x/crypto/acme/autocert +golang.org/x/crypto/argon2 golang.org/x/crypto/bcrypt golang.org/x/crypto/pbkdf2 +golang.org/x/crypto/scrypt golang.org/x/crypto/ssh golang.org/x/crypto/acme golang.org/x/crypto/openpgp golang.org/x/crypto/md4 +golang.org/x/crypto/blake2b golang.org/x/crypto/blowfish golang.org/x/crypto/curve25519 golang.org/x/crypto/ed25519 @@ -372,8 +375,8 @@ golang.org/x/oauth2/internal # golang.org/x/sys v0.0.0-20190620070143-6f217b454f45 golang.org/x/sys/windows golang.org/x/sys/windows/svc -golang.org/x/sys/unix golang.org/x/sys/cpu +golang.org/x/sys/unix # golang.org/x/text v0.3.2 golang.org/x/text/transform golang.org/x/text/encoding From f88aa1d21572beafc5a22db0c9712751f47fc0ac Mon Sep 17 00:00:00 2001 From: Mura Li Date: Sun, 7 Jul 2019 15:26:56 +0800 Subject: [PATCH 201/220] Support git.PATH entry in app.ini (#6772) --- custom/conf/app.ini.sample | 2 ++ .../doc/advanced/config-cheat-sheet.en-us.md | 1 + modules/git/git.go | 15 +++++++++++---- modules/setting/git.go | 4 ++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 89c12c42bf..e44cc90a4b 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -670,6 +670,8 @@ SCHEDULE = @every 24h UPDATE_EXISTING = true [git] +; The path of git executable. If empty, Gitea searches through the PATH environment. +PATH = ; Disables highlight of added and removed changes DISABLE_DIFF_HIGHLIGHT = false ; Max number of lines allowed in a single file in diff view diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 128e01b90a..61905f8ad8 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -409,6 +409,7 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` ## Git (`git`) +- `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment. - `MAX_GIT_DIFF_LINES`: **100**: Max number of lines allowed of a single file in diff view. - `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view. - `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view. diff --git a/modules/git/git.go b/modules/git/git.go index fda6f45251..964760dfda 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -77,20 +77,27 @@ func BinVersion() (string, error) { return gitVersion, nil } -func init() { +// SetExecutablePath changes the path of git executable and checks the file permission and version. +func SetExecutablePath(path string) error { + // If path is empty, we use the default value of GitExecutable "git" to search for the location of git. + if path != "" { + GitExecutable = path + } absPath, err := exec.LookPath(GitExecutable) if err != nil { - panic(fmt.Sprintf("Git not found: %v", err)) + return fmt.Errorf("Git not found: %v", err) } GitExecutable = absPath gitVersion, err := BinVersion() if err != nil { - panic(fmt.Sprintf("Git version missing: %v", err)) + return fmt.Errorf("Git version missing: %v", err) } if version.Compare(gitVersion, GitVersionRequired, "<") { - panic(fmt.Sprintf("Git version not supported. Requires version > %v", GitVersionRequired)) + return fmt.Errorf("Git version not supported. Requires version > %v", GitVersionRequired) } + + return nil } // Init initializes git module diff --git a/modules/setting/git.go b/modules/setting/git.go index 4163f1039d..8495be8836 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -16,6 +16,7 @@ import ( var ( // Git settings Git = struct { + Path string DisableDiffHighlight bool MaxGitDiffLines int MaxGitDiffLineCharacters int @@ -59,6 +60,9 @@ func newGit() { if err := Cfg.Section("git").MapTo(&Git); err != nil { log.Fatal("Failed to map Git settings: %v", err) } + if err := git.SetExecutablePath(Git.Path); err != nil { + log.Fatal("Failed to initialize Git settings", err) + } git.DefaultCommandExecutionTimeout = time.Duration(Git.Timeout.Default) * time.Second binVersion, err := git.BinVersion() From fcda2d5b35ec9bec9a8e8fa0a0fb04cb21593648 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 7 Jul 2019 07:29:09 +0000 Subject: [PATCH 202/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 142 ++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index a7d4487ca9..74930d7f2d 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -306,6 +306,7 @@ password_not_match=Las contraseñas no coinciden. username_been_taken=El nombre de usuario ya está en uso. repo_name_been_taken=El nombre del repositorio ya está usado. visit_rate_limit=Limitar tasa a visitas remotas. +2fa_auth_required=Requerir autenticación de doble factor a visitas remotas. org_name_been_taken=Ya existe una organización con este nombre. team_name_been_taken=Ya existe un equipo con este nombre. team_no_units_error=Permitir el acceso a por lo menos una sección del repositorio. @@ -313,6 +314,8 @@ email_been_used=La dirección de correo electrónico ya está usada. openid_been_used=La dirección OpenID '%s' ya está usada. username_password_incorrect=El nombre de usuario o la contraseña son incorrectos. enterred_invalid_repo_name=El nombre de repositorio que ha entrado es incorrecto. +enterred_invalid_owner_name=El nuevo nombre de usuario no es válido. +enterred_invalid_password=La contraseña que ha introducido es incorrecta. user_not_exist=Este usuario no existe. last_org_owner=No puedes eliminar al último usuario del equipo de 'propietarios'. Debe haber al menos un propietario en ningún equipo dado. cannot_add_org_to_team=Una organización no puede ser añadida como miembro de un equipo. @@ -324,6 +327,7 @@ auth_failed=Autenticación fallo: %v still_own_repo=Su cuenta posee uno o más repositorios; elimine o transfiera primero. still_has_org=Su cuenta es miembro de una o más organizaciones; déjalas primero. +org_still_own_repo=Esta organización todavía es dueña de uno o más repositorios; elimínelos o transfiéralos primero. target_branch_not_exist=La rama de destino no existe @@ -333,65 +337,122 @@ join_on=Registrado el repositories=Repositorios activity=Actividad pública followers=Seguidores +starred=Repositorios Favoritos following=Siguiendo follow=Seguir unfollow=Dejar de seguir +heatmap.loading=Cargando mapa de calor… +user_bio=Biografía form.name_reserved=El usuario '%s' está reservado. +form.name_pattern_not_allowed=El patrón '%s' no está permitido en un nombre de usuario. [settings] profile=Perfil +account=Cuenta password=Contraseña security=Seguridad avatar=Avatar ssh_gpg_keys=SSH / claves GPG social=Redes Sociales +applications=Aplicaciones +orgs=Administrar organizaciones repos=Repositorios delete=Eliminar cuenta twofa=Autenticación de doble factor +account_link=Cuentas vinculadas +organization=Organizaciones uid=UUID +u2f=Claves de seguridad public_profile=Perfil público +profile_desc=Su dirección de correo se utilizará para las notificaciones y otras operaciones. +password_username_disabled=Usuarios no locales no tienen permitido cambiar su nombre de usuario. Por favor, contacta con el administrador del sistema para más detalles. full_name=Nombre completo website=Página web location=Localización update_theme=Actualizar tema update_profile=Actualizar perfil update_profile_success=Tu perfil ha sido actualizado. +change_username=Su nombre de usuario ha sido cambiado. +change_username_prompt=Nota: los cambios de nombre de usuario también cambian la URL de su cuenta. continue=Continuar cancel=Cancelar +language=Idioma +ui=Tema +lookup_avatar_by_mail=Buscar avatar por dirección de correo electrónico federated_avatar_lookup=Búsqueda de Avatar Federado enable_custom_avatar=Activar avatar personalizado choose_new_avatar=Selecciona nuevo avatar update_avatar=Actualizar Avatar delete_current_avatar=Eliminar avatar +uploaded_avatar_not_a_image=El archivo subido no es una imagen. +uploaded_avatar_is_too_big=El archivo subido ha excedido el tamaño máximo. update_avatar_success=Su avatar ha sido actualizado. change_password=Actualizar contraseña old_password=Contraseña actual new_password=Nueva contraseña +retype_new_password=Confirmar nueva contraseña password_incorrect=Contraseña actual incorrecta. +change_password_success=Su contraseña ha sido modificada. Utilice su nueva contraseña la próxima vez que acceda a la cuenta. password_change_disabled=Los usuarios no locales no pueden actualizar su contraseña a través de la interfaz web de Gitea. emails=Direcciones de correo electrónico +manage_emails=Administrar direcciones de correo electrónico +manage_themes=Selecciona el tema por defecto +manage_openid=Administrar direcciones OpenID email_desc=Tu dirección de correo principal se utilizará para las notificaciones y otras operaciones. +theme_desc=Este será su tema por defecto en todo el sitio. primary=Principal +primary_email=Hacer primaria +delete_email=Eliminar +email_deletion=Eliminar dirección de correo electrónico +email_deletion_desc=La dirección de correo electrónico e información relacionada se eliminará de su cuenta. Los commits de Git hechos por esta dirección de correo electrónico permanecerán inalterados. ¿Continuar? +email_deletion_success=La dirección de correo electrónico ha sido eliminada. theme_update_success=Su tema fue actualizado. +theme_update_error=El tema seleccionado no existe. +openid_deletion=Eliminar dirección OpenID +openid_deletion_desc=Eliminar esta dirección OpenID de su cuenta le impedirá iniciar sesión con ella. ¿Continuar? +openid_deletion_success=La dirección OpenID ha sido eliminada. +add_new_email=Añadir nueva dirección de correo electrónico +add_new_openid=Añadir nueva dirección OpenID +add_email=Añadir dirección de correo electrónico add_openid=Añadir nuevo OpenID URI +add_email_confirmation_sent=Un correo electrónico de confirmación ha sido enviado a '%s'. Por favor, compruebe su bandeja de entrada durante los próximos %s para confirmar su dirección de correo electrónico. +add_email_success=La nueva dirección de correo electrónico ha sido añadida. +add_openid_success=La nueva dirección OpenID ha sido añadida. +keep_email_private=Ocultar dirección de correo electrónico +keep_email_private_popup=Su dirección de correo electrónico será ocultada de otros usuarios. +openid_desc=OpenID le permite delegar la autenticación a un proveedor externo. manage_ssh_keys=Gestionar Claves SSH manage_gpg_keys=Administrar claves GPG add_key=Añadir Clave +ssh_desc=Estas claves públicas SSH están asociadas con su cuenta. Las correspondientes claves privadas permite acceso completo a sus repositorios. +gpg_desc=Estas claves públicas GPG están asociadas con su cuenta. Mantenga sus claves privadas a salvo, ya que permiten verificar commits. ssh_helper=¿Necesitas ayuda? Echa un vistazo en la guía de GitHub para crear tus propias claves SSH o resolver problemas comunes que puede encontrar al usar SSH. gpg_helper=¿Necesitas ayuda? Echa un vistazo en la guía de GitHub sobre GPG. add_new_key=Añadir clave SSH add_new_gpg_key=Añadir clave GPG +ssh_key_been_used=Esta clave SSH ya ha sido añadida al servidor. +ssh_key_name_used=Una clave SSH con el mismo nombre ya ha sido añadida a su cuenta. +gpg_key_id_used=Ya existe una clave GPG pública con el mismo ID. +gpg_no_key_email_found=Esta clave GPG no es usable con ninguna de las direcciones de correo electrónico asociadas con su cuenta. subkeys=Subclaves key_id=ID de clave key_name=Nombre de la Clave key_content=Contenido +add_key_success=Se ha añadido la clave SSH '%s'. +add_gpg_key_success=Se ha añadido la clave GPG '%s'. +delete_key=Eliminar +ssh_key_deletion=Eliminar clave SSH +gpg_key_deletion=Eliminar clave GPG ssh_key_deletion_desc=Eliminando una clave SSH se revoca su acceso a su cuenta. ¿Continuar? +gpg_key_deletion_desc=Eliminando una clave GPG se des-verifican los commits firmados con ella. ¿Continuar? +ssh_key_deletion_success=La clave SSH ha sido eliminada. +gpg_key_deletion_success=La clave GPG ha sido eliminada. add_on=Añadido en valid_until=Válido hasta valid_forever=Válido para siempre @@ -403,24 +464,66 @@ key_state_desc=Esta clave ha sido usada en los últimos 7 días token_state_desc=Este token ha sido utilizado en los últimos 7 días show_openid=Mostrar mi perfil hide_openid=Esconderse de perfil +ssh_disabled=SSH deshabilitado manage_social=Gestionar Redes Sociales asociadas +social_desc=Estas cuentas sociales están vinculadas a su cuenta de Gitea. Asegúrese de que las reconoce todas, ya que pueden ser usadas para iniciar sesión en su cuenta de Gitea. +unbind=Desvincular +unbind_success=La cuenta social ha sido desvinculada de su cuenta Gitea. +manage_access_token=Administrar Tokens de Acceso generate_new_token=Generar nuevo Token +tokens_desc=Estos tokens otorgan acceso a su cuenta usando la API de Gitea. +new_token_desc=Las aplicaciones que utilizan un token tienen acceso completo a su cuenta. token_name=Nombre del Token generate_token=Generar Token +generate_token_success=Su nuevo token ha sido generado. Cópielo ahora, ya que no se volverá a mostrar. delete_token=Eliminar +access_token_deletion=Eliminar Token de Acceso +access_token_deletion_desc=Eliminando un token revocará el acceso a su cuenta para todas las aplicaciones que lo usen. ¿Continuar? +delete_token_success=El token ha sido eliminado. Las aplicaciones que lo usen ya no tienen acceso a su cuenta. +manage_oauth2_applications=Administrar aplicaciones OAuth2 +edit_oauth2_application=Modificar aplicaciones OAuth2 +oauth2_applications_desc=Las aplicaciones OAuth2 permiten a su aplicación de terceros autenticar de forma segura a los usuarios en esta instancia de Gitea. +remove_oauth2_application=Eliminar aplicación OAuth2 +remove_oauth2_application_desc=Eliminar una aplicación OAuth2 revocará el acceso a todos los tokens de acceso firmados. ¿Continuar? +remove_oauth2_application_success=La aplicación ha sido eliminada. +create_oauth2_application=Crear una nueva aplicación OAuth2 +create_oauth2_application_button=Crear Aplicación +create_oauth2_application_success=Ha creado una nueva aplicación OAuth2 con éxito. update_oauth2_application_success=Ha actualizado correctamente la aplicación OAuth2. +oauth2_application_name=Nombre de la Aplicación +oauth2_select_type=¿Qué tipo de aplicación es? +oauth2_type_web=Web (por ejemplo: Node.JS, Tomcat, Go) +oauth2_type_native=Nativa (por ejemplo, móvil, escritorio, navegador) +oauth2_redirect_uri=URI de redireccionado +save_application=Guardar +oauth2_client_id=ID de cliente +oauth2_client_secret=Secreto de cliente +oauth2_regenerate_secret=Regenerar secreto oauth2_regenerate_secret_hint=¿Ha perdido su secreto? oauth2_client_secret_hint=El secreto no será visible si revisa esta página. Por favor, guarda su secreto. +oauth2_application_edit=Editar +oauth2_application_create_description=Las aplicaciones OAuth2 le dan acceso a su aplicación de terceros a cuentas de usuario en esta instancia. +oauth2_application_remove_description=Eliminar una aplicación OAuth2 impedirá que acceda a cuentas de usuario autorizadas en esta instancia. ¿Continuar? +authorized_oauth2_applications=Aplicaciones OAuth2 autorizadas authorized_oauth2_applications_description=Ha concedido acceso a su cuenta personal de Gitea a estas aplicaciones de terceros. Por favor, revoque el acceso a los aplicaciones que ya no son necesarias. +revoke_key=Revocar +revoke_oauth2_grant=Revocar acceso +revoke_oauth2_grant_description=Revocar el acceso a esta aplicación impedirá que esta aplicación acceda a sus datos. ¿Está seguro? +revoke_oauth2_grant_success=Ha revocado el acceso con éxito. +twofa_desc=La autenticación de doble factor mejora la seguridad de su cuenta. twofa_is_enrolled=Su cuenta actualmente está registrada en la autenticación de doble factor. twofa_not_enrolled=Tu cuenta no está actualmente inscrita en la autenticación de doble factor. +twofa_disable=Deshabilitar autenticación de doble factor twofa_scratch_token_regenerate=Regenerar código de respaldo twofa_scratch_token_regenerated=Su código de respaldo ahora es %s. Guárdelo en un lugar seguro. +twofa_enroll=Inscribirse en la autenticación de doble factor +twofa_disable_note=Puede deshabilitar la autenticación de doble factor si lo necesita. +twofa_disable_desc=Deshabilitar la autenticación de doble factor hará su cuenta menos segura. ¿Continuar? regenerate_scratch_token_desc=Si extravió su código de respaldo, o ya lo usó para iniciar sesión, puede restablecerlo aquí. twofa_disabled=La autenticación de doble factor ha sido deshabilitada. scan_this_image=Analiza esta imagen con la aplicación de autenticación: @@ -429,36 +532,69 @@ then_enter_passcode=E introduzca el código de acceso mostrado en la aplicación passcode_invalid=El código de acceso es incorrecto. Vuelva a intentarlo. twofa_enrolled=Su cuenta ha sido inscrita en la autenticación de doble factor. ¡Guarde su código de respaldo (%s) en un lugar seguro, ya que sólo se muestra una vez! +u2f_desc=Las claves de seguridad son dispositivos hardware que contienen claves criptográficas. Pueden ser usados para la autenticación de doble factor. Las claves de seguridad deben soportar el estándar FIDOU2F. u2f_require_twofa=Su cuenta debe tener activada la autenticación de doble factor para utilizar claves de seguridad. +u2f_register_key=Añadir clave de seguridad +u2f_nickname=Nombre de usuario +u2f_press_button=Pulse el botón en su clave de seguridad para registrarla. +u2f_delete_key=Eliminar clave de seguridad +u2f_delete_key_desc=Si elimina una clave de seguridad no podrá utilizarla para registrarte con ella. ¿Continuar? +manage_account_links=Administrar cuentas vinculadas +manage_account_links_desc=Estas cuentas externas están vinculadas a su cuenta de Gitea. account_links_not_available=Actualmente no hay cuentas externas vinculadas a su cuenta de Gitea. +remove_account_link=Eliminar cuenta vinculada +remove_account_link_desc=Eliminar una cuenta vinculada revocará su acceso a su cuenta de Gitea. ¿Continuar? +remove_account_link_success=La cuenta vinculada ha sido eliminada. orgs_none=No eres miembro de ninguna organización. repos_none=No posees ningún repositorio delete_account=Elimina tu cuenta +delete_prompt=Esta operación eliminará permanentemente su cuenta de usuario. NO podrá deshacerse. confirm_delete_account=Confirmar Eliminación +delete_account_title=Eliminar cuenta de usuario +delete_account_desc=¿Está seguro que desea eliminar permanentemente esta cuenta de usuario? [repo] owner=Propietario repo_name=Nombre del repositorio +repo_name_helper=Un buen nombre de repositorio está compuesto por palabras clave cortas, memorables y únicas. visibility=Visibilidad +visibility_helper=Hacer repositorio privado +visibility_helper_forced=El administrador de su sitio obliga a nuevos repositorios a ser privados. visibility_fork_helper=(Cambiar esto afectará a todos los forks) +clone_helper=¿Necesita ayuda para clonar? Visite Ayuda. fork_repo=Hacer fork del repositorio fork_from=Crear un fork desde +fork_visibility_helper=La visibilidad de un repositorio del cual se ha hecho fork no puede ser cambiada. repo_desc=Descripción repo_lang=Idioma +repo_gitignore_helper=Seleccionar plantillas de .gitignore. license=Licencia +license_helper=Seleccione un archivo de licencia. +readme=LÉAME +readme_helper=Seleccione una plantilla de archivo LÉAME. auto_init=Inicializar el repositorio (añade .gitignore, licencia y README) create_repo=Crear repositorio default_branch=Rama por defecto mirror_prune=Purgar +mirror_prune_desc=Eliminar referencias de seguimiento de remotes obsoletas +mirror_interval=Intervalo de réplica (Las unidades de tiempo válidas son 'h', 'm', 's'). Pone 0 para deshabilitar la sincronización automática. +mirror_interval_invalid=El intervalo de réplica no es válido. +mirror_address=Clonar desde URL +mirror_address_desc=Incluir cualquier credencial de autorización requerida en la URL. Debe ser la url escapada como corresponda +mirror_address_url_invalid=La url proporcionada no es válida. Debe escapar correctamente de todos los componentes de la url. +mirror_address_protocol_invalid=La url proporcionada no es válida. Sólo las ubicaciones http(s):// o git:// pueden ser copiadas desde. +mirror_last_synced=Sincronizado por última vez watchers=Seguidores stargazers=Fans forks=Forks pick_reaction=Escoge tu reacción reactions_more=y %d más +archive.title=Este repositorio está archivado. Puede ver los archivos y clonarlo, pero no puede subir cambios o reportar incidencias ni pedir Pull Requests. +archive.issue.nocomment=Este repositorio está archivado. No se puede comentar en las incidencias. form.reach_limit_of_creation=Ya han alcanzado su límite de repositorios de %d. form.name_reserved=El nombre de repositorio '%s' está reservado. @@ -516,10 +652,16 @@ editor.commit_directly_to_this_branch=Hacer commit directamente en la rama nueva rama
      para este commit y hacer un pull request. editor.cancel=Cancelar editor.branch_already_exists=La rama '%s' ya existe en este repositorio. +editor.file_editing_no_longer_exists=El archivo que está editando, '%s', ya no existe en este repositorio. +editor.file_deleting_no_longer_exists=El archivo que se está eliminando, '%s', ya no existe en este repositorio. +editor.file_changed_while_editing=Desde que comenzó a editar, el contenido del archivo ha sido cambiado. Clic aquí para ver qué ha cambiado o presione confirmar de nuevo para sobrescribir los cambios. +editor.file_already_exists=Ya existe un archivo con nombre '%s' en este repositorio. editor.no_changes_to_show=No existen cambios para mostrar. editor.fail_to_update_file=Error al actualizar/crear el archivo '%s', error: %v +editor.add_subdir=Añadir un directorio… editor.unable_to_upload_files=Error al subir archivos a '%s', error: %v editor.upload_files_to_dir=Subir archivos a '%s' +editor.cannot_commit_to_protected_branch=No se puede hacer commit a la rama protegida '%s'. commits.commits=Commits commits.find=Buscar From 1f1ecda541d7f526c004e7bfabab814dbc84dc2c Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Sun, 7 Jul 2019 22:14:12 -0400 Subject: [PATCH 203/220] Display original author and URL information when showing migrated issues/comments (#7352) * Store original author info for migrated issues and comments Keep original author name for displaying in Gitea interface and also store original author user ID for potential future use in linking accounts from old location. * Add original_url for repo Store the original URL for a migrated repo Clean up migrations/tests * fix migration * fix golangci-lint * make 'make revive' happy also * Modify templates to use OriginalAuthor if set Use the original author name in templates if it is set rather than the user who migrated/currently owns the issues * formatting fixes * make generate-swagger * Use default avatar for imported comments * Remove no longer used IgnoreIssueAuthor option * Add OriginalAuthorID to swagger also --- models/issue.go | 44 ++++++------- models/issue_comment.go | 6 +- models/migrations/migrations.go | 2 + models/migrations/v89.go | 36 +++++++++++ models/repo.go | 15 +++++ modules/migrations/base/comment.go | 1 + modules/migrations/base/issue.go | 1 + modules/migrations/base/options.go | 20 +++--- modules/migrations/base/pullrequest.go | 1 + modules/migrations/base/repo.go | 1 + modules/migrations/gitea.go | 63 ++++++++++--------- modules/migrations/gitea_test.go | 19 +++--- modules/migrations/github.go | 5 +- modules/migrations/github_test.go | 10 +++ modules/migrations/migrate.go | 23 +------ modules/structs/issue.go | 22 ++++--- modules/structs/issue_comment.go | 14 +++-- modules/structs/repo.go | 1 + modules/templates/helper.go | 11 ++++ options/locale/locale_en-US.ini | 2 + public/css/index.css | 3 + public/less/_base.less | 12 ++++ templates/repo/issue/list.tmpl | 5 +- templates/repo/issue/view_content.tmpl | 8 +++ .../repo/issue/view_content/comments.tmpl | 8 +++ templates/repo/issue/view_title.tmpl | 22 +++++-- templates/swagger/v1_json.tmpl | 22 +++++++ templates/user/dashboard/issues.tmpl | 4 +- 28 files changed, 263 insertions(+), 118 deletions(-) create mode 100644 models/migrations/v89.go diff --git a/models/issue.go b/models/issue.go index b5504beb71..63074cd40c 100644 --- a/models/issue.go +++ b/models/issue.go @@ -25,27 +25,29 @@ import ( // Issue represents an issue or pull request of repository. type Issue struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"` - Repo *Repository `xorm:"-"` - Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository. - PosterID int64 `xorm:"INDEX"` - Poster *User `xorm:"-"` - Title string `xorm:"name"` - Content string `xorm:"TEXT"` - RenderedContent string `xorm:"-"` - Labels []*Label `xorm:"-"` - MilestoneID int64 `xorm:"INDEX"` - Milestone *Milestone `xorm:"-"` - Priority int - AssigneeID int64 `xorm:"-"` - Assignee *User `xorm:"-"` - IsClosed bool `xorm:"INDEX"` - IsRead bool `xorm:"-"` - IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not. - PullRequest *PullRequest `xorm:"-"` - NumComments int - Ref string + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"` + Repo *Repository `xorm:"-"` + Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository. + PosterID int64 `xorm:"INDEX"` + Poster *User `xorm:"-"` + OriginalAuthor string + OriginalAuthorID int64 + Title string `xorm:"name"` + Content string `xorm:"TEXT"` + RenderedContent string `xorm:"-"` + Labels []*Label `xorm:"-"` + MilestoneID int64 `xorm:"INDEX"` + Milestone *Milestone `xorm:"-"` + Priority int + AssigneeID int64 `xorm:"-"` + Assignee *User `xorm:"-"` + IsClosed bool `xorm:"INDEX"` + IsRead bool `xorm:"-"` + IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not. + PullRequest *PullRequest `xorm:"-"` + NumComments int + Ref string DeadlineUnix util.TimeStamp `xorm:"INDEX"` diff --git a/models/issue_comment.go b/models/issue_comment.go index c9f1bd9d5f..b930b0b12a 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -101,8 +101,10 @@ const ( type Comment struct { ID int64 `xorm:"pk autoincr"` Type CommentType - PosterID int64 `xorm:"INDEX"` - Poster *User `xorm:"-"` + PosterID int64 `xorm:"INDEX"` + Poster *User `xorm:"-"` + OriginalAuthor string + OriginalAuthorID int64 IssueID int64 `xorm:"INDEX"` Issue *Issue `xorm:"-"` LabelID int64 diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ef43b0453b..62fadf5f36 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -232,6 +232,8 @@ var migrations = []Migration{ NewMigration("add avatar field to repository", addAvatarFieldToRepository), // v88 -> v89 NewMigration("add commit status context field to commit_status", addCommitStatusContext), + // v89 -> v90 + NewMigration("add original author/url migration info to issues, comments, and repo ", addOriginalMigrationInfo), } // Migrate database to current version diff --git a/models/migrations/v89.go b/models/migrations/v89.go new file mode 100644 index 0000000000..83d0b1a8b9 --- /dev/null +++ b/models/migrations/v89.go @@ -0,0 +1,36 @@ +// Copyright 2019 The Gitea 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 migrations + +import "github.com/go-xorm/xorm" + +func addOriginalMigrationInfo(x *xorm.Engine) error { + // Issue see models/issue.go + type Issue struct { + OriginalAuthor string + OriginalAuthorID int64 + } + + if err := x.Sync2(new(Issue)); err != nil { + return err + } + + // Issue see models/issue_comment.go + type Comment struct { + OriginalAuthor string + OriginalAuthorID int64 + } + + if err := x.Sync2(new(Comment)); err != nil { + return err + } + + // Issue see models/repo.go + type Repository struct { + OriginalURL string + } + + return x.Sync2(new(Repository)) +} diff --git a/models/repo.go b/models/repo.go index 59ce18fa88..9bedeba952 100644 --- a/models/repo.go +++ b/models/repo.go @@ -136,6 +136,7 @@ type Repository struct { Name string `xorm:"INDEX NOT NULL"` Description string Website string + OriginalURL string DefaultBranch string NumWatches int @@ -847,6 +848,7 @@ func (repo *Repository) CloneLink() (cl *CloneLink) { type MigrateRepoOptions struct { Name string Description string + OriginalURL string IsPrivate bool IsMirror bool RemoteAddr string @@ -878,6 +880,7 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err repo, err := CreateRepository(doer, u, CreateRepoOptions{ Name: opts.Name, Description: opts.Description, + OriginalURL: opts.OriginalURL, IsPrivate: opts.IsPrivate, IsMirror: opts.IsMirror, }) @@ -1092,6 +1095,7 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { type CreateRepoOptions struct { Name string Description string + OriginalURL string Gitignores string License string Readme string @@ -1358,6 +1362,7 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err Name: opts.Name, LowerName: strings.ToLower(opts.Name), Description: opts.Description, + OriginalURL: opts.OriginalURL, IsPrivate: opts.IsPrivate, IsFsckEnabled: !opts.IsMirror, CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch, @@ -2678,3 +2683,13 @@ func (repo *Repository) DeleteAvatar() error { } return sess.Commit() } + +// GetOriginalURLHostname returns the hostname of a URL or the URL +func (repo *Repository) GetOriginalURLHostname() string { + u, err := url.Parse(repo.OriginalURL) + if err != nil { + return repo.OriginalURL + } + + return u.Host +} diff --git a/modules/migrations/base/comment.go b/modules/migrations/base/comment.go index d89ec3a3f5..38c544d6e0 100644 --- a/modules/migrations/base/comment.go +++ b/modules/migrations/base/comment.go @@ -10,6 +10,7 @@ import "time" // Comment is a standard comment information type Comment struct { IssueIndex int64 + PosterID int64 PosterName string PosterEmail string Created time.Time diff --git a/modules/migrations/base/issue.go b/modules/migrations/base/issue.go index ddadd0c2b3..08d947b05d 100644 --- a/modules/migrations/base/issue.go +++ b/modules/migrations/base/issue.go @@ -10,6 +10,7 @@ import "time" // Issue is a standard issue information type Issue struct { Number int64 + PosterID int64 PosterName string PosterEmail string Title string diff --git a/modules/migrations/base/options.go b/modules/migrations/base/options.go index 262981b933..ba7fdc6815 100644 --- a/modules/migrations/base/options.go +++ b/modules/migrations/base/options.go @@ -12,15 +12,15 @@ type MigrateOptions struct { AuthPassword string Name string Description string + OriginalURL string - Wiki bool - Issues bool - Milestones bool - Labels bool - Releases bool - Comments bool - PullRequests bool - Private bool - Mirror bool - IgnoreIssueAuthor bool // if true will not add original author information before issues or comments content. + Wiki bool + Issues bool + Milestones bool + Labels bool + Releases bool + Comments bool + PullRequests bool + Private bool + Mirror bool } diff --git a/modules/migrations/base/pullrequest.go b/modules/migrations/base/pullrequest.go index 515cab3f91..42456fd314 100644 --- a/modules/migrations/base/pullrequest.go +++ b/modules/migrations/base/pullrequest.go @@ -15,6 +15,7 @@ type PullRequest struct { Number int64 Title string PosterName string + PosterID int64 PosterEmail string Content string Milestone string diff --git a/modules/migrations/base/repo.go b/modules/migrations/base/repo.go index 907d8fc09e..5cfb0de920 100644 --- a/modules/migrations/base/repo.go +++ b/modules/migrations/base/repo.go @@ -15,4 +15,5 @@ type Repository struct { AuthUsername string AuthPassword string CloneURL string + OriginalURL string } diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 1df824c94f..b15aed5f4b 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -82,6 +82,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate r, err := models.MigrateRepository(g.doer, owner, models.MigrateRepoOptions{ Name: g.repoName, Description: repo.Description, + OriginalURL: repo.OriginalURL, IsMirror: repo.IsMirror, RemoteAddr: repo.CloneURL, IsPrivate: repo.IsPrivate, @@ -247,17 +248,19 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { } var is = models.Issue{ - RepoID: g.repo.ID, - Repo: g.repo, - Index: issue.Number, - PosterID: g.doer.ID, - Title: issue.Title, - Content: issue.Content, - IsClosed: issue.State == "closed", - IsLocked: issue.IsLocked, - MilestoneID: milestoneID, - Labels: labels, - CreatedUnix: util.TimeStamp(issue.Created.Unix()), + RepoID: g.repo.ID, + Repo: g.repo, + Index: issue.Number, + PosterID: g.doer.ID, + OriginalAuthor: issue.PosterName, + OriginalAuthorID: issue.PosterID, + Title: issue.Title, + Content: issue.Content, + IsClosed: issue.State == "closed", + IsLocked: issue.IsLocked, + MilestoneID: milestoneID, + Labels: labels, + CreatedUnix: util.TimeStamp(issue.Created.Unix()), } if issue.Closed != nil { is.ClosedUnix = util.TimeStamp(issue.Closed.Unix()) @@ -293,11 +296,13 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { } cms = append(cms, &models.Comment{ - IssueID: issueID, - Type: models.CommentTypeComment, - PosterID: g.doer.ID, - Content: comment.Content, - CreatedUnix: util.TimeStamp(comment.Created.Unix()), + IssueID: issueID, + Type: models.CommentTypeComment, + PosterID: g.doer.ID, + OriginalAuthor: comment.PosterName, + OriginalAuthorID: comment.PosterID, + Content: comment.Content, + CreatedUnix: util.TimeStamp(comment.Created.Unix()), }) // TODO: Reactions @@ -430,18 +435,20 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR HasMerged: pr.Merged, Issue: &models.Issue{ - RepoID: g.repo.ID, - Repo: g.repo, - Title: pr.Title, - Index: pr.Number, - PosterID: g.doer.ID, - Content: pr.Content, - MilestoneID: milestoneID, - IsPull: true, - IsClosed: pr.State == "closed", - IsLocked: pr.IsLocked, - Labels: labels, - CreatedUnix: util.TimeStamp(pr.Created.Unix()), + RepoID: g.repo.ID, + Repo: g.repo, + Title: pr.Title, + Index: pr.Number, + PosterID: g.doer.ID, + OriginalAuthor: pr.PosterName, + OriginalAuthorID: pr.PosterID, + Content: pr.Content, + MilestoneID: milestoneID, + IsPull: true, + IsClosed: pr.State == "closed", + IsLocked: pr.IsLocked, + Labels: labels, + CreatedUnix: util.TimeStamp(pr.Created.Unix()), }, } diff --git a/modules/migrations/gitea_test.go b/modules/migrations/gitea_test.go index 22da7da171..88a3a6d218 100644 --- a/modules/migrations/gitea_test.go +++ b/modules/migrations/gitea_test.go @@ -34,16 +34,15 @@ func TestGiteaUploadRepo(t *testing.T) { Name: repoName, AuthUsername: "", - Wiki: true, - Issues: true, - Milestones: true, - Labels: true, - Releases: true, - Comments: true, - PullRequests: true, - Private: true, - Mirror: false, - IgnoreIssueAuthor: false, + Wiki: true, + Issues: true, + Milestones: true, + Labels: true, + Releases: true, + Comments: true, + PullRequests: true, + Private: true, + Mirror: false, }) assert.NoError(t, err) diff --git a/modules/migrations/github.go b/modules/migrations/github.go index e6b532df9c..93ba108548 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -107,13 +107,13 @@ func (g *GithubDownloaderV3) GetRepoInfo() (*base.Repository, error) { if err != nil { return nil, err } - // convert github repo to stand Repo return &base.Repository{ Owner: g.repoOwner, Name: gr.GetName(), IsPrivate: *gr.Private, Description: gr.GetDescription(), + OriginalURL: gr.GetHTMLURL(), CloneURL: gr.GetCloneURL(), }, nil } @@ -317,6 +317,7 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, allIssues = append(allIssues, &base.Issue{ Title: *issue.Title, Number: int64(*issue.Number), + PosterID: *issue.User.ID, PosterName: *issue.User.Login, PosterEmail: email, Content: body, @@ -359,6 +360,7 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er } allComments = append(allComments, &base.Comment{ IssueIndex: issueNumber, + PosterID: *comment.User.ID, PosterName: *comment.User.Login, PosterEmail: email, Content: *comment.Body, @@ -451,6 +453,7 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq Title: *pr.Title, Number: int64(*pr.Number), PosterName: *pr.User.Login, + PosterID: *pr.User.ID, PosterEmail: email, Content: body, Milestone: milestone, diff --git a/modules/migrations/github_test.go b/modules/migrations/github_test.go index 700183bdc1..0f52a62eb2 100644 --- a/modules/migrations/github_test.go +++ b/modules/migrations/github_test.go @@ -68,6 +68,7 @@ func TestGitHubDownloadRepo(t *testing.T) { Owner: "go-gitea", Description: "Git with a cup of tea, painless self-hosted git service", CloneURL: "https://github.com/go-gitea/gitea.git", + OriginalURL: "https://github.com/go-gitea/gitea", }, repo) milestones, err := downloader.GetMilestones() @@ -180,6 +181,7 @@ func TestGitHubDownloadRepo(t *testing.T) { Title: "Contribution system: History heatmap for user", Content: "Hi guys,\r\n\r\nI think that is a possible feature, a history heatmap similar to github or gitlab.\r\nActually exists a plugin called Calendar HeatMap. I used this on mine project to heat application log and worked fine here.\r\nThen, is only a idea, what you think? :)\r\n\r\nhttp://cal-heatmap.com/\r\nhttps://github.com/wa0x6e/cal-heatmap\r\n\r\nReference: https://github.com/gogits/gogs/issues/1640", Milestone: "1.7.0", + PosterID: 1520407, PosterName: "joubertredrat", State: "closed", Created: time.Date(2016, 11, 02, 18, 51, 55, 0, time.UTC), @@ -209,6 +211,7 @@ func TestGitHubDownloadRepo(t *testing.T) { Title: "display page revisions on wiki", Content: "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991", Milestone: "1.x.x", + PosterID: 1520407, PosterName: "joubertredrat", State: "open", Created: time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC), @@ -238,6 +241,7 @@ func TestGitHubDownloadRepo(t *testing.T) { Title: "audit logs", Content: "Hi,\r\n\r\nI think that is good idea to have user operation log to admin see what the user is doing at Gogs. Similar to example below\r\n\r\n| user | operation | information |\r\n| --- | --- | --- |\r\n| joubertredrat | repo.create | Create repo MyProjectData |\r\n| joubertredrat | user.settings | Edit settings |\r\n| tboerger | repo.fork | Create Fork from MyProjectData to ForkMyProjectData |\r\n| bkcsoft | repo.remove | Remove repo MySource |\r\n| tboerger | admin.auth | Edit auth LDAP org-connection |\r\n\r\nThis resource can be used on user page too, as user activity, set that log row is public (repo._) or private (user._, admin.*) and display only public activity.\r\n\r\nWhat you think?\r\n\r\n[Chat summary from March 14, 2017](https://github.com/go-gitea/gitea/issues/8#issuecomment-286463807)\r\n\r\nReferences:\r\nhttps://github.com/gogits/gogs/issues/3016", Milestone: "1.x.x", + PosterID: 1520407, PosterName: "joubertredrat", State: "open", Created: time.Date(2016, 11, 02, 18, 59, 20, 0, time.UTC), @@ -270,6 +274,7 @@ func TestGitHubDownloadRepo(t *testing.T) { assert.EqualValues(t, []*base.Comment{ { IssueIndex: 6, + PosterID: 4726179, PosterName: "bkcsoft", Created: time.Date(2016, 11, 02, 18, 59, 48, 0, time.UTC), Content: `I would prefer a solution that is in the backend, unless it's required to have it update without reloading. Unfortunately I can't seem to find anything that does that :unamused: @@ -288,6 +293,7 @@ Also this would _require_ caching, since it will fetch huge amounts of data from }, { IssueIndex: 6, + PosterID: 1520407, PosterName: "joubertredrat", Created: time.Date(2016, 11, 02, 19, 16, 56, 0, time.UTC), Content: `Yes, this plugin build on front-end, with backend I don't know too, but we can consider make component for this. @@ -306,6 +312,7 @@ In my case I use ajax to get data, but build on frontend anyway }, { IssueIndex: 6, + PosterID: 1799009, PosterName: "xinity", Created: time.Date(2016, 11, 03, 13, 04, 56, 0, time.UTC), Content: `following @bkcsoft retention strategy in cache is a must if we don't want gitea to waste ressources. @@ -345,6 +352,7 @@ something like in the latest 15days could be enough don't you think ? Title: "Rename import paths: \"github.com/gogits/gogs\" -> \"github.com/go-gitea/gitea\"", Content: "", Milestone: "1.0.0", + PosterID: 7011819, PosterName: "andreynering", State: "closed", Created: time.Date(2016, 11, 02, 17, 01, 19, 0, time.UTC), @@ -380,6 +388,7 @@ something like in the latest 15days could be enough don't you think ? Title: "Fix sender of issue notifications", Content: "It is the FROM field in mailer configuration that needs be used,\r\nnot the USER field, which is for authentication.\r\n\r\nMigrated from https://github.com/gogits/gogs/pull/3616\r\n", Milestone: "1.0.0", + PosterID: 289678, PosterName: "strk", State: "closed", Created: time.Date(2016, 11, 02, 17, 24, 19, 0, time.UTC), @@ -417,6 +426,7 @@ something like in the latest 15days could be enough don't you think ? Title: "Use proper url for libravatar dep", Content: "Fetch go-libravatar from its official source, rather than from an unmaintained fork\r\n", Milestone: "1.0.0", + PosterID: 289678, PosterName: "strk", State: "closed", Created: time.Date(2016, 11, 02, 17, 34, 31, 0, time.UTC), diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 7fc7911f21..a86614c317 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -6,8 +6,6 @@ package migrations import ( - "fmt" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations/base" @@ -155,11 +153,6 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if err != nil { return err } - for _, issue := range issues { - if !opts.IgnoreIssueAuthor { - issue.Content = fmt.Sprintf("Author: @%s \n\n%s", issue.PosterName, issue.Content) - } - } if err := uploader.CreateIssues(issues...); err != nil { return err @@ -175,11 +168,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if err != nil { return err } - for _, comment := range comments { - if !opts.IgnoreIssueAuthor { - comment.Content = fmt.Sprintf("Author: @%s \n\n%s", comment.PosterName, comment.Content) - } - } + allComments = append(allComments, comments...) if len(allComments) >= commentBatchSize { @@ -212,11 +201,6 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - for _, pr := range prs { - if !opts.IgnoreIssueAuthor { - pr.Content = fmt.Sprintf("Author: @%s \n\n%s", pr.PosterName, pr.Content) - } - } if err := uploader.CreatePullRequests(prs...); err != nil { return err } @@ -231,11 +215,6 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if err != nil { return err } - for _, comment := range comments { - if !opts.IgnoreIssueAuthor { - comment.Content = fmt.Sprintf("Author: @%s \n\n%s", comment.PosterName, comment.Content) - } - } allComments = append(allComments, comments...) diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 6d7517bdc7..58fd7344b4 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -29,16 +29,18 @@ type PullRequestMeta struct { // Issue represents an issue in a repository // swagger:model type Issue struct { - ID int64 `json:"id"` - URL string `json:"url"` - Index int64 `json:"number"` - Poster *User `json:"user"` - Title string `json:"title"` - Body string `json:"body"` - Labels []*Label `json:"labels"` - Milestone *Milestone `json:"milestone"` - Assignee *User `json:"assignee"` - Assignees []*User `json:"assignees"` + ID int64 `json:"id"` + URL string `json:"url"` + Index int64 `json:"number"` + Poster *User `json:"user"` + OriginalAuthor string `json:"original_author"` + OriginalAuthorID int64 `json:"original_author_id"` + Title string `json:"title"` + Body string `json:"body"` + Labels []*Label `json:"labels"` + Milestone *Milestone `json:"milestone"` + Assignee *User `json:"assignee"` + Assignees []*User `json:"assignees"` // Whether the issue is open or closed // // type: string diff --git a/modules/structs/issue_comment.go b/modules/structs/issue_comment.go index 185f3910ed..0c8ac20017 100644 --- a/modules/structs/issue_comment.go +++ b/modules/structs/issue_comment.go @@ -10,12 +10,14 @@ import ( // Comment represents a comment on a commit or issue type Comment struct { - ID int64 `json:"id"` - HTMLURL string `json:"html_url"` - PRURL string `json:"pull_request_url"` - IssueURL string `json:"issue_url"` - Poster *User `json:"user"` - Body string `json:"body"` + ID int64 `json:"id"` + HTMLURL string `json:"html_url"` + PRURL string `json:"pull_request_url"` + IssueURL string `json:"issue_url"` + Poster *User `json:"user"` + OriginalAuthor string `json:"original_author"` + OriginalAuthorID int64 `json:"original_author_id"` + Body string `json:"body"` // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time diff --git a/modules/structs/repo.go b/modules/structs/repo.go index b4d162b776..81203319e0 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -31,6 +31,7 @@ type Repository struct { HTMLURL string `json:"html_url"` SSHURL string `json:"ssh_url"` CloneURL string `json:"clone_url"` + OriginalURL string `json:"original_url"` Website string `json:"website"` Stars int `json:"stars_count"` Forks int `json:"forks_count"` diff --git a/modules/templates/helper.go b/modules/templates/helper.go index c4551bb4be..5a3969c098 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -82,6 +82,7 @@ func NewFuncMap() []template.FuncMap { "FileSize": base.FileSize, "Subtract": base.Subtract, "EntryIcon": base.EntryIcon, + "MigrationIcon": MigrationIcon, "Add": func(a, b int) int { return a + b }, @@ -540,3 +541,13 @@ func TrN(lang string, cnt interface{}, key1, keyN string) string { } return keyN } + +// MigrationIcon returns a Font Awesome name matching the service an issue/comment was migrated from +func MigrationIcon(hostname string) string { + switch hostname { + case "github.com": + return "fa-github" + default: + return "fa-git-alt" + } +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 223df91fda..0c83a7aef1 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -621,6 +621,8 @@ migrate.invalid_local_path = "The local path is invalid. It does not exist or is migrate.failed = Migration failed: %v migrate.lfs_mirror_unsupported = Mirroring LFS objects is not supported - use 'git lfs fetch --all' and 'git lfs push --all' instead. migrate.migrate_items_options = When migrating from github, input a username and migration options will be displayed. +migrated_from = Migrated from %[2]s +migrated_from_fake = Migrated From %[1]s mirror_from = mirror of forked_from = forked from diff --git a/public/css/index.css b/public/css/index.css index 437605e1d3..9039409f14 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -137,6 +137,9 @@ a{cursor:pointer} .ui .background.purple{background-color:#6e5494!important} .ui .background.yellow{background-color:#fbbf09!important} .ui .background.gold{background-color:#a1882b!important} +.ui .migrate{color:#888!important;opacity:.5} +.ui .migrate a{color:#444!important} +.ui .migrate a:hover{color:#000!important} .ui .branch-tag-choice{line-height:20px} @media only screen and (max-width:767px){.ui.pagination.menu .item.navigation span.navigation_label,.ui.pagination.menu .item:not(.active):not(.navigation){display:none} } diff --git a/public/less/_base.less b/public/less/_base.less index 4ce1b8eff9..aae3b97c72 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -588,6 +588,18 @@ code, } } + .migrate { + color: #888888 !important; + opacity: 0.5; + a { + color: #444444 !important; + + &:hover { + color: #000000 !important; + } + } + } + .branch-tag-choice { line-height: 20px; } diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 3007c99106..45b2cc67e3 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -234,8 +234,9 @@

      {{ $timeStr := TimeSinceUnix .GetLastEventTimestamp $.Lang }} - - {{if gt .Poster.ID 0}} + {{if .OriginalAuthor }} + {{$.i18n.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor | Safe}} + {{else if gt .Poster.ID 0}} {{$.i18n.Tr .GetLastEventLabel $timeStr .Poster.HomeLink (.Poster.GetDisplayName | Escape) | Safe}} {{else}} {{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 16700a8dc1..b3f88c662d 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -12,12 +12,20 @@

      + {{if .Issue.OriginalAuthor }} + + {{else}} + {{end}}
      + {{if .Issue.OriginalAuthor }} + {{ .Issue.OriginalAuthor }} {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} {{if .Repository.OriginalURL}} ({{$.i18n.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname | Safe }}){{end}} + {{else}} {{.Issue.Poster.GetDisplayName}} {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} + {{end}} {{if not $.Repository.IsArchived}}
      {{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) }} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 20474f6302..68303cf1ca 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -9,12 +9,20 @@ 22 = REVIEW, 23 = ISSUE_LOCKED, 24 = ISSUE_UNLOCKED --> {{if eq .Type 0}}
      + {{if .OriginalAuthor }} + + {{else}} + {{end}}
      + {{if .OriginalAuthor }} + {{ .OriginalAuthor }} {{$.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} {{if $.Repository.OriginalURL}}({{$.i18n.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname | Safe }}){{end}} + {{else}} {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} + {{end}} {{if not $.Repository.IsArchived}}
      {{if gt .ShowTag 0}} diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index 78c892fa4d..4b254d2c4b 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -27,16 +27,28 @@ {{if .Issue.IsPull}} {{if .Issue.PullRequest.HasMerged}} {{ $mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.Lang }} - {{.Issue.PullRequest.Merger.GetDisplayName}} - {{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits .HeadTarget .BaseTarget $mergedStr | Str2html}} + {{if .Issue.OriginalAuthor }} + {{.Issue.OriginalAuthor}} + {{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits .HeadTarget .BaseTarget $mergedStr | Str2html}} + {{else}} + {{.Issue.PullRequest.Merger.GetDisplayName}} + {{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits .HeadTarget .BaseTarget $mergedStr | Str2html}} + {{end}} {{else}} - {{.Issue.Poster.GetDisplayName}} - {{$.i18n.Tr "repo.pulls.title_desc" .NumCommits .HeadTarget .BaseTarget | Str2html}} + {{if .Issue.OriginalAuthor }} + {{.Issue.OriginalAuthor}} + {{$.i18n.Tr "repo.pulls.title_desc" .NumCommits .HeadTarget .BaseTarget | Str2html}} + {{else}} + {{.Issue.Poster.GetDisplayName}} + {{$.i18n.Tr "repo.pulls.title_desc" .NumCommits .HeadTarget .BaseTarget | Str2html}} + {{end}} {{end}} {{else}} {{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.Lang }} - {{if gt .Issue.Poster.ID 0}} + {{if .Issue.OriginalAuthor }} + {{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr .Issue.OriginalAuthor | Safe}} + {{else if gt .Issue.Poster.ID 0}} {{$.i18n.Tr "repo.issues.opened_by" $createdStr .Issue.Poster.HomeLink (.Issue.Poster.GetDisplayName|Escape) | Safe}} {{else}} {{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.Poster.GetDisplayName|Escape) | Safe}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index d6d501ed22..11f4161172 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -6971,6 +6971,15 @@ "type": "string", "x-go-name": "IssueURL" }, + "original_author": { + "type": "string", + "x-go-name": "OriginalAuthor" + }, + "original_author_id": { + "type": "integer", + "format": "int64", + "x-go-name": "OriginalAuthorID" + }, "pull_request_url": { "type": "string", "x-go-name": "PRURL" @@ -8669,6 +8678,15 @@ "format": "int64", "x-go-name": "Index" }, + "original_author": { + "type": "string", + "x-go-name": "OriginalAuthor" + }, + "original_author_id": { + "type": "integer", + "format": "int64", + "x-go-name": "OriginalAuthorID" + }, "pull_request": { "$ref": "#/definitions/PullRequestMeta" }, @@ -9489,6 +9507,10 @@ "format": "int64", "x-go-name": "OpenIssues" }, + "original_url": { + "type": "string", + "x-go-name": "OriginalURL" + }, "owner": { "$ref": "#/definitions/User" }, diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index b69509d799..7083569164 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -93,7 +93,9 @@ {{end}}

      - {{if gt .Poster.ID 0}} + {{if .OriginalAuthor}} + {{$.i18n.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor | Safe}} + {{else if gt .Poster.ID 0}} {{$.i18n.Tr .GetLastEventLabel $timeStr .Poster.HomeLink (.Poster.GetDisplayName|Escape) | Safe}} {{else}} {{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName|Escape) | Safe}} From cb2ec41dce97c9ceb8db97332d1fa600bace3af5 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 8 Jul 2019 02:17:03 +0000 Subject: [PATCH 204/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 340 +++++++++++++++++++++++++++++++- 1 file changed, 338 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 74930d7f2d..b66db93e6c 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -585,7 +585,7 @@ mirror_interval_invalid=El intervalo de réplica no es válido. mirror_address=Clonar desde URL mirror_address_desc=Incluir cualquier credencial de autorización requerida en la URL. Debe ser la url escapada como corresponda mirror_address_url_invalid=La url proporcionada no es válida. Debe escapar correctamente de todos los componentes de la url. -mirror_address_protocol_invalid=La url proporcionada no es válida. Sólo las ubicaciones http(s):// o git:// pueden ser copiadas desde. +mirror_address_protocol_invalid=La url proporcionada no es válida. Sólo las ubicaciones http(s):// o git:// pueden ser replicadas desde. mirror_last_synced=Sincronizado por última vez watchers=Seguidores stargazers=Fans @@ -595,35 +595,56 @@ reactions_more=y %d más archive.title=Este repositorio está archivado. Puede ver los archivos y clonarlo, pero no puede subir cambios o reportar incidencias ni pedir Pull Requests. archive.issue.nocomment=Este repositorio está archivado. No se puede comentar en las incidencias. +archive.pull.nocomment=Este repositorio está archivado. No se puede comentar en los pull requests. form.reach_limit_of_creation=Ya han alcanzado su límite de repositorios de %d. form.name_reserved=El nombre de repositorio '%s' está reservado. +form.name_pattern_not_allowed=El patrón '%s' no está permitido en un nombre de repositorio. +need_auth=Autorización de clonación migrate_type=Tipo de migración migrate_type_helper=Este repositorio será una réplica +migrate_items=Objetos de migración +migrate_items_wiki=Wiki +migrate_items_milestones=Hitos +migrate_items_labels=Etiquetas +migrate_items_issues=Incidencias +migrate_items_pullrequests=Pull Requests +migrate_items_releases=Lanzamientos migrate_repo=Migrar Repositorio +migrate.clone_address=Migrar / Clonar desde URL +migrate.clone_address_desc=La URL HTTP(S) o de Git 'clone' de un repositorio existente +migrate.clone_local_path=o una ruta local del servidor migrate.permission_denied=No te está permitido importar repositorios locales. +migrate.invalid_local_path=La ruta local es inválida. No existe o no es un directorio. migrate.failed=Migración fallida: %v +migrate.lfs_mirror_unsupported=La replicación de objetos LFS no está soportada - use 'git lfs fetch --all' y 'git lfs push --all' en su lugar. +migrate.migrate_items_options=Cuando migra desde github, se mostrarán un nombre de usuario y se mostrarán opciones de migración. -mirror_from=espejo de +mirror_from=réplica de forked_from=forkeado de fork_from_self=No puede hacer fork a un repositorio que ya es suyo. fork_guest_user=Regístrate para forkear este repositorio. copy_link=Copiar +copy_link_success=El enlace ha sido copiado +copy_link_error=Use ⌘ + C o Ctrl-C para copiar copied=Copiado OK unwatch=Dejar de seguir watch=Seguir unstar=Eliminar de favoritos star=Destacar fork=Fork +download_archive=Descargar repositorio no_desc=Sin descripción quick_guide=Guía rápida clone_this_repo=Clonar este repositorio create_new_repo_command=Crear un nuevo repositorio desde línea de comandos push_exist_repo=Hacer push de un repositorio existente desde línea de comandos +empty_message=Este repositorio no contiene ningún contenido. code=Código +code.desc=Acceder código fuente, archivos, commits, y ramas. branch=Rama tree=Árbol filter_branch_and_tag=Filtrar por rama o etiqueta @@ -633,25 +654,54 @@ issues=Incidencias pulls=Peticiones pull labels=Etiquetas milestones=Hitos +commits=Commits +commit=Commit releases=Lanzamientos file_raw=Original file_history=Histórico file_view_raw=Ver original file_permalink=Enlace permanente +file_too_large=El archivo es demasiado grande para ser mostrado. +video_not_supported_in_browser=Su navegador no soporta el tag video de HTML5. +audio_not_supported_in_browser=Su navegador no soporta el tag audio de HTML5. stored_lfs=Almacenados con Git LFS +commit_graph=Gráfico de commits blame=Blame +normal_view=Vista normal +editor.new_file=Nuevo Archivo +editor.upload_file=Subir archivo +editor.edit_file=Editar Archivo editor.preview_changes=Vista previa de los cambios +editor.cannot_edit_lfs_files=Los archivos LFS no se pueden editar en la interfaz web. +editor.cannot_edit_non_text_files=Los archivos binarios no se pueden editar en la interfaz web. +editor.edit_this_file=Editar Archivo +editor.must_be_on_a_branch=Debes estar en una rama para hacer o proponer cambios en este archivo. editor.fork_before_edit=Debes hacer fork a este repositorio para hacer o proponer cambios a este archivo. +editor.delete_this_file=Eliminar archivo +editor.must_have_write_access=Debes tener permisos de escritura para hacer o proponer cambios a este archivo. +editor.file_delete_success=El archivo '%s' ha sido eliminado. +editor.name_your_file=Nombre su archivo… +editor.filename_help=Añade un directorio escribiendo su nombre seguido de una barra ('/'). Para eliminar un directorio, presione la tecla de retroceso al comienzo del campo de entrada. editor.or=o +editor.cancel_lower=Cancelar editor.commit_changes=Crear commit de los cambios +editor.add_tmpl=Añadir '' editor.add=Añadir '%s' editor.update=Actualizar '%s' editor.delete=Eliminar '%s' +editor.commit_message_desc=Añadir una descripción extendida opcional… editor.commit_directly_to_this_branch=Hacer commit directamente en la rama %s. editor.create_new_branch=Crear una nueva rama para este commit y hacer un pull request. +editor.new_branch_name_desc=Nombre de la rama nueva… editor.cancel=Cancelar +editor.filename_cannot_be_empty=El nombre del archivo no puede estar vacío. +editor.filename_is_invalid=El nombre de archivo no es válido: '%s'. +editor.branch_does_not_exist=La rama '%s' no existe en este repositorio. editor.branch_already_exists=La rama '%s' ya existe en este repositorio. +editor.directory_is_a_file=Nombre de directorio '%s' ya se utiliza como un nombre de archivo en este repositorio. +editor.file_is_a_symlink='%s' es un enlace simbólico. Los enlaces simbólicos no se pueden editar en el editor de la web +editor.filename_is_a_directory=Nombre de archivo '%s' ya se utiliza como un nombre de directorio en este repositorio. editor.file_editing_no_longer_exists=El archivo que está editando, '%s', ya no existe en este repositorio. editor.file_deleting_no_longer_exists=El archivo que se está eliminando, '%s', ya no existe en este repositorio. editor.file_changed_while_editing=Desde que comenzó a editar, el contenido del archivo ha sido cambiado. Clic aquí para ver qué ha cambiado o presione confirmar de nuevo para sobrescribir los cambios. @@ -663,17 +713,27 @@ editor.unable_to_upload_files=Error al subir archivos a '%s', error: %v editor.upload_files_to_dir=Subir archivos a '%s' editor.cannot_commit_to_protected_branch=No se puede hacer commit a la rama protegida '%s'. +commits.desc=Ver el historial de cambios de código fuente. commits.commits=Commits +commits.no_commits=No hay commits en común. '%s' y '%s' tienen historias completamente diferentes. +commits.search=Buscar commits… +commits.search.tooltip=Puede prefijar palabras clave con "author:", "committer:", "after:", o "before:", por ejemplo, "revert author:Alice before:2019-04-01". commits.find=Buscar +commits.search_all=Todas las Ramas commits.author=Autor commits.message=Mensaje commits.date=Fecha commits.older=Anterior commits.newer=Posterior commits.signed_by=Firmado por +commits.gpg_key_id=ID de clave GPG +ext_issues=Incidencias externas +ext_issues.desc=Enlace a un gestor de incidencias externo. +issues.desc=Organizar los informes de fallos, tareas e hitos. issues.new=Nueva incidencia +issues.new.title_empty=El título no puede estar vacío issues.new.labels=Etiquetas issues.new.no_label=Sin etiquetas issues.new.clear_labels=Limpiar etiquetas @@ -682,25 +742,40 @@ issues.new.no_milestone=Sin Milestone issues.new.clear_milestone=Limpiar Milestone issues.new.open_milestone=Milestones abiertas issues.new.closed_milestone=Milestones cerradas +issues.new.assignees=Asignados +issues.new.clear_assignees=Limpiar asignados +issues.new.no_assignees=No asignados +issues.no_ref=Ninguna Rama/Etiqueta especificada issues.create=Crear incidencia issues.new_label=Nueva Etiqueta +issues.new_label_placeholder=Nombre etiqueta +issues.new_label_desc_placeholder=Descripción issues.create_label=Crear etiqueta issues.label_templates.title=Carga un conjunto predefinido de etiquetas +issues.label_templates.info=No hay etiquetas existentes todavía. Crea una etiqueta con "Nueva Etiqueta" o use la etiqueta predefinida: issues.label_templates.helper=Seleccionar un conjunto de etiquetas +issues.label_templates.use=Utilice la etiqueta issues.label_templates.fail_to_load_file=Error al cargar el archivo de plantilla de etiqueta '%s': %v +issues.add_label_at=ha añadido la etiqueta

      %s
      %s +issues.remove_label_at=ha eliminado la etiqueta
      %s
      %s issues.add_milestone_at=`ha añadido esto al hito %s %s ' issues.change_milestone_at=`modificó el hito de %s a %s %s` issues.remove_milestone_at=`eliminado esto del %s hito %s ' issues.deleted_milestone=`(eliminado)` issues.self_assign_at=`auto asignado este %s` issues.add_assignee_at='fue asignado por %s %s' +issues.remove_assignee_at=`fue desasignado por %s %s` +issues.remove_self_assignment=`eliminado su asignación %s` issues.change_title_at=`título cambiado de %s a %s %s` issues.delete_branch_at=`rama eliminada %s %s` issues.open_tab=%d abiertas issues.close_tab=%d cerradas issues.filter_label=Etiqueta +issues.filter_label_no_select=Todas las etiquetas issues.filter_milestone=Milestone +issues.filter_milestone_no_select=Todos los hitos issues.filter_assignee=Asignada a +issues.filter_assginee_no_select=Todos los asignados issues.filter_type=Tipo issues.filter_type.all_issues=Todas las incidencias issues.filter_type.assigned_to_you=Asignadas a ti @@ -713,14 +788,25 @@ issues.filter_sort.recentupdate=Actualizada recientemente issues.filter_sort.leastupdate=Actualizada menos recientemente issues.filter_sort.mostcomment=Más comentadas issues.filter_sort.leastcomment=Menos comentadas +issues.filter_sort.nearduedate=Fecha de vencimiento más cercana +issues.filter_sort.farduedate=Fecha de vencimiento más lejana +issues.filter_sort.moststars=Mas estrellas +issues.filter_sort.feweststars=Menor número de estrellas +issues.filter_sort.mostforks=La mayoría de forks +issues.filter_sort.fewestforks=Menor número de forks issues.action_open=Abrir issues.action_close=Cerrar issues.action_label=Etiqueta issues.action_milestone=Hito +issues.action_milestone_no_select=Sin hito issues.action_assignee=Asignado a issues.action_assignee_no_select=Sin asignado issues.opened_by=abierta %[1]s por %[3]s +pulls.merged_by=fusionado %[1]s por %[3]s +pulls.merged_by_fake=fusionado %[1]s por %[2]s +issues.closed_by=cerrado %[1]s por %[3]s issues.opened_by_fake=abierta %[1]s por %[2]s +issues.closed_by_fake=cerrado %[1]s por %[2]s issues.previous=Página Anterior issues.next=Página Siguiente issues.open_title=Abierta @@ -730,7 +816,9 @@ issues.commented_at=`comentado %s` issues.delete_comment_confirm=¿Seguro que deseas eliminar este comentario? issues.no_content=Aún no existe contenido. issues.close_issue=Cerrar +issues.close_comment_issue=Comentar y cerrar issues.reopen_issue=Reabrir +issues.reopen_comment_issue=Comentar y reabrir issues.create_comment=Comentar issues.closed_at=`cerró %[2]s` issues.reopened_at=`reabrió %[2]s` @@ -743,12 +831,18 @@ issues.edit=Editar issues.cancel=Cancelar issues.save=Guardar issues.label_title=Nombre etiqueta +issues.label_description=Descripción de la etiqueta issues.label_color=Color etiqueta issues.label_count=%d etiquetas issues.label_open_issues=%d incidencias abiertas issues.label_edit=Editar issues.label_delete=Borrar +issues.label_modify=Editar etiqueta +issues.label_deletion=Eliminar etiqueta +issues.label_deletion_desc=Eliminar una etiqueta la elimina de todos las incidencias. ¿Continuar? +issues.label_deletion_success=La etiqueta ha sido eliminada. issues.label.filter_sort.alphabetically=Alfabéticamente +issues.label.filter_sort.reverse_alphabetically=Invertir alfabéticamente issues.label.filter_sort.by_size=Tamaño issues.label.filter_sort.reverse_by_size=Tamaño reversa issues.num_participants=%d participantes @@ -756,28 +850,119 @@ issues.attachment.open_tab='Haga clic para ver "%s" en una pestaña nueva' issues.attachment.download=`Haga clic para descargar "%s"` issues.subscribe=Suscribir issues.unsubscribe=Desuscribirse +issues.lock=Bloquear conversación +issues.unlock=Desbloquear conversación +issues.lock.unknown_reason=No se puede bloquear una incidencia con una razón desconocida. +issues.lock_duplicate=Una incidencia no puede ser bloqueada dos veces. +issues.unlock_error=No puede desbloquear una incidencia que no esta bloqueada. +issues.lock_with_reason=bloqueado como %s y conversación limitada a colaboradores %s +issues.lock_no_reason=conversación limitada y bloqueada a los colaboradores %s +issues.unlock_comment=desbloqueó esta conversación %s +issues.lock_confirm=Bloquear +issues.unlock_confirm=Desbloquear +issues.lock.notice_1=- Otros usuarios no pueden añadir nuevos comentarios a esta incidencia. +issues.lock.notice_2=- Usted y otros colaboradores con acceso a este repositorio todavía pueden dejar comentarios que otros pueden ver. issues.lock.notice_3=- Siempre puede desbloquear esta incidencia de nuevo en el futuro. +issues.unlock.notice_1=- Todos podrían comentar esta incidencia de nuevo. issues.unlock.notice_2=- Siempre puede bloquear esta incidencia de nuevo en el futuro. +issues.lock.reason=Motivo del bloqueo +issues.lock.title=Bloquear conversación sobre esta incidencia. +issues.unlock.title=Desbloquear conversación sobre esta incidencia. +issues.comment_on_locked=No puede comentar una incidencia bloqueada. +issues.tracker=Gestor de tiempo issues.start_tracking_short=Iniciar +issues.start_tracking=Inicio de seguimiento de tiempo issues.start_tracking_history=`ha empezado a trabajar %s` +issues.tracker_auto_close=El temporizador se detendrá automáticamente cuando se cierre este problema issues.tracking_already_started='Ya has comenzado el tiempo de seguimiento en este tema!' +issues.stop_tracking=Detener +issues.stop_tracking_history=`dejó de trabajar %s` +issues.add_time=Añadir tiempo gastado manualmente +issues.add_time_short=Añadir tiempo gastado +issues.add_time_cancel=Cancelar +issues.add_time_history=`añadió tiempo gastado %s` issues.add_time_hours=Horas issues.add_time_minutes=Minutos +issues.add_time_sum_to_small=No se ha entrado tiempo. issues.cancel_tracking=Cancelar +issues.cancel_tracking_history=`canceló el seguimiento de tiempo %s` +issues.time_spent_total=Tiempo total gastado +issues.time_spent_from_all_authors=`Tiempo total gastado: %s` +issues.due_date=Fecha de vencimiento +issues.invalid_due_date_format=El formato de la fecha de vencimiento debe ser 'aaaa-mm-dd'. +issues.error_modifying_due_date=Fallo al modificar la fecha de vencimiento. +issues.error_removing_due_date=Fallo al eliminar la fecha de vencimiento. +issues.due_date_form=aaaa-mm-dd +issues.due_date_form_add=Añadir fecha de vencimiento +issues.due_date_form_edit=Editar +issues.due_date_form_remove=Eliminar +issues.due_date_not_writer=Necesita acceso de escritura al repositorio para actualizar la fecha de vencimiento de un issue. +issues.due_date_not_set=Sin fecha de vencimiento. +issues.due_date_added=añadió la fecha de vencimiento %s %s +issues.due_date_modified=modificó la fecha de vencimiento a %s de %s %s +issues.due_date_remove=eliminó la fecha de vencimiento %s %s +issues.due_date_overdue=Vencido +issues.due_date_invalid=La fecha de vencimiento es inválida o está fuera de rango. Por favor utilice el formato 'aaaa-mm-dd'. +issues.dependency.title=Dependencias +issues.dependency.issue_no_dependencies=Esta incidencia actualmente no tiene ninguna dependencia. +issues.dependency.pr_no_dependencies=Este pull request actualmente no tiene ninguna dependencia. +issues.dependency.add=Añadir dependencia… +issues.dependency.cancel=Cancelar +issues.dependency.remove=Eliminar +issues.dependency.remove_info=Eliminar esta dependencia +issues.dependency.added_dependency=`%[2]s ha añadido una nueva dependencia %[3]s` +issues.dependency.removed_dependency=`%[2]s ha eliminado una dependencia %[3]s` +issues.dependency.issue_closing_blockedby=Cerrar este pull request está bloqueado por las siguientes issues +issues.dependency.pr_closing_blockedby=Cierre de esta incidencia es bloqueado por las siguientes incidencias +issues.dependency.issue_close_blocks=Esta incidencia bloquea el cierre de las siguientes incidencias +issues.dependency.pr_close_blocks=Este pull request bloquea el cierre de las siguientes incidencias +issues.dependency.issue_close_blocked=Necesita cerrar todos las incidencias que bloquean esta incidencia antes de que se puede cerrar. +issues.dependency.pr_close_blocked=Necesita cerrar todos las incidencias que bloquean este pull request antes de poder fusionarse. +issues.dependency.blocks_short=Bloque +issues.dependency.blocked_by_short=Depende de +issues.dependency.remove_header=Eliminar dependencia +issues.dependency.issue_remove_text=Esto eliminará la dependencia de esta incidencia. ¿Continuar? +issues.dependency.pr_remove_text=Esto eliminará la dependencia de este pull request. ¿Continuar? +issues.dependency.setting=Habilitar las dependencias para las incidencias y los pull requests +issues.dependency.add_error_same_issue=No se puede hacer que una incidencia dependa de sí misma. +issues.dependency.add_error_dep_issue_not_exist=Incidencia dependiente no existe. +issues.dependency.add_error_dep_not_exist=La dependencia no existe. +issues.dependency.add_error_dep_exists=La dependencia ya existe. +issues.dependency.add_error_cannot_create_circular=No puede crear una depenciena con dos issues que se estan bloqueando mutuamente. +issues.review.self.approval=No puede aprobar su propio pull request. +issues.review.self.rejection=No puede sugerir cambios en su propio pull request. +issues.review.approve=aprobado estos cambios %s +issues.review.comment=revisado %s +issues.review.content.empty=Es necesario dejar un comentario indicando los cambios solicitados. +issues.review.reject=cambios solicitados %s +issues.review.pending=Pendiente +issues.review.review=Revisar +issues.review.reviewers=Revisores +issues.review.show_outdated=Mostrar obsoletos +issues.review.hide_outdated=Ocultar obsoletos +pulls.desc=Habilitar solicitudes de fusión y revisiones de código. pulls.new=Nuevo Pull Request +pulls.compare_changes=Nuevo pull request pulls.filter_branch=Filtrar rama pulls.no_results=Sin resultados. +pulls.nothing_to_compare=Estas ramas son iguales. No hay necesidad para crear un pull request. pulls.create=Crear Pull Request pulls.title_desc=desea fusionar %[1]d commits de %[2]s en %[3]s pulls.merged_title_desc=fusionados %[1]d commits de %[2]s en %[3]s %[4]s pulls.tab_conversation=Conversación pulls.tab_commits=Commits +pulls.tab_files=Archivos modificados pulls.reopen_to_merge=Vuelva a abrir la solicitud de "pull" para realizar una fusión. pulls.merged=Fusionado +pulls.has_merged=El pull request ha sido fusionado. pulls.data_broken=Este pull request está rota debido a que falta información del fork. +pulls.is_checking=La comprobación de conflicto de fusión está en progreso. Inténtalo de nuevo en unos momentos. pulls.can_auto_merge_desc=Este Pull Request puede ser fusionado automáticamente. +pulls.cannot_auto_merge_helper=Combinar manualmente para resolver los conflictos. pulls.merge_pull_request=Fusionar Pull Request +pulls.invalid_merge_option=No puede utilizar esta opción de combinación para esta solicitud de extracción. +pulls.open_unmerged_pull_exists=`No puede realizar la reapertura porque hay un pull request pendiente (#%d) con propiedades idénticas.` pulls.status_checking=Algunas comprobaciones están pendientes pulls.status_checks_success=Todas las comprobaciones han sido exitosas pulls.status_checks_error=Algunas comprobaciones han fallado @@ -789,30 +974,50 @@ milestones.closed=Cerrada %s milestones.no_due_date=Sin fecha límite milestones.open=Abrir milestones.close=Cerrar +milestones.new_subheader=Los hitos organizan las incidencias y el seguimiento del progreso. +milestones.completeness=%d%% Completado milestones.create=Crear hito milestones.title=Título milestones.desc=Descripción milestones.due_date=Fecha límite (opcional) milestones.clear=Limpiar +milestones.invalid_due_date_format=El formato de fecha de vencimiento debe ser 'AAAA-mm-dd'. +milestones.create_success=Se ha creado el hito '%s'. milestones.edit=Editar Milestone +milestones.edit_subheader=Los hitos organizan los problemas y siguen el progreso. milestones.cancel=Cancelar milestones.modify=Actualizar hito milestones.edit_success=El hito '%s' ha sido actualizado. +milestones.deletion=Eliminar hito +milestones.deletion_desc=Eliminando un hito lo elimina de todos los problemas relacionados. ¿Continuar? +milestones.deletion_success=El hito se ha eliminado. +milestones.filter_sort.closest_due_date=Más cerca de la fecha de vencimiento +milestones.filter_sort.furthest_due_date=Más lejos de la fecha de vencimiento +milestones.filter_sort.least_complete=Menos completa milestones.filter_sort.most_complete=Más completa milestones.filter_sort.most_issues=Mayoría de los problemas milestones.filter_sort.least_issues=Menos problemas +ext_wiki=Wiki externa +ext_wiki.desc=Enlace a una wiki externa. wiki=Wiki +wiki.welcome=¡Bienvenidos a la Wiki! +wiki.welcome_desc=Esta wiki le permite escribir y compartir documentación con otros colaboradores. +wiki.desc=Escriba y comparta documentación con colaboradores. +wiki.create_first_page=Crear la primera página wiki.page=Página wiki.filter_page=Filtrar página +wiki.new_page=Página wiki.default_commit_message=Escriba una nota acerca de la actualización de esta página (opcional). wiki.save_page=Guardar página wiki.last_commit_info=%s editó esta página %s wiki.edit_page_button=Editar wiki.new_page_button=Nueva página wiki.delete_page_button=Eliminar página +wiki.delete_page_notice_1=La eliminación de la página wiki '%s' no se puede deshacer. ¿Continuar? wiki.page_already_exists=Ya existe una página con el mismo nombre. +wiki.reserved_page=El nombre de la página wiki '%s' ya está reservado. wiki.pages=Páginas wiki.last_updated=Última actualización %s @@ -826,8 +1031,22 @@ activity.overview=Resumen activity.active_prs_count_1=%d Solicitud de extracción Activa activity.active_prs_count_n=%d Solicitudes "pull" activas activity.merged_prs_count_1=Solicitud de extracción combinada +activity.merged_prs_count_n=Pull Requests Fusionados +activity.opened_prs_count_1=Pull Request Propuesta +activity.opened_prs_count_n=Pull Requests Propuestas +activity.title.user_1=%d usuario +activity.title.user_n=%d usuarios +activity.title.prs_1=%d Pull request +activity.title.prs_n=%d Pull requests +activity.title.prs_merged_by=%s fusionado por %s +activity.title.prs_opened_by=%s propuesto por %s +activity.merged_prs_label=Fusionado +activity.opened_prs_label=Propuesto +activity.active_issues_count_1=%d Incidencia activa +activity.active_issues_count_n=%d Incidencias activas activity.closed_issues_count_1=Incidencia cerrada activity.closed_issues_count_n=Incidencias cerradas +activity.title.issues_1=%d Incidencia activity.title.issues_n=%d incidencias activity.title.issues_closed_by=%s cerrada por %s activity.title.issues_created_by=%s creada por %s @@ -835,13 +1054,35 @@ activity.closed_issue_label=Cerrada activity.new_issues_count_1=Nueva incidencia activity.new_issues_count_n=Nuevas incidencias activity.new_issue_label=Abierta +activity.title.unresolved_conv_1=%d Conversación no resuelta +activity.title.unresolved_conv_n=%d conversaciones sin resolver +activity.unresolved_conv_desc=Estas incidencias y pull requests que han cambiado recientemente todavía no han sido resueltos. +activity.unresolved_conv_label=Abierta +activity.title.releases_1=%d Lanzamiento +activity.title.releases_n=%d Lanzamientos +activity.title.releases_published_by=%s publicado por %s +activity.published_release_label=Publicado activity.no_git_activity=No ha habido ningún commit en este período. +activity.git_stats_exclude_merges=Excluyendo fusiones, activity.git_stats_author_1=%d autor activity.git_stats_author_n=%d autores +activity.git_stats_pushed_1=ha empujado +activity.git_stats_pushed_n=han empujado activity.git_stats_commit_1=%d commit +activity.git_stats_commit_n=%d commits +activity.git_stats_push_to_branch=a %s y +activity.git_stats_push_to_all_branches=en todas las ramas. activity.git_stats_on_default_branch=En %s, activity.git_stats_file_1=%d archivo activity.git_stats_file_n=%d archivos +activity.git_stats_files_changed_1=ha cambiado +activity.git_stats_files_changed_n=han cambiado +activity.git_stats_additions=y ha habido +activity.git_stats_addition_1=%d adición +activity.git_stats_addition_n=%d adiciones +activity.git_stats_and_deletions=y +activity.git_stats_deletion_1=%d eliminación +activity.git_stats_deletion_n=%d eliminaciones search=Buscar search.search_repo=Buscar repositorio @@ -849,6 +1090,9 @@ search.results=Resultados de la búsqueda para "%s" en %s settings=Configuración settings.desc=La configuración es donde puede administrar la configuración del repositorio +settings.options=Repositorio +settings.collaboration=Colaboradores +settings.collaboration.admin=Administrador settings.collaboration.write=Escritura settings.collaboration.read=Lectura settings.collaboration.undefined=Indefinido @@ -856,37 +1100,119 @@ settings.hooks=Webhooks settings.githooks=Git Hooks settings.basic_settings=Configuración Básica settings.mirror_settings=Configuración de réplica +settings.sync_mirror=Sincronizar ahora +settings.mirror_sync_in_progress=La sincronización del repositorio replicado está en curso. Vuelva a intentarlo más tarde. +settings.site=Sitio web settings.update_settings=Actualizar configuración settings.advanced_settings=Ajustes avanzados +settings.wiki_desc=Activar Wiki de repositorio +settings.use_internal_wiki=Usar Wiki integrada +settings.use_external_wiki=Usar Wiki externa settings.external_wiki_url=URL externa de la Wiki +settings.external_wiki_url_error=La URL de la Wiki externa no es una URL válida. +settings.external_wiki_url_desc=Los visitantes serán redirigidos a la URL de la Wiki externa al hacer click en la pestaña de la Wiki. +settings.issues_desc=Activar gestor de incidencias para este repositorio +settings.use_internal_issue_tracker=Usar gestor de incidencias integrado +settings.use_external_issue_tracker=Usar gestor de incidencias externo +settings.external_tracker_url=URL del gestor de incidencias externo +settings.external_tracker_url_error=La URL del gestor de incidencias externo no es una URL válida. +settings.external_tracker_url_desc=Los visitantes serán redirigidos a la URL del gestor de incidencias externo al hacer click en la pestaña de Incidencias. settings.tracker_url_format=Formato URL del tracker de incidencias externo +settings.tracker_url_format_error=El formato de la URL del gestor de incidencias externo no es válido. +settings.tracker_issue_style=Formato numérico del gestor de incidencias externo settings.tracker_issue_style.numeric=Numérico settings.tracker_issue_style.alphanumeric=Alfanumérico +settings.tracker_url_format_desc=Utilice los marcadores {user}, {repo} y {index} para designar el usuario, el nombre del repositorio y el índice de incidencia. +settings.enable_timetracker=Habilitar gestor de tiempo +settings.allow_only_contributors_to_track_time=Deje que solo los colaboradores hagan un seguimiento del tiempo +settings.pulls_desc=Activar Pull Requests para este repositorio +settings.pulls.ignore_whitespace=Ignorar espacios en blanco en conflictos +settings.pulls.allow_merge_commits=Activar Commit Fusionar +settings.pulls.allow_rebase_merge=Activar Rebase de los commits fusionados +settings.pulls.allow_rebase_merge_commit=Activar Rebase con commits explícitos de fusión (--no-ff) +settings.pulls.allow_squash_commits=Activar Squash en los commits fusionados +settings.admin_settings=Ajustes de administrador +settings.admin_enable_health_check=Activar cheques de estado de salud del repositorio (git fsck) +settings.admin_enable_close_issues_via_commit_in_any_branch=Cerrar una incidencia a través de un commit realizado en una rama no principal settings.danger_zone=Zona de Peligro settings.new_owner_has_same_repo=El nuevo propietario tiene un repositorio con el mismo nombre. +settings.convert=Convertir en repositorio normal +settings.convert_desc=Puede convertir este respositorio replicado en un repositorio normal. Esta acción no se puede revertir. +settings.convert_notices_1=Esta operación convertirá el repositorio replicado en un repositorio normal y no puede deshacerse. +settings.convert_confirm=Convertir repositorio +settings.convert_succeed=El repositorio replicado ha sido convertido en un repositorio normal. settings.transfer=Transferir la propiedad +settings.wiki_delete_notices_1=- Esto eliminará y desactivará permanentemente el wiki del repositorio para %s. +settings.confirm_wiki_delete=Eliminar los datos del Wiki +settings.wiki_deletion_success=La wiki del repositorio ha sido eliminada. settings.delete=Eliminar este repositorio +settings.delete_desc=Eliminar un repositorio es permanente y no se puede deshacer. settings.delete_notices_1=- Esta operación NO PUEDE revertirse. +settings.delete_notices_2=- Esta operación eliminará permanentemente todo en el repositorio de %s, incluidas asociaciones de código, problemas, comentarios, wiki y colaboradores. settings.delete_notices_fork_1=Los forks de este repositorio serán independientes después de eliminarlo. +settings.deletion_success=El repositorio ha sido eliminado. +settings.update_settings_success=Las opciones del repositorio han sido actualizadas. settings.transfer_owner=Nuevo Propietario +settings.make_transfer=Realizar Transferencia +settings.transfer_succeed=El repositorio ha sido transferido. +settings.confirm_delete=Eliminar este repositorio +settings.add_collaborator=Añadir colaborador +settings.add_collaborator_success=El nuevo colaborador ha sido añadido. +settings.add_collaborator_inactive_user=No se puede añadir un usuario inactivo como colaborador. +settings.add_collaborator_duplicate=El colaborador ya está añadido a este repositorio. +settings.delete_collaborator=Eliminar +settings.collaborator_deletion=Eliminar colaborador +settings.collaborator_deletion_desc=Eliminar un colaborador revocará su acceso a este repositorio. ¿Continuar? +settings.remove_collaborator_success=El colaborador ha sido eliminado. +settings.search_user_placeholder=Buscar usuario… +settings.org_not_allowed_to_be_collaborator=Las organizaciones no pueden ser añadidas como colaboradoras. settings.add_webhook=Añadir Webhook +settings.add_webhook.invalid_channel_name=El nombre del canal Webhook no puede estar vacío y no puede contener sólo un # carácter. +settings.hooks_desc=Los webhooks automáticamente hacen peticiones HTTP POST a un servidor cuando ciertos eventos de Gitea se activan. Lee más en la guía de webhooks. +settings.webhook_deletion=Eliminar Webhook +settings.webhook_deletion_desc=Eliminar un webhook borra sus ajustes e historial de entrega. ¿Continuar? +settings.webhook_deletion_success=El webhook ha sido eliminado. settings.webhook.test_delivery=Test de entrega +settings.webhook.test_delivery_desc=Prueba este webhook con un evento falso. +settings.webhook.test_delivery_success=Se ha añadido un evento falso a la cola. Puede tardar unos segundos antes de que se muestre en el historial de entrega. settings.webhook.request=Petición settings.webhook.response=Respuesta settings.webhook.headers=Encabezado +settings.webhook.payload=Contenido settings.webhook.body=Cuerpo del mensaje +settings.githooks_desc=Los hooks de Git son ejecutados por el propio Git. Puede editar los archivos de hooks a continuación para configurar operaciones personalizadas. settings.githook_edit_desc=Si el hook no está activo, se mostrará contenido de ejemplo. Dejar el contenido vacío deshabilitará este hook. settings.githook_name=Nombre del Hook settings.githook_content=Contenido del Hook settings.update_githook=Actualizar Hook +settings.add_webhook_desc=Gitea enviará solicitudes POST con un tipo de contenido especificado a la URL de destino. Leer más en la guía webhooks. +settings.payload_url=Url destino +settings.http_method=Método HTTP +settings.content_type=Tipo de contenido POST settings.secret=Secreto settings.slack_username=Nombre de usuario settings.slack_icon_url=URL de icono settings.discord_username=Usuario settings.discord_icon_url=URL de icono settings.slack_color=Color +settings.event_desc=Activar: +settings.event_push_only=Eventos Push +settings.event_send_everything=Todos los eventos +settings.event_choose=Eventos personalizados… settings.event_create=Crear +settings.event_create_desc=Rama o etiqueta creada. +settings.event_delete=Eliminar +settings.event_delete_desc=Rama o etiqueta eliminada +settings.event_fork=Fork settings.event_fork_desc=Repositorio forkeado +settings.event_issues=Incidencias +settings.event_issues_desc=Incidencia abierta, cerrada, reabierta, editada, asignada, desasignada, etiqueta actualizada, etiqueta limpiada, hito marcado, o desmarcado. +settings.event_issue_comment=Comentario de incidencia +settings.event_issue_comment_desc=Comentario de incidencias creado, editado o borrado. +settings.event_release=Lanzamiento +settings.event_release_desc=Lanzamiento publicado, actualizado o eliminado en un repositorio. +settings.event_pull_request=Pull Request +settings.event_pull_request_desc=Pull Request abierta, cerrada, reabierta, editada, aprobada, rechazada, comentario de revisión, asignada, no asignada, etiqueta actualizada, etiqueta borrada o sincronizada. settings.update_webhook=Actualizar Webhook settings.recent_deliveries=Envíos Recientes settings.hook_type=Tipo de Hook @@ -897,9 +1223,15 @@ settings.deploy_keys=Claves de Despliegue settings.add_deploy_key=Añadir Clave de Despliegue settings.title=Título settings.deploy_key_content=Contenido +settings.branch_protection=Proteccion de la rama '%s' +settings.protect_this_branch=Activar protección de rama +settings.protect_whitelist_search_users=Buscar usuarios… +settings.protect_whitelist_search_teams=Buscar equipos… settings.protect_merge_whitelist_committers_desc=Permitir a los usuarios o equipos de la lista a fusionar peticiones pull dentro de esta rama. +settings.protect_required_approvals=Aprobaciones requeridas: settings.add_protected_branch=Activar protección settings.delete_protected_branch=Desactivar protección +settings.archive.error_ismirror=No puede archivar un repositorio replicado. diff.browse_source=Explorar el Código diff.parent=padre @@ -1003,6 +1335,7 @@ first_page=Primera last_page=Última dashboard.system_status=Estado del sistema +dashboard.statistic_info=La base de datos de Gitea contiene %d usuarios, %d organizaciones, %d claves públicas, %d repositorios, %d elementos observados, %d destacados, %d acciones, %d accesos, %d incidencias, %d comentarios, %d cuentas sociales, %d seguidos, %d réplicas, %d releases, %d orígenes de autenticación, %d webhooks, %d milestones, %d etiquetas, %d tareas de hook, %d equipos, %d tareas de actualización, %d adjuntos. dashboard.operation_name=Nombre de la operación dashboard.operation_switch=Interruptor dashboard.operation_run=Ejecutar @@ -1202,6 +1535,9 @@ merge_pull_request=`fusionado pull request %s#%[2]s` transfer_repo=transfirió el repositorio %s a %s delete_tag=etiqueta eliminada %[2]s de %[3]s delete_branch=rama %[2]s eliminada, de %[3]s +mirror_sync_push=sincronizó cambios a %[3]s en %[4]s desde réplica +mirror_sync_create=sincronizada nueva referencia %[2]s a %[3]s desde réplica +mirror_sync_delete=sincronizada y eliminada referencia %[2]s en %[3]s desde réplica [tool] ago=hace %s From ff85a6331e02338100e3799b5787bf8b686fe003 Mon Sep 17 00:00:00 2001 From: quantonganh Date: Mon, 8 Jul 2019 14:32:46 +0700 Subject: [PATCH 205/220] only return head: null if source branch was deleted (#6705) * only return head: null if source branch was deleted * add URL into GetPullRequest * TestPullRequest_APIFormat * log error if it is not Err(Branch)NotExist --- models/pull.go | 90 +++++++++++++++++++++++++++++---------------- models/pull_test.go | 10 ++++- 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/models/pull.go b/models/pull.go index 6ee2ec555d..7dd6050c67 100644 --- a/models/pull.go +++ b/models/pull.go @@ -189,36 +189,6 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest { return nil } } - if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil { - log.Error("pr.BaseRepo.GetBranch[%d]: %v", pr.BaseBranch, err) - return nil - } - if baseCommit, err = baseBranch.GetCommit(); err != nil { - log.Error("baseBranch.GetCommit[%d]: %v", pr.ID, err) - return nil - } - if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil { - log.Error("pr.HeadRepo.GetBranch[%d]: %v", pr.HeadBranch, err) - return nil - } - if headCommit, err = headBranch.GetCommit(); err != nil { - log.Error("headBranch.GetCommit[%d]: %v", pr.ID, err) - return nil - } - apiBaseBranchInfo := &api.PRBranchInfo{ - Name: pr.BaseBranch, - Ref: pr.BaseBranch, - Sha: baseCommit.ID.String(), - RepoID: pr.BaseRepoID, - Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false), - } - apiHeadBranchInfo := &api.PRBranchInfo{ - Name: pr.HeadBranch, - Ref: pr.HeadBranch, - Sha: headCommit.ID.String(), - RepoID: pr.HeadRepoID, - Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false), - } if err = pr.Issue.loadRepo(e); err != nil { log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err) @@ -227,6 +197,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest { apiPullRequest := &api.PullRequest{ ID: pr.ID, + URL: pr.Issue.HTMLURL(), Index: pr.Index, Poster: apiIssue.Poster, Title: apiIssue.Title, @@ -241,13 +212,68 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest { DiffURL: pr.Issue.DiffURL(), PatchURL: pr.Issue.PatchURL(), HasMerged: pr.HasMerged, - Base: apiBaseBranchInfo, - Head: apiHeadBranchInfo, MergeBase: pr.MergeBase, Deadline: apiIssue.Deadline, Created: pr.Issue.CreatedUnix.AsTimePtr(), Updated: pr.Issue.UpdatedUnix.AsTimePtr(), } + baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch) + if err != nil { + if git.IsErrBranchNotExist(err) { + apiPullRequest.Base = nil + } else { + log.Error("GetBranch[%s]: %v", pr.BaseBranch, err) + return nil + } + } else { + apiBaseBranchInfo := &api.PRBranchInfo{ + Name: pr.BaseBranch, + Ref: pr.BaseBranch, + RepoID: pr.BaseRepoID, + Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false), + } + baseCommit, err = baseBranch.GetCommit() + if err != nil { + if git.IsErrNotExist(err) { + apiBaseBranchInfo.Sha = "" + } else { + log.Error("GetCommit[%s]: %v", baseBranch.Name, err) + return nil + } + } else { + apiBaseBranchInfo.Sha = baseCommit.ID.String() + } + apiPullRequest.Base = apiBaseBranchInfo + } + + headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch) + if err != nil { + if git.IsErrBranchNotExist(err) { + apiPullRequest.Head = nil + } else { + log.Error("GetBranch[%s]: %v", pr.HeadBranch, err) + return nil + } + } else { + apiHeadBranchInfo := &api.PRBranchInfo{ + Name: pr.HeadBranch, + Ref: pr.HeadBranch, + RepoID: pr.HeadRepoID, + Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false), + } + headCommit, err = headBranch.GetCommit() + if err != nil { + if git.IsErrNotExist(err) { + apiHeadBranchInfo.Sha = "" + } else { + log.Error("GetCommit[%s]: %v", headBranch.Name, err) + return nil + } + } else { + apiHeadBranchInfo.Sha = headCommit.ID.String() + } + apiPullRequest.Head = apiHeadBranchInfo + } if pr.Status != PullRequestStatusChecking { mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress() diff --git a/models/pull_test.go b/models/pull_test.go index 5a53474ac4..df051d51bc 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -31,7 +31,15 @@ func TestPullRequest_LoadIssue(t *testing.T) { assert.Equal(t, int64(2), pr.Issue.ID) } -// TODO TestPullRequest_APIFormat +func TestPullRequest_APIFormat(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + pr := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest) + assert.NoError(t, pr.LoadAttributes()) + assert.NoError(t, pr.LoadIssue()) + apiPullRequest := pr.APIFormat() + assert.NotNil(t, apiPullRequest) + assert.Nil(t, apiPullRequest.Head) +} func TestPullRequest_GetBaseRepo(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) From d7211c5b5d90a3e6bc9c1550e2c0bf7d0d9ad66f Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 8 Jul 2019 07:34:55 +0000 Subject: [PATCH 206/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index b66db93e6c..1fc32f7190 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1229,8 +1229,13 @@ settings.protect_whitelist_search_users=Buscar usuarios… settings.protect_whitelist_search_teams=Buscar equipos… settings.protect_merge_whitelist_committers_desc=Permitir a los usuarios o equipos de la lista a fusionar peticiones pull dentro de esta rama. settings.protect_required_approvals=Aprobaciones requeridas: +settings.protect_approvals_whitelist_users=Lista blanca de usuarios revisores: +settings.protect_approvals_whitelist_teams=Lista blanca de equipos revisores: settings.add_protected_branch=Activar protección settings.delete_protected_branch=Desactivar protección +settings.update_protect_branch_success=La protección de la rama '%s' ha sido actualizada. +settings.remove_protected_branch_success=La protección de la rama '%s' ha sido desactivada. +settings.protected_branch_deletion=Desactivar protección de rama settings.archive.error_ismirror=No puede archivar un repositorio replicado. diff.browse_source=Explorar el Código From e5b247ea8e77689bb14e5f304ada36f9326f0904 Mon Sep 17 00:00:00 2001 From: Cherrg Date: Mon, 8 Jul 2019 10:20:22 +0200 Subject: [PATCH 207/220] wiki - page revisions list (#7369) fix #7 * add wiki page revision list * mobile improvements * css improvements for long usernames * split renderWikiPage into 3 functions Signed-off-by: Michael Gnehr --- options/locale/locale_en-US.ini | 3 + public/css/index.css | 5 + public/less/_markdown.less | 32 ++++ routers/repo/wiki.go | 266 ++++++++++++++++++++++-------- routers/routes/routes.go | 1 + templates/repo/wiki/revision.tmpl | 104 ++++++++++++ templates/repo/wiki/view.tmpl | 1 + 7 files changed, 341 insertions(+), 71 deletions(-) create mode 100644 templates/repo/wiki/revision.tmpl diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 0c83a7aef1..6ef1277c62 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1034,6 +1034,9 @@ wiki.save_page = Save Page wiki.last_commit_info = %s edited this page %s wiki.edit_page_button = Edit wiki.new_page_button = New Page +wiki.file_revision = Page Revision +wiki.wiki_page_revisions = Wiki Page Revisions +wiki.back_to_wiki = Back to wiki page wiki.delete_page_button = Delete Page wiki.delete_page_notice_1 = Deleting the wiki page '%s' cannot be undone. Continue? wiki.page_already_exists = A wiki page with the same name already exists. diff --git a/public/css/index.css b/public/css/index.css index 9039409f14..b948766b41 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -290,6 +290,11 @@ footer .ui.left,footer .ui.right{line-height:40px} .markdown:not(code) .csv-data tr{border-top:0} .markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0} .markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em} +.repository.wiki.revisions .ui.container>.ui.stackable.grid{flex-direction:row-reverse} +.repository.wiki.revisions .ui.container>.ui.stackable.grid>.header{margin-top:0} +.repository.wiki.revisions .ui.container>.ui.stackable.grid>.header .sub.header{padding-left:52px} +.file-revisions-btn{display:block;float:left;margin-bottom:2px!important;padding:11px!important;margin-right:10px!important} +.file-revisions-btn i{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} .home .logo{max-width:220px} @media only screen and (max-width:767px){.home .hero h1{font-size:3.5em} .home .hero h2{font-size:2em} diff --git a/public/less/_markdown.less b/public/less/_markdown.less index e971248f6f..1dcc2caf94 100644 --- a/public/less/_markdown.less +++ b/public/less/_markdown.less @@ -494,3 +494,35 @@ padding-left: 2em; } } + +.repository.wiki.revisions { + .ui.container > .ui.stackable.grid { + -ms-flex-direction: row-reverse; + flex-direction: row-reverse; + + > .header { + margin-top: 0; + + .sub.header { + padding-left: 52px; + } + } + } +} + +.file-revisions-btn { + display: block; + float: left; + margin-bottom: 2px !important; + padding: 11px !important; + margin-right: 10px !important; + + i { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } +} diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go index 43149c0340..0fdf853630 100644 --- a/routers/repo/wiki.go +++ b/routers/repo/wiki.go @@ -23,10 +23,11 @@ import ( ) const ( - tplWikiStart base.TplName = "repo/wiki/start" - tplWikiView base.TplName = "repo/wiki/view" - tplWikiNew base.TplName = "repo/wiki/new" - tplWikiPages base.TplName = "repo/wiki/pages" + tplWikiStart base.TplName = "repo/wiki/start" + tplWikiView base.TplName = "repo/wiki/view" + tplWikiRevision base.TplName = "repo/wiki/revision" + tplWikiNew base.TplName = "repo/wiki/new" + tplWikiPages base.TplName = "repo/wiki/pages" ) // MustEnableWiki check if wiki is enabled, if external then redirect @@ -107,18 +108,20 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte { // wikiContentsByName returns the contents of a wiki page, along with a boolean // indicating whether the page exists. Writes to ctx if an error occurs. -func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, bool) { - entry, err := findEntryForFile(commit, models.WikiNameToFilename(wikiName)) - if err != nil { +func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string, bool) { + var entry *git.TreeEntry + var err error + pageFilename := models.WikiNameToFilename(wikiName) + if entry, err = findEntryForFile(commit, pageFilename); err != nil { ctx.ServerError("findEntryForFile", err) - return nil, false + return nil, nil, "", false } else if entry == nil { - return nil, false + return nil, nil, "", true } - return wikiContentsByEntry(ctx, entry), true + return wikiContentsByEntry(ctx, entry), entry, pageFilename, false } -func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *git.TreeEntry) { +func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { wikiRepo, commit, err := findWikiRepoCommit(ctx) if err != nil { if !git.IsErrNotExist(err) { @@ -128,88 +131,176 @@ func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *gi } // Get page list. - if isViewPage { - entries, err := commit.ListEntries() - if err != nil { - ctx.ServerError("ListEntries", err) - return nil, nil - } - pages := make([]PageMeta, 0, len(entries)) - for _, entry := range entries { - if !entry.IsRegular() { - continue - } - wikiName, err := models.WikiFilenameToName(entry.Name()) - if err != nil { - if models.IsErrWikiInvalidFileName(err) { - continue - } - ctx.ServerError("WikiFilenameToName", err) - return nil, nil - } else if wikiName == "_Sidebar" || wikiName == "_Footer" { - continue - } - pages = append(pages, PageMeta{ - Name: wikiName, - SubURL: models.WikiNameToSubURL(wikiName), - }) - } - ctx.Data["Pages"] = pages + entries, err := commit.ListEntries() + if err != nil { + ctx.ServerError("ListEntries", err) + return nil, nil } + pages := make([]PageMeta, 0, len(entries)) + for _, entry := range entries { + if !entry.IsRegular() { + continue + } + wikiName, err := models.WikiFilenameToName(entry.Name()) + if err != nil { + if models.IsErrWikiInvalidFileName(err) { + continue + } + ctx.ServerError("WikiFilenameToName", err) + return nil, nil + } else if wikiName == "_Sidebar" || wikiName == "_Footer" { + continue + } + pages = append(pages, PageMeta{ + Name: wikiName, + SubURL: models.WikiNameToSubURL(wikiName), + }) + } + ctx.Data["Pages"] = pages + // get requested pagename pageName := models.NormalizeWikiName(ctx.Params(":page")) if len(pageName) == 0 { pageName = "Home" } ctx.Data["PageURL"] = models.WikiNameToSubURL(pageName) - ctx.Data["old_title"] = pageName ctx.Data["Title"] = pageName ctx.Data["title"] = pageName ctx.Data["RequireHighlightJS"] = true - pageFilename := models.WikiNameToFilename(pageName) - var entry *git.TreeEntry - if entry, err = findEntryForFile(commit, pageFilename); err != nil { - ctx.ServerError("findEntryForFile", err) - return nil, nil - } else if entry == nil { + //lookup filename in wiki - get filecontent, gitTree entry , real filename + data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName) + if noEntry { ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages") + } + if entry == nil || ctx.Written() { return nil, nil } - data := wikiContentsByEntry(ctx, entry) + + sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar") if ctx.Written() { return nil, nil } - if isViewPage { - sidebarContent, sidebarPresent := wikiContentsByName(ctx, commit, "_Sidebar") - if ctx.Written() { - return nil, nil - } - - footerContent, footerPresent := wikiContentsByName(ctx, commit, "_Footer") - if ctx.Written() { - return nil, nil - } - - metas := ctx.Repo.Repository.ComposeMetas() - ctx.Data["content"] = markdown.RenderWiki(data, ctx.Repo.RepoLink, metas) - ctx.Data["sidebarPresent"] = sidebarPresent - ctx.Data["sidebarContent"] = markdown.RenderWiki(sidebarContent, ctx.Repo.RepoLink, metas) - ctx.Data["footerPresent"] = footerPresent - ctx.Data["footerContent"] = markdown.RenderWiki(footerContent, ctx.Repo.RepoLink, metas) - } else { - ctx.Data["content"] = string(data) - ctx.Data["sidebarPresent"] = false - ctx.Data["sidebarContent"] = "" - ctx.Data["footerPresent"] = false - ctx.Data["footerContent"] = "" + footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer") + if ctx.Written() { + return nil, nil } + metas := ctx.Repo.Repository.ComposeMetas() + ctx.Data["content"] = markdown.RenderWiki(data, ctx.Repo.RepoLink, metas) + ctx.Data["sidebarPresent"] = sidebarContent != nil + ctx.Data["sidebarContent"] = markdown.RenderWiki(sidebarContent, ctx.Repo.RepoLink, metas) + ctx.Data["footerPresent"] = footerContent != nil + ctx.Data["footerContent"] = markdown.RenderWiki(footerContent, ctx.Repo.RepoLink, metas) + + // get commit count - wiki revisions + commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) + ctx.Data["CommitCount"] = commitsCount + return wikiRepo, entry } +func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { + wikiRepo, commit, err := findWikiRepoCommit(ctx) + if err != nil { + if !git.IsErrNotExist(err) { + ctx.ServerError("GetBranchCommit", err) + } + return nil, nil + } + + // get requested pagename + pageName := models.NormalizeWikiName(ctx.Params(":page")) + if len(pageName) == 0 { + pageName = "Home" + } + ctx.Data["PageURL"] = models.WikiNameToSubURL(pageName) + ctx.Data["old_title"] = pageName + ctx.Data["Title"] = pageName + ctx.Data["title"] = pageName + ctx.Data["RequireHighlightJS"] = true + + //lookup filename in wiki - get filecontent, gitTree entry , real filename + data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName) + if noEntry { + ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages") + } + if entry == nil || ctx.Written() { + return nil, nil + } + + ctx.Data["content"] = string(data) + ctx.Data["sidebarPresent"] = false + ctx.Data["sidebarContent"] = "" + ctx.Data["footerPresent"] = false + ctx.Data["footerContent"] = "" + + // get commit count - wiki revisions + commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) + ctx.Data["CommitCount"] = commitsCount + + // get page + page := ctx.QueryInt("page") + if page <= 1 { + page = 1 + } + + // get Commit Count + commitsHistory, err := wikiRepo.CommitsByFileAndRange("master", pageFilename, page) + if err != nil { + ctx.ServerError("CommitsByFileAndRange", err) + return nil, nil + } + commitsHistory = models.ValidateCommitsWithEmails(commitsHistory) + commitsHistory = models.ParseCommitsWithSignature(commitsHistory) + + ctx.Data["Commits"] = commitsHistory + + pager := context.NewPagination(int(commitsCount), git.CommitsRangeSize, page, 5) + pager.SetDefaultParams(ctx) + ctx.Data["Page"] = pager + + return wikiRepo, entry +} + +func renderEditPage(ctx *context.Context) { + _, commit, err := findWikiRepoCommit(ctx) + if err != nil { + if !git.IsErrNotExist(err) { + ctx.ServerError("GetBranchCommit", err) + } + return + } + + // get requested pagename + pageName := models.NormalizeWikiName(ctx.Params(":page")) + if len(pageName) == 0 { + pageName = "Home" + } + ctx.Data["PageURL"] = models.WikiNameToSubURL(pageName) + ctx.Data["old_title"] = pageName + ctx.Data["Title"] = pageName + ctx.Data["title"] = pageName + ctx.Data["RequireHighlightJS"] = true + + //lookup filename in wiki - get filecontent, gitTree entry , real filename + data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName) + if noEntry { + ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages") + } + if entry == nil || ctx.Written() { + return + } + + ctx.Data["content"] = string(data) + ctx.Data["sidebarPresent"] = false + ctx.Data["sidebarContent"] = "" + ctx.Data["footerPresent"] = false + ctx.Data["footerContent"] = "" +} + // Wiki renders single wiki page func Wiki(ctx *context.Context) { ctx.Data["PageIsWiki"] = true @@ -221,7 +312,7 @@ func Wiki(ctx *context.Context) { return } - wikiRepo, entry := renderWikiPage(ctx, true) + wikiRepo, entry := renderViewPage(ctx) if ctx.Written() { return } @@ -247,6 +338,39 @@ func Wiki(ctx *context.Context) { ctx.HTML(200, tplWikiView) } +// WikiRevision renders file revision list of wiki page +func WikiRevision(ctx *context.Context) { + ctx.Data["PageIsWiki"] = true + ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki) && !ctx.Repo.Repository.IsArchived + + if !ctx.Repo.Repository.HasWiki() { + ctx.Data["Title"] = ctx.Tr("repo.wiki") + ctx.HTML(200, tplWikiStart) + return + } + + wikiRepo, entry := renderRevisionPage(ctx) + if ctx.Written() { + return + } + if entry == nil { + ctx.Data["Title"] = ctx.Tr("repo.wiki") + ctx.HTML(200, tplWikiStart) + return + } + + // Get last change information. + wikiPath := entry.Name() + lastCommit, err := wikiRepo.GetCommitByPath(wikiPath) + if err != nil { + ctx.ServerError("GetCommitByPath", err) + return + } + ctx.Data["Author"] = lastCommit.Author + + ctx.HTML(200, tplWikiRevision) +} + // WikiPages render wiki pages list page func WikiPages(ctx *context.Context) { if !ctx.Repo.Repository.HasWiki() { @@ -399,7 +523,7 @@ func EditWiki(ctx *context.Context) { return } - renderWikiPage(ctx, false) + renderEditPage(ctx) if ctx.Written() { return } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 744088a9d7..ec57e8f5fd 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -804,6 +804,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/wiki", func() { m.Get("/?:page", repo.Wiki) m.Get("/_pages", repo.WikiPages) + m.Get("/:page/_revision", repo.WikiRevision) m.Group("", func() { m.Combo("/_new").Get(repo.NewWiki). diff --git a/templates/repo/wiki/revision.tmpl b/templates/repo/wiki/revision.tmpl new file mode 100644 index 0000000000..a64c386edc --- /dev/null +++ b/templates/repo/wiki/revision.tmpl @@ -0,0 +1,104 @@ +{{template "base/head" .}} +
      + {{template "repo/header" .}} + {{ $title := .title}} +
      +
      +
      +
      + {{if not $.DisableHTTP}} + + {{end}} + {{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} + + {{end}} + {{if not $.DisableHTTP}} + + {{else if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} + + {{end}} + {{if or ((not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)))}} + + {{end}} +
      +
      +
      + {{.revision}} + {{$title}} +
      + {{$timeSince := TimeSince .Author.When $.Lang}} + {{.i18n.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}} +
      +
      +
      +

      {{.i18n.Tr "repo.wiki.wiki_page_revisions"}}

      +
      +

      +
      +
      + {{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}} +
      +
      +

      + + {{if and .Commits (gt .CommitCount 0)}} +
      + + + + + + + + + + {{ $r:= List .Commits}} + {{range $r}} + + + + + + {{end}} + +
      {{.i18n.Tr "repo.commits.author"}}SHA1{{.i18n.Tr "repo.commits.date"}}
      + {{if .User}} + {{if .User.FullName}} +   {{.User.FullName}} + {{else}} +   {{.Author.Name}} + {{end}} + {{else}} +   {{.Author.Name}} + {{end}} + + + {{TimeSince .Author.When $.Lang}}
      +
      + {{end}} + + {{template "base/paginate" .}} + +
      +
      +
      + + +{{template "base/footer" .}} diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index dd2de2a041..f775ac9429 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -56,6 +56,7 @@
      + {{.CommitCount}} {{$title}}
      {{$timeSince := TimeSince .Author.When $.Lang}} From 5f8f42e2749d2a0ab7f3b47e57edb3acda942b63 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 8 Jul 2019 08:23:19 +0000 Subject: [PATCH 208/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_lv-LV.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index cdc0df84ca..9cb62c7010 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -620,6 +620,8 @@ migrate.invalid_local_path=Nederīgs lokālais ceļš. Tas neeksistē vai nav di migrate.failed=Migrācija neizdevās: %v migrate.lfs_mirror_unsupported=LFS objektu spoguļošana netiek atbalstīta - tā vietā izmantojiet 'git lfs fetch --all' un 'git lfs push --all'. migrate.migrate_items_options=Pārņemot datus no GitHub, ievadiet lietotāja vārdu, lai redzētu papildus iestatījumus. +migrated_from=Migrēts no %[2]s +migrated_from_fake=Migrēts no %[1]s mirror_from=spogulis no forked_from=atdalīts no @@ -767,7 +769,7 @@ issues.add_assignee_at=`tika piešķirta problēma no %s %s` issues.remove_assignee_at=`tika noņemta problēma no %s %s` issues.remove_self_assignment=`noņēma sev problēmu %s` issues.change_title_at=`nomainīts virsraksts no %s uz %s %s` -issues.delete_branch_at=`izdzēsts atzars %s %s` +issues.delete_branch_at=`izdzēsa atzaru %s %s` issues.open_tab=%d atvērti issues.close_tab=%d aizvērti issues.filter_label=Etiķete From 427a161c67c8b2be2c4324870b06686f1f5de3d6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 8 Jul 2019 18:10:56 +0800 Subject: [PATCH 209/220] Fix migration tests since #7 fixed (#7375) * fix migration tests since #7 fixed * fix test time --- modules/migrations/github_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/migrations/github_test.go b/modules/migrations/github_test.go index 0f52a62eb2..54845ab426 100644 --- a/modules/migrations/github_test.go +++ b/modules/migrations/github_test.go @@ -174,6 +174,7 @@ func TestGitHubDownloadRepo(t *testing.T) { var ( closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC) + closed7 = time.Date(2019, 7, 8, 8, 20, 23, 0, time.UTC) ) assert.EqualValues(t, []*base.Issue{ { @@ -210,10 +211,10 @@ func TestGitHubDownloadRepo(t *testing.T) { Number: 7, Title: "display page revisions on wiki", Content: "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991", - Milestone: "1.x.x", + Milestone: "1.10.0", PosterID: 1520407, PosterName: "joubertredrat", - State: "open", + State: "closed", Created: time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC), Labels: []*base.Label{ { @@ -235,6 +236,7 @@ func TestGitHubDownloadRepo(t *testing.T) { Heart: 0, Hooray: 0, }, + Closed: &closed7, }, { Number: 8, From 6138388ffa2af6c2efa4d0a4f293aa661ca4bfa7 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 8 Jul 2019 10:13:47 +0000 Subject: [PATCH 210/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 1fc32f7190..b44c20de59 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1213,6 +1213,8 @@ settings.event_release=Lanzamiento settings.event_release_desc=Lanzamiento publicado, actualizado o eliminado en un repositorio. settings.event_pull_request=Pull Request settings.event_pull_request_desc=Pull Request abierta, cerrada, reabierta, editada, aprobada, rechazada, comentario de revisión, asignada, no asignada, etiqueta actualizada, etiqueta borrada o sincronizada. +settings.event_push=Push +settings.event_push_desc=Git push a un repositorio. settings.update_webhook=Actualizar Webhook settings.recent_deliveries=Envíos Recientes settings.hook_type=Tipo de Hook @@ -1221,11 +1223,20 @@ settings.slack_domain=Dominio settings.slack_channel=Canal settings.deploy_keys=Claves de Despliegue settings.add_deploy_key=Añadir Clave de Despliegue +settings.is_writable_info=Permitir que esta clave de despliegue pueda hacer push a este repositorio. settings.title=Título settings.deploy_key_content=Contenido +settings.protected_branch_can_push=¿Permitir hacer push? +settings.protected_branch_can_push_yes=Puede hacer push +settings.protected_branch_can_push_no=No puede hacer push settings.branch_protection=Proteccion de la rama '%s' settings.protect_this_branch=Activar protección de rama +settings.protect_this_branch_desc=Prevenir eliminar y desactivar hacer git push en esta rama. +settings.protect_whitelist_committers=Activar lista blanca para hacer push +settings.protect_whitelist_committers_desc=Permitir hacer push en esta rama a los usuarios o equipos en la lista blanca (pero no hacer push forzado). +settings.protect_whitelist_users=Usuarios en la lista blanca para hacer push: settings.protect_whitelist_search_users=Buscar usuarios… +settings.protect_whitelist_teams=Equipos en la lista blanca para hacer push: settings.protect_whitelist_search_teams=Buscar equipos… settings.protect_merge_whitelist_committers_desc=Permitir a los usuarios o equipos de la lista a fusionar peticiones pull dentro de esta rama. settings.protect_required_approvals=Aprobaciones requeridas: @@ -1236,6 +1247,7 @@ settings.delete_protected_branch=Desactivar protección settings.update_protect_branch_success=La protección de la rama '%s' ha sido actualizada. settings.remove_protected_branch_success=La protección de la rama '%s' ha sido desactivada. settings.protected_branch_deletion=Desactivar protección de rama +settings.protected_branch_deletion_desc=Desactivar la protección de la rama permite a los usuarios con permiso de escritura hacer push a la rama. ¿Continuar? settings.archive.error_ismirror=No puede archivar un repositorio replicado. diff.browse_source=Explorar el Código @@ -1538,6 +1550,7 @@ reopen_pull_request=`reabrió el pull request %s#%[2]s comment_issue=`comentó en la incidencia %s#%[2]s` merge_pull_request=`fusionado pull request %s#%[2]s` transfer_repo=transfirió el repositorio %s a %s +push_tag=hizó push la etiqueta %[2]s a %[3]s delete_tag=etiqueta eliminada %[2]s de %[3]s delete_branch=rama %[2]s eliminada, de %[3]s mirror_sync_push=sincronizó cambios a %[3]s en %[4]s desde réplica From c8a52b949b722b1dc51e7cd1bbf84c081c57b0d2 Mon Sep 17 00:00:00 2001 From: Cherrg Date: Mon, 8 Jul 2019 17:29:52 +0200 Subject: [PATCH 211/220] fix post parameter - on issue list - unset assignee (#7380) * fix post parameter - issue list - assignee fix #7328 - remove assignee on issue list return 500 Signed-off-by: Michael Gnehr * add missing semicolons Signed-off-by: Michael Gnehr --- public/js/index.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index ef8a1093ad..b4ce8c78b6 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2137,12 +2137,16 @@ $(document).ready(function () { }); $('.issue-action').click(function () { - var action = this.dataset.action - var elementId = this.dataset.elementId - var issueIDs = $('.issue-checkbox').children('input:checked').map(function() { + let action = this.dataset.action; + let elementId = this.dataset.elementId; + let issueIDs = $('.issue-checkbox').children('input:checked').map(function() { return this.dataset.issueId; }).get().join(); - var url = this.dataset.url + let url = this.dataset.url; + if (elementId === '0' && url.substr(-9) === '/assignee'){ + elementId = ''; + action = 'clear'; + } updateIssuesMeta(url, action, issueIDs, elementId).then(reload); }); From 1fc90bb474dfbf19ecbd285de9e2b92db1f7ec99 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 8 Jul 2019 15:49:00 +0000 Subject: [PATCH 212/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 5 + options/locale/locale_es-ES.ini | 339 +++++++++++++++++++++++++++++++- options/locale/locale_fr-FR.ini | 18 ++ options/locale/locale_pt-BR.ini | 9 + 4 files changed, 368 insertions(+), 3 deletions(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index ac4e0b1b19..d6ee0d2126 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -620,6 +620,8 @@ migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder i migrate.failed=Fehler bei der Migration: %v migrate.lfs_mirror_unsupported=Spiegeln von LFS-Objekten wird nicht unterstützt - nutze stattdessen 'git lfs fetch --all' und 'git lfs push --all'. migrate.migrate_items_options=Wenn du von GitHub migrierst und einen Benutzernamen eingegeben hast, werden die Migrationsoptionen angezeigt. +migrated_from=Migriert von %[2]s +migrated_from_fake=Migriert von %[1]s mirror_from=Mirror von forked_from=geforkt von @@ -1028,6 +1030,7 @@ wiki.save_page=Seite speichern wiki.last_commit_info=%s hat diese Seite bearbeitet %s wiki.edit_page_button=Bearbeiten wiki.new_page_button=Neue Seite +wiki.back_to_wiki=Zurück zur Wiki-Seite wiki.delete_page_button=Seite löschen wiki.delete_page_notice_1=Das Löschen der Wiki-Seite „%s“ kann nicht rückgängig gemacht werden. Fortfahren? wiki.page_already_exists=Eine Wiki-Seite mit dem gleichen Namen existiert bereits. @@ -1724,6 +1727,7 @@ config.ssh_minimum_key_sizes=Mindestschlüssellängen config.lfs_config=LFS-Konfiguration config.lfs_enabled=Aktiviert config.lfs_content_path=LFS Content-Pfad +config.lfs_http_auth_expiry=Ablauf der LFS HTTP Authentifizierung config.db_config=Datenbankkonfiguration config.db_type=Typ @@ -1864,6 +1868,7 @@ push_tag=hat Tag %[2]s auf %[3]s delete_tag=hat Tag %[2]s in %[3]s gelöscht delete_branch=hat Branch %[2]s in %[3]s gelöscht compare_commits=Vergleiche %d Commits +compare_commits_general=Commits vergleichen mirror_sync_push=hat Commits des Mirrors mit %[3]s in %[4]s synchronisiert mirror_sync_create=hat eine neue Referenz des Mirrors %[2]s mit %[3]s synchronisiert mirror_sync_delete=hat die Referenz des Mirrors %[2]s in %[3]s synchronisiert und gelöscht diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index b44c20de59..6595ff2dae 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -620,6 +620,8 @@ migrate.invalid_local_path=La ruta local es inválida. No existe o no es un dire migrate.failed=Migración fallida: %v migrate.lfs_mirror_unsupported=La replicación de objetos LFS no está soportada - use 'git lfs fetch --all' y 'git lfs push --all' en su lugar. migrate.migrate_items_options=Cuando migra desde github, se mostrarán un nombre de usuario y se mostrarán opciones de migración. +migrated_from=Migrado desde %[2]s +migrated_from_fake=Migrado desde %[1]s mirror_from=réplica de forked_from=forkeado de @@ -929,6 +931,7 @@ issues.dependency.add_error_dep_issue_not_exist=Incidencia dependiente no existe issues.dependency.add_error_dep_not_exist=La dependencia no existe. issues.dependency.add_error_dep_exists=La dependencia ya existe. issues.dependency.add_error_cannot_create_circular=No puede crear una depenciena con dos issues que se estan bloqueando mutuamente. +issues.dependency.add_error_dep_not_same_repo=Ambas incidencias deben estar en el mismo repositorio. issues.review.self.approval=No puede aprobar su propio pull request. issues.review.self.rejection=No puede sugerir cambios en su propio pull request. issues.review.approve=aprobado estos cambios %s @@ -944,9 +947,13 @@ issues.review.hide_outdated=Ocultar obsoletos pulls.desc=Habilitar solicitudes de fusión y revisiones de código. pulls.new=Nuevo Pull Request pulls.compare_changes=Nuevo pull request +pulls.compare_changes_desc=Seleccione la rama en la que se fusiona y la rama a recuperar. +pulls.compare_base=fusionar en +pulls.compare_compare=recuperar de pulls.filter_branch=Filtrar rama pulls.no_results=Sin resultados. pulls.nothing_to_compare=Estas ramas son iguales. No hay necesidad para crear un pull request. +pulls.has_pull_request=`Ya existe un pull request entre estas ramas: %[2]s#%[3]d` pulls.create=Crear Pull Request pulls.title_desc=desea fusionar %[1]d commits de %[2]s en %[3]s pulls.merged_title_desc=fusionados %[1]d commits de %[2]s en %[3]s %[4]s @@ -954,13 +961,25 @@ pulls.tab_conversation=Conversación pulls.tab_commits=Commits pulls.tab_files=Archivos modificados pulls.reopen_to_merge=Vuelva a abrir la solicitud de "pull" para realizar una fusión. +pulls.cant_reopen_deleted_branch=Este pull request no se puede reabrir porque la rama fue eliminada. pulls.merged=Fusionado pulls.has_merged=El pull request ha sido fusionado. +pulls.title_wip_desc=`Comience el título con %s para prevenir que el pull request se fusione accidentalmente.` +pulls.cannot_merge_work_in_progress=Este pull request está marcado como un trabajo en progreso. Elimine el prefijo %s del título cuando esté listo pulls.data_broken=Este pull request está rota debido a que falta información del fork. +pulls.files_conflicted=Este pull request tiene cambios en conflicto con la rama de destino. pulls.is_checking=La comprobación de conflicto de fusión está en progreso. Inténtalo de nuevo en unos momentos. +pulls.blocked_by_approvals=Este pull request aún no tiene suficientes aprobaciones. %d de %d autorizaciones concedidas. pulls.can_auto_merge_desc=Este Pull Request puede ser fusionado automáticamente. +pulls.cannot_auto_merge_desc=Este pull request no se puede combinar automáticamente debido a conflictos. pulls.cannot_auto_merge_helper=Combinar manualmente para resolver los conflictos. +pulls.no_merge_desc=Este pull request no se puede combinar porque todas las opciones de combinación del repositorio están deshabilitadas. +pulls.no_merge_helper=Habilite las opciones de combinación en la configuración del repositorio o fusione el pull request manualmente. +pulls.no_merge_wip=Este pull request no se puede combinar porque está marcada como un trabajo en progreso. pulls.merge_pull_request=Fusionar Pull Request +pulls.rebase_merge_pull_request=Hacer Rebase y Fusionar +pulls.rebase_merge_commit_pull_request=Hacer Rebase y Fusionar (--no-ff) +pulls.squash_merge_pull_request=Hacer Squash y Fusionar pulls.invalid_merge_option=No puede utilizar esta opción de combinación para esta solicitud de extracción. pulls.open_unmerged_pull_exists=`No puede realizar la reapertura porque hay un pull request pendiente (#%d) con propiedades idénticas.` pulls.status_checking=Algunas comprobaciones están pendientes @@ -1014,6 +1033,9 @@ wiki.save_page=Guardar página wiki.last_commit_info=%s editó esta página %s wiki.edit_page_button=Editar wiki.new_page_button=Nueva página +wiki.file_revision=Revisión de página +wiki.wiki_page_revisions=Revisiones de la página Wiki +wiki.back_to_wiki=Volver a la página wiki wiki.delete_page_button=Eliminar página wiki.delete_page_notice_1=La eliminación de la página wiki '%s' no se puede deshacer. ¿Continuar? wiki.page_already_exists=Ya existe una página con el mismo nombre. @@ -1066,8 +1088,8 @@ activity.no_git_activity=No ha habido ningún commit en este período. activity.git_stats_exclude_merges=Excluyendo fusiones, activity.git_stats_author_1=%d autor activity.git_stats_author_n=%d autores -activity.git_stats_pushed_1=ha empujado -activity.git_stats_pushed_n=han empujado +activity.git_stats_pushed_1=ha hecho push +activity.git_stats_pushed_n=han hecho push activity.git_stats_commit_1=%d commit activity.git_stats_commit_n=%d commits activity.git_stats_push_to_branch=a %s y @@ -1142,6 +1164,12 @@ settings.convert_notices_1=Esta operación convertirá el repositorio replicado settings.convert_confirm=Convertir repositorio settings.convert_succeed=El repositorio replicado ha sido convertido en un repositorio normal. settings.transfer=Transferir la propiedad +settings.transfer_desc=Transferir este repositorio a un usuario o una organizacion de la cual disponga de privilegios administrativos. +settings.transfer_notices_1=- Perderá el acceso al repositorio si lo transfiere a un usuario individual. +settings.transfer_notices_2=- Mantendrá el acceso al repositorio si lo transfiere a una organización que usted (co-)posee. +settings.transfer_form_title=Escriba el nombre del repositorio como confirmación: +settings.wiki_delete=Eliminar datos de Wiki +settings.wiki_delete_desc=Eliminar los datos del wiki del repositorio es permanente y no se puede deshacer. settings.wiki_delete_notices_1=- Esto eliminará y desactivará permanentemente el wiki del repositorio para %s. settings.confirm_wiki_delete=Eliminar los datos del Wiki settings.wiki_deletion_success=La wiki del repositorio ha sido eliminada. @@ -1215,17 +1243,40 @@ settings.event_pull_request=Pull Request settings.event_pull_request_desc=Pull Request abierta, cerrada, reabierta, editada, aprobada, rechazada, comentario de revisión, asignada, no asignada, etiqueta actualizada, etiqueta borrada o sincronizada. settings.event_push=Push settings.event_push_desc=Git push a un repositorio. +settings.event_repository=Repositorio +settings.event_repository_desc=Repositorio creado o eliminado. +settings.active=Activo +settings.active_helper=La información sobre los eventos desencadenados se enviará a esta URL de webhook. +settings.add_hook_success=El webhook ha sido añadido. settings.update_webhook=Actualizar Webhook +settings.update_hook_success=El webhook ha sido actualizado. +settings.delete_webhook=Eliminar Webhook settings.recent_deliveries=Envíos Recientes settings.hook_type=Tipo de Hook +settings.add_slack_hook_desc=Integrar Slack en su repositorio. settings.slack_token=Token settings.slack_domain=Dominio settings.slack_channel=Canal +settings.add_discord_hook_desc=Integrar Discord en su repositorio. +settings.add_dingtalk_hook_desc=Integrar Dingtalk en su repositorio. +settings.add_telegram_hook_desc=Integrar Telegrama en tu repositorio. +settings.add_msteams_hook_desc=Integrar Microsoft Teams en tu repositorio. settings.deploy_keys=Claves de Despliegue settings.add_deploy_key=Añadir Clave de Despliegue +settings.deploy_key_desc=Las claves de despliegue tienen acceso de sólo lectura al repositorio. +settings.is_writable=Habilitar acceso de escritura settings.is_writable_info=Permitir que esta clave de despliegue pueda hacer push a este repositorio. +settings.no_deploy_keys=Aún no existen claves de despliegue. settings.title=Título settings.deploy_key_content=Contenido +settings.key_been_used=Una clave de despliegue con contenido idéntico ya se encuentra en uso. +settings.key_name_used=Ya existe una clave de despliegue con el mismo nombre. +settings.add_key_success=La clave de despliegue '%s' ha sido añadida. +settings.deploy_key_deletion=Eliminar clave de despliegue +settings.deploy_key_deletion_desc=Eliminar una clave de despliegue revocará el acceso de la misma a este repositorio. ¿Continuar? +settings.deploy_key_deletion_success=La clave de despliegue ha sido eliminada. +settings.branches=Ramas +settings.protected_branch=Protección de rama settings.protected_branch_can_push=¿Permitir hacer push? settings.protected_branch_can_push_yes=Puede hacer push settings.protected_branch_can_push_no=No puede hacer push @@ -1238,8 +1289,12 @@ settings.protect_whitelist_users=Usuarios en la lista blanca para hacer push: settings.protect_whitelist_search_users=Buscar usuarios… settings.protect_whitelist_teams=Equipos en la lista blanca para hacer push: settings.protect_whitelist_search_teams=Buscar equipos… +settings.protect_merge_whitelist_committers=Activar lista blanca para fusionar settings.protect_merge_whitelist_committers_desc=Permitir a los usuarios o equipos de la lista a fusionar peticiones pull dentro de esta rama. +settings.protect_merge_whitelist_users=Usuarios en la lista blanca para fusionar: +settings.protect_merge_whitelist_teams=Equipos en la lista blanca para fusionar: settings.protect_required_approvals=Aprobaciones requeridas: +settings.protect_required_approvals_desc=Permitir solo fusionar un pull request con suficientes revisiones positivas de usuarios o equipos en la lista blanca. settings.protect_approvals_whitelist_users=Lista blanca de usuarios revisores: settings.protect_approvals_whitelist_teams=Lista blanca de equipos revisores: settings.add_protected_branch=Activar protección @@ -1248,20 +1303,59 @@ settings.update_protect_branch_success=La protección de la rama '%s' ha sido ac settings.remove_protected_branch_success=La protección de la rama '%s' ha sido desactivada. settings.protected_branch_deletion=Desactivar protección de rama settings.protected_branch_deletion_desc=Desactivar la protección de la rama permite a los usuarios con permiso de escritura hacer push a la rama. ¿Continuar? +settings.default_branch_desc=Seleccione una rama de repositorio por defecto para los pull request y los commits: +settings.choose_branch=Elija una rama… +settings.no_protected_branch=No hay ramas protegidas. +settings.edit_protected_branch=Editar +settings.protected_branch_required_approvals_min=Las aprobaciones necesarias no pueden ser negativas. +settings.bot_token=Token del Bot +settings.chat_id=ID Chat +settings.archive.button=Archivar Repositorio +settings.archive.header=Archivar este repositorio +settings.archive.text=Archivar el repositorio lo hará exclusivamente de lectura. Está oculto del tablero, no se podrán hacer commits, incidencias o pull-requests. +settings.archive.success=El repositorio ha sido archivado exitosamente. +settings.archive.error=Ha ocurrido un error al intentar archivar el repositorio. Vea el registro para más detalles. settings.archive.error_ismirror=No puede archivar un repositorio replicado. +settings.archive.branchsettings_unavailable=Los ajustes de rama no están disponibles si el repositorio está archivado. +settings.unarchive.button=Desarchivar Repositorio +settings.unarchive.header=Desarchivar este Repositorio +settings.unarchive.text=Des-archivar el repositorio restaurará su capacidad de recibir commits y pushes, así como nuevas incidencias y pull-requests. +settings.unarchive.success=El repositorio ha sido desarchivado exitosamente. +settings.unarchive.error=Ha ocurrido un error al intentar des-archivar el repositorio. Vea el registro para más detalles. +settings.update_avatar_success=El avatar del repositorio ha sido actualizado. diff.browse_source=Explorar el Código diff.parent=padre diff.commit=commit +diff.git-notes=Notas +diff.data_not_available=El contenido del Diff no está disponible diff.show_diff_stats=Mostrar estadísticas de diff diff.show_split_view=Dividir vista diff.show_unified_view=Unificar vista +diff.whitespace_button=Espacio blanco +diff.whitespace_show_everything=Mostrar todos los cambios +diff.whitespace_ignore_all_whitespace=Ignorar espacio en blanco al comparar líneas +diff.whitespace_ignore_amount_changes=Ignorar cambios en cantidad de espacio en blanco +diff.whitespace_ignore_at_eol=Ignorar cambios en espacios en blanco al final de la línea diff.stats_desc=Se han modificado %d ficheros con %d adiciones y %d borrados diff.bin=BIN diff.view_file=Ver fichero diff.file_suppressed=La diferencia del archivo ha sido suprimido porque es demasiado grande diff.too_many_files=Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio +diff.comment.placeholder=Deja un comentario +diff.comment.markdown_info=Es posible estilizar con markdown. +diff.comment.add_single_comment=Añadir solo comentario +diff.comment.add_review_comment=Añadir comentario +diff.comment.start_review=Comenzar revisión +diff.comment.reply=Responder +diff.review=Revisión +diff.review.header=Enviar revisión +diff.review.placeholder=Comentario de revisión +diff.review.comment=Comentario +diff.review.approve=Aprobar +diff.review.reject=Solicitud de cambios +releases.desc=Seguir las versiones y descargas del proyecto. release.releases=Lanzamientos release.new_release=Nueva Release release.draft=Borrador @@ -1270,53 +1364,104 @@ release.stable=Estable release.edit=editar release.ahead=%d commits en %s desde esta release release.source_code=Código Fuente +release.new_subheader=Los lanzamientos organizan las versiones de proyectos. +release.edit_subheader=Los lanzamientos organizan las versiones de proyectos. release.tag_name=Nombre de la etiqueta release.target=Destino +release.tag_helper=Escoge una etiqueta existente o crea una nueva. release.title=Título release.content=Contenido +release.prerelease_desc=Marcar como Pre-Lanzamiento +release.prerelease_helper=Marcar este lanzamiento como no es adecuada para usar en producción. release.cancel=Cancelar release.publish=Publicar Release release.save_draft=Guardar borrador +release.edit_release=Actualizar Lanzamiento +release.delete_release=Eliminar Lanzamiento +release.deletion=Eliminar Lanzamiento +release.deletion_desc=Eliminar uno lanzamiento elimina su etiqueta Git del repositorio. El contenido del repositorio y el historial siguen sin cambios. ¿Continuar? release.deletion_success=El lanzamiento ha sido eliminado. +release.tag_name_already_exist=Ya existe uno lanzamiento con esta etiqueta. +release.tag_name_invalid=El nombre de la etiqueta no es válido. release.downloads=Descargas +branch.name=Nombre de la rama branch.search=Buscar ramas +branch.already_exists=Ya existe una rama con el nombre %s. branch.delete_head=Eliminar +branch.delete=Eliminar la rama con el nombre '%s' branch.delete_html=Eliminar rama +branch.delete_desc=Eliminar una rama es permanente. NO PUEDE deshacerse. ¿Continuar? +branch.deletion_success=La rama con el nombre '%s' ha sido eliminado. +branch.deletion_failed=Fallo al eliminar la rama con el nombre '%s'. +branch.delete_branch_has_new_commits=La rama con el nombre '%s' no puede eliminar porque se han añadido nuevos commits después de fusionar. branch.create_branch=Crear rama %s branch.create_from=desde '%s' +branch.create_success=La rama con el nombre '%s' ha sido creado. branch.branch_already_exists=La rama '%s' ya existe en este repositorio. +branch.branch_name_conflict=La rama con el nombre '%s' entra en conflicto con la rama ya existente con el nombre '%s'. +branch.tag_collision=No puede crear una rama con el mismo nombre '%s' como una etiqueta ya existente en este repositorio. branch.deleted_by=Eliminada por %s +branch.restore_success=La rama '%s' ha sido restaurada. +branch.restore_failed=Fallo al restaurar la rama %s. +branch.protected_deletion_failed=La rama '%s' está protegida. No se puede eliminar. +topic.manage_topics=Administrar temas topic.done=Hecho +topic.count_prompt=No puede seleccionar más de 25 temas +topic.format_prompt=Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo. [org] org_name_holder=Nombre de la organización org_full_name_holder=Nombre completo de la organización +org_name_helper=Los nombres de organización deben ser cortos y destacados. create_org=Crear Organización repo_updated=Actualizado people=Personas teams=Equipos lower_members=miembros lower_repositories=repositorios +create_new_team=Nuevo equipo +create_team=Crear equipo org_desc=Descripción team_name=Nombre del equipo team_desc=Descripción +team_name_helper=Los nombres de equipos deben ser cortos y destacados. +team_desc_helper=Describa el propósito o rol del equipo. +team_permission_desc=Permiso +team_unit_desc=Permitir acceso a las secciones del repositorio +form.name_reserved=El nombre de la organización '%s' está reservado. +form.name_pattern_not_allowed=El patrón '%s' no está permitido en el nombre de una organización. +form.create_org_not_allowed=No tiene permisos para crear organizaciones. settings=Configuración +settings.options=Organización settings.full_name=Nombre completo settings.website=Página web settings.location=Localización +settings.visibility=Visibilidad +settings.visibility.public=Público +settings.visibility.limited=Limitado (Visible sólo para los usuarios registrados) +settings.visibility.private=Privado (Visible sólo para miembros de la organización) settings.update_settings=Actualizar configuración settings.update_setting_success=Configuración de la organización se han actualizado. +settings.change_orgname_prompt=Nota: cambiar el nombre de la organización también cambia la URL de la organización. +settings.update_avatar_success=Se ha actualizado el avatar de la organización. settings.delete=Eliminar organización settings.delete_account=Eliminar esta organización +settings.delete_prompt=La organización será eliminada permanentemente. ¡Esta acción NO PUEDE deshacerse! settings.confirm_delete_account=Confirmar eliminación +settings.delete_org_title=Eliminar organización +settings.delete_org_desc=Esta organización se eliminará permanentemente. ¿Continuar? settings.hooks_desc=Añadir webhooks que serán ejecutados para todos los repositorios de esta organización. members.membership_visibility=Visibilidad de Membresía: +members.public=Público +members.public_helper=hacer oculto +members.private=Oculto +members.private_helper=hacer público members.member_role=Rol del miembro: members.owner=Propietario members.member=Miembro @@ -1328,44 +1473,84 @@ members.invite_now=Invitar teams.join=Unirse teams.leave=Abandonar teams.read_access=Acceso de Lectura +teams.read_access_helper=Los miembros pueden ver y clonar los repositorios del equipo. teams.write_access=Acceso de Escritura +teams.write_access_helper=Los miembros pueden leer y hacer push a los repositorios del equipo. +teams.admin_access=Acceso administrativo teams.admin_access_helper=Los miembros pueden hacer pull y push a los repositorios del equipo y añadir colaboradores a ellos. teams.no_desc=Este equipo no tiene descripción teams.settings=Configuración +teams.owners_permission_desc=Los propietarios tienen acceso total a todos los repositorios y tienen acceso administrativo a la organización. teams.members=Miembros del equipo teams.update_settings=Actualizar configuración +teams.delete_team=Eliminar equipo teams.add_team_member=Añadir miembro al equipo +teams.delete_team_title=Eliminar equipo +teams.delete_team_desc=Eliminar un equipo revoca el acceso de repositorio a sus miembros ¿Continuar? teams.delete_team_success=El equipo ha sido eliminado. +teams.read_permission_desc=Este equipo tiene permisos de Lectura: los miembros pueden ver y clonar los repositorios del equipo. +teams.write_permission_desc=Este equipo tiene permisos de Escritura: los miembros pueden ver y hacer push a los repositorios del equipo. +teams.admin_permission_desc=Este equipo tiene permisos de Administración: los miembros pueden ver, hacer push y añadir colaboradores a los repositorios del equipo. teams.repositories=Repositorios del equipo +teams.search_repo_placeholder=Buscar repositorio… teams.add_team_repository=Añadir repositorio al equipo teams.remove_repo=Eliminar teams.add_nonexistent_repo=El repositorio que estás intentando añadir no existe, por favor, créalo primero. +teams.add_duplicate_users=El usuario ya es miembro del equipo. +teams.repos.none=Este equipo no tiene repositorios accesibles. +teams.members.none=No hay miembros en este equipo. [admin] dashboard=Panel de control +users=Cuenta de Usuario organizations=Organizaciones repositories=Repositorios +hooks=Webhooks por defecto +authentication=Orígenes de autenticación config=Configuración notices=Notificaciones del sistema monitor=Monitorización first_page=Primera last_page=Última +total=Total: %d +dashboard.statistic=Resumen +dashboard.operations=Operaciones de mantenimiento dashboard.system_status=Estado del sistema dashboard.statistic_info=La base de datos de Gitea contiene %d usuarios, %d organizaciones, %d claves públicas, %d repositorios, %d elementos observados, %d destacados, %d acciones, %d accesos, %d incidencias, %d comentarios, %d cuentas sociales, %d seguidos, %d réplicas, %d releases, %d orígenes de autenticación, %d webhooks, %d milestones, %d etiquetas, %d tareas de hook, %d equipos, %d tareas de actualización, %d adjuntos. dashboard.operation_name=Nombre de la operación dashboard.operation_switch=Interruptor dashboard.operation_run=Ejecutar +dashboard.clean_unbind_oauth=Limpiar conexiones OAuth no enlazadas dashboard.clean_unbind_oauth_success=Se han eliminado las conexiones de OAuth no vinculadas. +dashboard.delete_inactivate_accounts=Eliminar todas las cuentas inactivas +dashboard.delete_inactivate_accounts_success=Todas las cuentas inactivas han sido eliminadas. +dashboard.delete_repo_archives=Eliminar todos los archivos de repositorios +dashboard.delete_repo_archives_success=Todos los archivos de repositorios han sido eliminados. +dashboard.delete_missing_repos=Eliminar todos los repositorios que faltan sus archivos Git +dashboard.delete_missing_repos_success=Todos los repositorios que faltan sus archivos Git han sido eliminados. +dashboard.delete_generated_repository_avatars=Eliminar avatares generados del repositorio +dashboard.delete_generated_repository_avatars_success=Se eliminaron los avatares del repositorio generados. +dashboard.git_gc_repos=Ejecutar la recolección de basura en los repositorios +dashboard.git_gc_repos_success=Todos los repositorios han terminado de recolección de basura. dashboard.resync_all_sshkeys=Actualizar el archivo '.ssh/authorized_keys' con las claves SSH de Gitea (no es necesario para el servidor SSH incorporado). +dashboard.resync_all_sshkeys_success=Las claves públicas SSH controladas por Gitea han sido actualizadas. +dashboard.resync_all_hooks=Resincronizar los hooks de pre-recepción, actualización y post-recepción de todos los repositorios. +dashboard.resync_all_hooks_success=Todos los hooks de pre-recepción, actualización y post-recepción del repositorio han sido resincronizados. dashboard.reinit_missing_repos=Reiniciar todos los repositorios Git faltantes de los que existen registros dashboard.reinit_missing_repos_success=Todos los repositorios Git faltantes para los que existen registros se han reinicializado. +dashboard.sync_external_users=Sincronizar datos de usuario externo +dashboard.sync_external_users_started=Se ha iniciado la sincronización de datos de usuario externo. +dashboard.git_fsck=Ejecutar comprobaciones de salud en todos los repositorios +dashboard.git_fsck_started=Se han iniciado controles de salud de repositorio. dashboard.server_uptime=Tiempo de actividad del servidor dashboard.current_goroutine=Gorutinas actuales dashboard.current_memory_usage=Uso de memoria actual dashboard.total_memory_allocated=Total de Memoria Reservada dashboard.memory_obtained=Memoria Obtenida dashboard.pointer_lookup_times=Tiempos de búsqueda de punteros +dashboard.memory_allocate_times=Asignaciones de memoria +dashboard.memory_free_times=Liberaciones de memoria dashboard.current_heap_usage=Uso de Heap actual dashboard.heap_memory_obtained=Memoria de Heap Obtenida dashboard.heap_memory_idle=Memoria de Heap Inactiva @@ -1388,17 +1573,45 @@ dashboard.total_gc_pause=Pausa Total por GC dashboard.last_gc_pause=Última Pausa por GC dashboard.gc_times=Ejecuciones GC +users.user_manage_panel=Gestión de cuentas de usuario +users.new_account=Crear Cuenta de Usuario +users.name=Nombre de usuario users.activated=Activado users.admin=Administrador users.repos=Repositorios users.created=Creado +users.last_login=Último registro +users.never_login=Nunca registrado +users.send_register_notify=Enviar notificación de registro de usuario +users.new_success=La cuenta de usuario '%s' ha sido creada. users.edit=Editar -users.auth_source=Fuente de Autenticación +users.auth_source=Origen de Autenticación +users.local=Local +users.auth_login_name=Nombre de inicio de sesión de autenticación +users.password_helper=Deja la contraseña vacía para mantenerla sin cambios. +users.update_profile_success=La cuenta de usuario ha sido actualizada. +users.edit_account=Editar Cuenta de Usuario +users.max_repo_creation=Número máximo de repositorios +users.max_repo_creation_desc=(Introduzca -1 para usar el límite por defecto global.) +users.is_activated=Cuenta de usuario activada +users.prohibit_login=Desactivar inicio de sesión +users.is_admin=Es administrador +users.allow_git_hook=Puede crear Git Hooks +users.allow_import_local=Puede importar repositorios locales +users.allow_create_organization=Puede crear organizaciones +users.update_profile=Actualizar cuenta de usuario +users.delete_account=Eliminar Cuenta de Usuario +users.still_own_repo=Este usuario todavía posee uno o más depósitos. Eliminar o transferir estos repositorios primero. +users.still_has_org=Este usuario es un miembro de una organización. Primero retire el usuario de cualquier organización. +users.deletion_success=La cuenta de usuario ha sido eliminada. +orgs.org_manage_panel=Gestión de organizaciones orgs.name=Nombre orgs.teams=Equipos orgs.members=Miembros +orgs.new_orga=Nueva organización +repos.repo_manage_panel=Gestión de repositorios repos.owner=Propietario repos.name=Nombre repos.private=Privado @@ -1406,49 +1619,108 @@ repos.watches=Vigilantes repos.stars=Estrellas repos.forks=Forks repos.issues=Incidencias +repos.size=Tamaño +hooks.desc=Los Webhooks automáticamente hacen peticiones HTTP POST a un servidor cuando ciertos eventos de Gitea se activan. Los ganchos definidos aquí son predeterminados y serán copiados en todos los nuevos repositorios. Leer más en la guía webhooks. +hooks.add_webhook=Añadir Webhook por defecto +hooks.update_webhook=Actualizar Webhook por defecto +auths.auth_manage_panel=Gestión de origen de autenticación +auths.new=Añadir origen de autenticación auths.name=Nombre auths.type=Tipo auths.enabled=Activo +auths.syncenabled=Habilitar la sincronización de usuario auths.updated=Actualizado auths.auth_type=Tipo de autenticación auths.auth_name=Nombre de autenticación auths.security_protocol=Protocolo de seguridad auths.domain=Dominio +auths.host=Servidor auths.port=Puerto +auths.bind_dn=Bind DN auths.bind_password=Contraseña Bind +auths.bind_password_helper=Advertencia: Esta contraseña se almacena en texto plano. Utilice una cuenta de sólo lectura si es posible. auths.user_base=Base de búsqueda de usuarios auths.user_dn=DN de Usuario +auths.attribute_username=Atributo nombre de usuario +auths.attribute_username_placeholder=Dejar vacío para usar el nombre de usuario introducido en Gitea. +auths.attribute_name=Atributo nombre +auths.attribute_surname=Atributo apellido +auths.attribute_mail=Atributo correo electrónico +auths.attribute_ssh_public_key=Atributo Clave Pública SSH +auths.attributes_in_bind=Obtener atributos en el contexto de Bind DN +auths.use_paged_search=Usar búsqueda paginada +auths.search_page_size=Tamaño de página auths.filter=Filtro de usuario auths.admin_filter=Filtro de aministrador +auths.ms_ad_sa=Atributos de búsqueda de MS AD auths.smtp_auth=Tipo de autenticación SMTP +auths.smtphost=Servidor SMTP auths.smtpport=Puerto SMTP auths.allowed_domains=Dominios Permitidos +auths.allowed_domains_helper=Dejar vacío para permitir todos los dominios. Separa múltiples dominios con una coma (','). auths.enable_tls=Habilitar cifrado TLS auths.skip_tls_verify=Omitir la verificación TLS auths.pam_service_name=Nombre del Servicio PAM +auths.oauth2_provider=Proveedor OAuth2 +auths.oauth2_clientID=ID de cliente (clave) +auths.oauth2_clientSecret=Secreto del cliente +auths.openIdConnectAutoDiscoveryURL=URL de descubrimiento automático de OpenID Connect +auths.oauth2_use_custom_url=Utilizar URLs personalizadas en vez de direcciones URL por defecto +auths.oauth2_tokenURL=URL del token +auths.oauth2_authURL=URL de Autorización +auths.oauth2_profileURL=URL del perfil +auths.oauth2_emailURL=URL de email auths.enable_auto_register=Hablilitar Auto-Registro auths.tips=Consejos +auths.tips.oauth2.general=Autenticación OAuth2 auths.tips.oauth2.general.tip=Al registrar una nueva autenticación vía OAuth2, la URL de devolución/redirección debe ser: /user/oauth2//callback +auths.tip.oauth2_provider=Proveedor OAuth2 +auths.tip.bitbucket=Registrar un nuevo usuario de OAuth en https://bitbucket.org/account/user//oauth-consumers/new y agregar el permiso 'Cuenta' - 'Lectura' auths.tip.dropbox=Crear nueva aplicación en https://www.dropbox.com/developers/apps auths.tip.facebook=Registre una nueva aplicación en https://developers.facebook.com/apps y agregue el producto "Facebook Login auths.tip.github=Registre una nueva aplicación OAuth en https://github.com/settings/applications/new auths.tip.gitlab=Registrar nueva solicitud en https://gitlab.com/profile/applications +auths.tip.google_plus=Obtener credenciales de cliente OAuth2 desde la consola API de Google en https://console.developers.google.com/ auths.tip.openid_connect=Use el OpenID Connect Discovery URL (/.well-known/openid-configuration) para especificar los puntos finales +auths.tip.twitter=Ir a https://dev.twitter.com/apps, crear una aplicación y asegurarse de que la opción "Permitir que esta aplicación sea usada para iniciar sesión con Twitter" está activada +auths.tip.discord=Registrar una nueva aplicación en https://discordapp.com/developers/applications/me +auths.edit=Editar origen de autenticación +auths.activated=Este origen de autenticación ha sido activado auths.new_success=Se agregó la autenticación '%s'. +auths.update_success=El origen de autenticación ha sido actualizado. +auths.update=Actualizar origen de autenticación +auths.delete=Eliminar origen de autenticación +auths.delete_auth_title=Eliminar origen de autenticación +auths.delete_auth_desc=Eliminar un origen de autenticación impide que los usuarios lo utilicen para iniciar sesión. ¿Continuar? +auths.still_in_used=El orígen de autenticación todavía está en uso. Convierta o elimine cualquier usuario que utilice este origen de autenticación primero. +auths.deletion_success=El origen de autenticación ha sido eliminado. +auths.login_source_exist=El origen de autenticación '%s' ya existe. config.server_config=Configuración del servidor +config.app_name=Título del sitio +config.app_ver=Versión de Gitea +config.app_url=URL base de Gitea +config.custom_conf=Ruta del fichero de configuración +config.custom_file_root_path=Ruta raíz de los archivos personalizada +config.domain=Dominio del servidor SSH +config.offline_mode=Modo offline config.disable_router_log=Deshabilitar Log del Router +config.run_user=Ejecutar como usuario config.run_mode=Modo de ejecución config.git_version=Versión de Git config.repo_root_path=Ruta del Repositorio +config.lfs_root_path=Ruta raíz de LFS config.static_file_root_path=Ruta de los Ficheros Estáticos +config.log_file_root_path=Ruta de ficheros de registro config.script_type=Tipo de Script config.reverse_auth_user=Autenticación Inversa de Usuario config.ssh_config=Configuración SSH config.ssh_enabled=Habilitado +config.ssh_start_builtin_server=Utilizar servidor integrado +config.ssh_domain=Dominio del servidor config.ssh_port=Puerto config.ssh_listen_port=Puerto de escucha config.ssh_root_path=Ruta raíz @@ -1457,25 +1729,58 @@ config.ssh_keygen_path=Ruta del generador de claves ('ssh-keygen') config.ssh_minimum_key_size_check=Tamaño mínimo de la clave de verificación config.ssh_minimum_key_sizes=Tamaños de clave mínimos +config.lfs_config=Configuración LFS +config.lfs_enabled=Habilitado +config.lfs_content_path=Ruta de contenido LFS +config.lfs_http_auth_expiry=Caducidad de la autentificación HTTP LFS config.db_config=Configuración de la Base de Datos config.db_type=Tipo +config.db_host=Host config.db_name=Nombre +config.db_user=Nombre de usuario +config.db_ssl_mode=SSL config.db_path=Ruta config.service_config=Configuración del servicio +config.register_email_confirm=Requerir confirmación de correo electrónico para registrarse +config.disable_register=Deshabilitar auto-registro +config.allow_only_external_registration=Permitir el registro únicamente a través de servicios externos +config.enable_openid_signup=Habilitar el auto-registro con OpenID +config.enable_openid_signin=Habilitar el inicio de sesión con OpenID config.show_registration_button=Mostrar Botón de Registro +config.require_sign_in_view=Requerir inicio de sesión obligatorio para ver páginas +config.mail_notify=Habilitar las notificaciones por correo electrónico config.disable_key_size_check=Deshabilitar la comprobación de Tamaño Mínimo de Clave +config.enable_captcha=Activar CAPTCHA config.active_code_lives=Habilitar Vida del Código +config.reset_password_code_lives=Caducidad del código de recuperación de cuenta +config.default_keep_email_private=Ocultar direcciones de correo electrónico por defecto +config.default_allow_create_organization=Permitir la creación de organizaciones por defecto +config.enable_timetracking=Habilitar seguimiento de tiempo +config.default_enable_timetracking=Habilitar seguimiento de tiempo por defecto +config.default_allow_only_contributors_to_track_time=Deje que solo los colaboradores hagan un seguimiento del tiempo +config.no_reply_address=Dominio de correos electrónicos ocultos +config.default_visibility_organization=Visibilidad por defecto para nuevas organizaciones +config.default_enable_dependencies=Habilitar dependencias de incidencias por defecto config.webhook_config=Configuración de Webhooks config.queue_length=Tamaño de Cola de Envío config.deliver_timeout=Timeout de Entrega +config.skip_tls_verify=Saltar verificación TLS +config.mailer_config=Configuración del servidor de correo config.mailer_enabled=Activado config.mailer_disable_helo=Desactivar HELO config.mailer_name=Nombre +config.mailer_host=Servidor config.mailer_user=Usuario +config.mailer_use_sendmail=Usar Sendmail +config.mailer_sendmail_path=Ruta de Sendmail +config.mailer_sendmail_args=Argumentos adicionales por Sendmail +config.send_test_mail=Enviar prueba de correo +config.test_mail_failed=Fallo al enviar correo electrónico de prueba a '%s': %v +config.test_mail_sent=Se ha enviado un correo electrónico de prueba a '%s'. config.oauth_config=Configuración OAuth config.oauth_enabled=Activado @@ -1484,6 +1789,7 @@ config.cache_config=Configuración de la Caché config.cache_adapter=Adaptador de la Caché config.cache_interval=Intervalo de la Caché config.cache_conn=Conexión de la Caché +config.cache_item_ttl=Período de vida para elementos de caché config.session_config=Configuración de la Sesión config.session_provider=Proveedor de la Sesión @@ -1514,12 +1820,23 @@ config.git_gc_timeout=Tiempo de espera de operación de GC config.log_config=Configuración del Log config.log_mode=Modo del Log +config.macaron_log_mode=Modo de registro Macaron +config.own_named_logger=Registro Nombrado +config.routes_to_default_logger=Enviado al registro por defecto +config.go_log=Utiliza el registro de Go (redireccionado a predeterminado) +config.router_log_mode=Modo de registro del Router +config.disabled_logger=Desactivado +config.access_log_mode=Modo de registro del Acceso +config.access_log_template=Plantilla +config.xorm_log_mode=Modo de registro XORM +config.xorm_log_sql=Registrar SQL monitor.cron=Tareas de Cron monitor.name=Nombre monitor.schedule=Agenda monitor.next=Siguiente monitor.previous=Anterior +monitor.execute_times=Ejecuciones monitor.process=Procesos en ejecución monitor.desc=Descripción monitor.start=Hora de Inicio @@ -1536,11 +1853,13 @@ notices.delete_all=Eliminar todas las notificaciones notices.type=Tipo notices.type_1=Repositorio notices.desc=Descripción +notices.op=Operación notices.delete_success=Los avisos del sistema se han eliminado. [action] create_repo=creó el repositorio %s rename_repo=repositorio renombrado de %[1]s a %[3]s +commit_repo=hizó push a %[3]s en %[4]s create_issue=`incidencia abierta %s#%[2]s` close_issue=`cerró la incidencia %s#%[2]s` reopen_issue=`reabrió la incidencia %s#%[2]s` @@ -1553,6 +1872,8 @@ transfer_repo=transfirió el repositorio %s a %s push_tag=hizó push la etiqueta %[2]s a %[3]s delete_tag=etiqueta eliminada %[2]s de %[3]s delete_branch=rama %[2]s eliminada, de %[3]s +compare_commits=Comparar %d commits +compare_commits_general=Comparar commits mirror_sync_push=sincronizó cambios a %[3]s en %[4]s desde réplica mirror_sync_create=sincronizada nueva referencia %[2]s a %[3]s desde réplica mirror_sync_delete=sincronizada y eliminada referencia %[2]s en %[3]s desde réplica @@ -1580,6 +1901,8 @@ raw_seconds=segundos raw_minutes=minutos [dropzone] +default_message=Suelte archivos o haga clic aquí para subir. +invalid_input_type=No puede subir archivos de este tipo. file_too_big=El tamaño del archivo ({{filesize}} MB) excede el tamaño máximo de ({{maxFilesize}} MB). remove_file=Eliminar archivo @@ -1587,12 +1910,22 @@ remove_file=Eliminar archivo notifications=Notificaciones unread=Sin leer read=Leídas +no_unread=No tiene notificaciones sin leer. +no_read=No hay notificaciones. +pin=Fijar notificación mark_as_read=Marcar como leído mark_as_unread=Marcar como no leído +mark_all_as_read=Marcar todo como leído [gpg] error.extract_sign=Error al extraer la firma +error.generate_hash=Error al generar hash of commit +error.no_committer_account=Ninguna cuenta vinculada a la dirección de correo electrónico del committer error.no_gpg_keys_found=No se encontró ninguna clave conocida en la base de datos para esta firma +error.not_signed_commit=No es un commit firmado +error.failed_retrieval_gpg_keys=No se pudo recuperar cualquier clave adjunta a la cuenta del committer [units] +error.no_unit_allowed_repo=No tiene permisos para acceder a ninguna sección de este repositorio. +error.unit_not_allowed=No tiene permisos para acceder a esta sección del repositorio. diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 67fdaa1424..e163a7060a 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -487,6 +487,7 @@ manage_oauth2_applications=Gérer les applications OAuth2 edit_oauth2_application=Modifier l'application OAuth2 oauth2_applications_desc=Les applications OAuth2 permettent à votre application tiers d'authentifier en toute sécurité les utilisateurs de cette instance Gitea. remove_oauth2_application=Supprimer l'application OAuth2 +remove_oauth2_application_desc=Supprimer une application OAuth2 révoquera l'accès à tous les jetons d'accès signés. Continuer ? remove_oauth2_application_success=L'application a été supprimée. create_oauth2_application=Créer une nouvelle application OAuth2 create_oauth2_application_button=Créer une application @@ -618,6 +619,9 @@ migrate.permission_denied=Vous n'êtes pas autorisé à importer des dépôts lo migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas un dossier. migrate.failed=Echec de migration: %v migrate.lfs_mirror_unsupported=La synchronisation des objets LFS n'est pas supportée - veuillez utiliser 'git lfs fetch --all' et 'git lfs push --all' à la place. +migrate.migrate_items_options=Quand vous migrez depuis github, saisissez un nom d'utilisateur et des options de migration seront affichées. +migrated_from=Migré de %[2]s +migrated_from_fake=Migré de %[1]s mirror_from=miroir de forked_from=bifurqué depuis @@ -978,6 +982,9 @@ pulls.rebase_merge_commit_pull_request=Rebase et Fusion (--no-ff) pulls.squash_merge_pull_request=Squash et fusionner pulls.invalid_merge_option=Vous ne pouvez pas utiliser cette option de fusion pour cette demande. pulls.open_unmerged_pull_exists=`Vous ne pouvez pas ré-ouvrir cette demande de fusion car il y a une demande de fusion (#%d) en attente avec des propriétés identiques.` +pulls.status_checking=Certains contrôles sont en attente +pulls.status_checks_success=Tous les contrôles ont réussi +pulls.status_checks_error=Certains contrôles ont échoué milestones.new=Nouveau jalon milestones.open_tab=%d Ouvert @@ -1026,6 +1033,9 @@ wiki.save_page=Enregistrer la page wiki.last_commit_info=%s a édité cette page %s wiki.edit_page_button=Modifier wiki.new_page_button=Nouvelle Page +wiki.file_revision=Révisions de la page +wiki.wiki_page_revisions=Révisions de la page wiki +wiki.back_to_wiki=Retour à la page wiki wiki.delete_page_button=Supprimer la page wiki.delete_page_notice_1=Supprimer la page de wiki "%s" ne peut être annulé. Continuer ? wiki.page_already_exists=Une page de wiki avec le même nom existe déjà. @@ -1304,11 +1314,14 @@ settings.archive.button=Archiver ce dépôt settings.archive.header=Archiver ce dépôt settings.archive.text=Archiver ce dépôt le rendra en lecture seule. Il sera caché du tableau de bord et vous ne pourrez plus envoyer de révision ni créer de ticket ou demande d'ajout. settings.archive.success=Ce dépôt a été archivé avec succès. +settings.archive.error=Une erreur s'est produite lors de l'archivage du dépôt. Voir le journal pour plus de détails. settings.archive.error_ismirror=Vous ne pouvez pas archiver un dépôt en miroir. settings.archive.branchsettings_unavailable=Le paramétrage des branches n'est pas disponible quand le dépôt est archivé. settings.unarchive.button=Désarchiver ce dépôt settings.unarchive.header=Désarchiver ce dépôt +settings.unarchive.text=Désarchiver le dépôt lui permettra de recevoir des révisions, ainsi que des nouveaux tickets ou demandes d'ajout. settings.unarchive.success=Ce dépôt a été désarchivé avec succès. +settings.unarchive.error=Une erreur s'est produite durant le désarchivage du dépôt. Voir le journal pour plus de détails. settings.update_avatar_success=L'avatar du dépôt a été mis à jour. diff.browse_source=Parcourir la source @@ -1716,6 +1729,10 @@ config.ssh_keygen_path=Chemin vers le générateur de clefs ("ssh-keygen") config.ssh_minimum_key_size_check=Vérification de la longueur de clé minimale config.ssh_minimum_key_sizes=Tailles de clé minimales +config.lfs_config=Configuration LFS +config.lfs_enabled=Activé +config.lfs_content_path=Chemin de contenu LFS +config.lfs_http_auth_expiry=Expiration de l'authentification HTTP LFS config.db_config=Configuration de la base de données config.db_type=Type @@ -1856,6 +1873,7 @@ push_tag=a soumis le tag %[2]s sur % delete_tag=étiquette supprimée %[2]s de %[3]s delete_branch=branche %[2]s supprimée de %[3]s compare_commits=Comparer %d révisions +compare_commits_general=Comparer les révisions mirror_sync_push=a synchronisé des révisions dans %[3]s vers %[4]s depuis le miroir mirror_sync_create=a synchronisé la nouvelle référence %[2]s vers %[3]s depuis le miroir mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence %[2]s vers %[3]s depuis le miroir diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index dd46bcffcb..605c13f69b 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -620,6 +620,8 @@ migrate.invalid_local_path=O caminho local é inválido. Ele não existe ou não migrate.failed=Migração falhou: %v migrate.lfs_mirror_unsupported=Espelhamento de objetos Git LFS não é suportado; ao invés use 'git lfs fetch --all' e 'git lfs push --all'. migrate.migrate_items_options=Ao migrar do github, insira um nome de usuário e as opções de migração serão exibidas. +migrated_from=Migrado de %[2]s +migrated_from_fake=Migrado de %[1]s mirror_from=espelhamento de forked_from=feito fork de @@ -980,6 +982,9 @@ pulls.rebase_merge_commit_pull_request=Aplicar Rebase e Merge (--no-ff) pulls.squash_merge_pull_request=Aplicar Squash e Merge pulls.invalid_merge_option=Você não pode usar esta opção de merge neste pull request. pulls.open_unmerged_pull_exists=`Não é possível executar uma operação de reabertura pois há um pull request pendente (#%d) com propriedades idênticas.` +pulls.status_checking=Algumas verificações estão pendentes +pulls.status_checks_success=Todas as verificações foram bem sucedidas +pulls.status_checks_error=Algumas verificações falharam milestones.new=Novo marco milestones.open_tab=%d Aberto @@ -1028,6 +1033,9 @@ wiki.save_page=Salvar página wiki.last_commit_info=%s editou esta página %s wiki.edit_page_button=Editar wiki.new_page_button=Nova página +wiki.file_revision=Revisão de página +wiki.wiki_page_revisions=Revisões de página Wiki +wiki.back_to_wiki=Voltar para página Wiki wiki.delete_page_button=Excluir página wiki.delete_page_notice_1=A exclusão da página de wiki '%s' não pode ser desfeita. Continuar? wiki.page_already_exists=Uma página de wiki com o mesmo nome já existe. @@ -1865,6 +1873,7 @@ push_tag=realizou push da tag %[2]s para %[3]s delete_branch=excluiu branch %[2]s de %[3]s compare_commits=Compare %d commits +compare_commits_general=Comparar commits mirror_sync_push=commits sincronizados para %[3]s em %[4]s do espelhamento mirror_sync_create=nova referência sincronizada %[2]s para %[3]s do espelhamento mirror_sync_delete=referência excluída e sincronizada %[2]s em %[3]s do espelhamento From 0622e830557fcf63c73541394a56ba23a700a65a Mon Sep 17 00:00:00 2001 From: Cherrg Date: Mon, 8 Jul 2019 19:11:04 +0200 Subject: [PATCH 213/220] add missing template variable on organisation settings (#7385) fix #6755 Signed-off-by: Michael Gnehr --- routers/org/setting.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/org/setting.go b/routers/org/setting.go index 0526a96e6f..b3ff01d238 100644 --- a/routers/org/setting.go +++ b/routers/org/setting.go @@ -39,6 +39,7 @@ func Settings(ctx *context.Context) { func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) { ctx.Data["Title"] = ctx.Tr("org.settings") ctx.Data["PageIsSettingsOptions"] = true + ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility) if ctx.HasError() { ctx.HTML(200, tplSettingsOptions) From 3c3f74988ac25962b7d72ad32a70b399e5c0f2bc Mon Sep 17 00:00:00 2001 From: Cherrg Date: Mon, 8 Jul 2019 21:18:09 +0200 Subject: [PATCH 214/220] ui fixes - compare view and archieved repo issues (#7345) * add 'repo archived - comment/pull not possible' message affects #7304 Signed-off-by: Michael Gnehr * add navbar to compare view Signed-off-by: Michael Gnehr * remove wrong if else Signed-off-by: Michael Gnehr --- templates/repo/diff/compare.tmpl | 14 +++++++++++--- templates/repo/header.tmpl | 6 ++---- templates/repo/issue/view_content.tmpl | 8 ++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index 877241fb39..1c8942d42f 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -5,8 +5,12 @@ {{if .PageIsComparePull}}

      - {{.i18n.Tr "repo.pulls.compare_changes"}} -
      {{.i18n.Tr "repo.pulls.compare_changes_desc"}}
      + {{if not .Repository.IsArchived}} + {{.i18n.Tr "repo.pulls.compare_changes"}} +
      {{.i18n.Tr "repo.pulls.compare_changes_desc"}}
      + {{ else }} + {{.i18n.Tr "action.compare_commits_general"}} + {{ end }}

      @@ -60,7 +64,11 @@
      - {{end}} + {{ else }} +
      + {{.i18n.Tr "repo.archive.title"}} +
      + {{ end }} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index f4eefd3fde..f264a9b559 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -46,7 +46,7 @@
      {{end}} -{{if not .IsDiffCompare}} +
      -{{else}} -
      -{{end}} +
      diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index b3f88c662d..acabe34782 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -107,6 +107,14 @@
      + {{ else if .Repository.IsArchived }} +
      + {{if .Issue.IsPull}} + {{.i18n.Tr "repo.archive.pull.nocomment"}} + {{else}} + {{.i18n.Tr "repo.archive.issue.nocomment"}} + {{end}} +
      {{ end }} {{else}} {{if .Repository.IsArchived}} From d7fccb29de20f0296a85b810f4ef08effd258c84 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Mon, 8 Jul 2019 22:24:52 -0400 Subject: [PATCH 215/220] Fetch refs for successful testing for tag (#7388) * Fetch refs for successful testing for tag Fix #7382 * Update .drone.yml --- .drone.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 086b5cd2b5..c07179b95d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -116,6 +116,17 @@ steps: - push - pull_request + - name: tag-pre-condition + pull: always + image: alpine/git + commands: + - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA} + depends_on: + - build + when: + event: + - tag + - name: tag-test pull: always image: golang:1.12 @@ -124,7 +135,7 @@ steps: environment: TAGS: bindata depends_on: - - build + - tag-pre-condition when: event: - tag From 46d3d10d77e878b463a4880ff8a484c176effb80 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 9 Jul 2019 02:27:49 +0000 Subject: [PATCH 216/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 1 - options/locale/locale_ja-JP.ini | 5 +++ options/locale/locale_nl-NL.ini | 72 +++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 6595ff2dae..cd77156202 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -305,7 +305,6 @@ password_not_match=Las contraseñas no coinciden. username_been_taken=El nombre de usuario ya está en uso. repo_name_been_taken=El nombre del repositorio ya está usado. -visit_rate_limit=Limitar tasa a visitas remotas. 2fa_auth_required=Requerir autenticación de doble factor a visitas remotas. org_name_been_taken=Ya existe una organización con este nombre. team_name_been_taken=Ya existe un equipo con este nombre. diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 79ddc673c2..c2f57a7f79 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -620,6 +620,8 @@ migrate.invalid_local_path=ローカルパスが無効です。 存在しない migrate.failed=移行に失敗しました: %v migrate.lfs_mirror_unsupported=LFSオブジェクトのミラーはサポートされていません。 代わりに 'git lfs fetch --all' と 'git lfs push --all' を使ってください。 migrate.migrate_items_options=移行元がGitHubの場合は、ユーザー名を入力すると移行オプションが表示されます。 +migrated_from=%[2]sから移行 +migrated_from_fake=%[1]sから移行 mirror_from=ミラー元 forked_from=フォーク元 @@ -1031,6 +1033,9 @@ wiki.save_page=ページを保存 wiki.last_commit_info=%s が %s にこのページを編集 wiki.edit_page_button=編集 wiki.new_page_button=新規ページ +wiki.file_revision=ページ・リビジョン +wiki.wiki_page_revisions=Wikiページのリビジョン +wiki.back_to_wiki=Wikiページに戻る wiki.delete_page_button=ページを削除 wiki.delete_page_notice_1=Wikiページ '%s' の削除は元に戻せません。 続行しますか? wiki.page_already_exists=既に同じ名前のWiki ページが存在します。 diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index ecbe980bc8..f0a9d02981 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -491,7 +491,9 @@ passcode_invalid=De code is niet correct. Probeer het nogmaals. u2f_register_key=Voeg beveiligingssleutel toe u2f_nickname=Gebruikersnaam +u2f_press_button=Druk op de knop op je beveiligingssleutel om hem te registreren. u2f_delete_key=Verwijder beveiligingssleutel +u2f_delete_key_desc=Als je een beveiligingssleutel verwijdert, kan je er niet meer mee inloggen. Doorgaan? manage_account_links=Gekoppelde accounts beheren manage_account_links_desc=Deze externe accounts zijn gekoppeld aan je Gitea-account. @@ -504,6 +506,7 @@ orgs_none=U bent geen lid van een organisatie. repos_none=U bezit geen repositories delete_account=Verwijder uw account +delete_prompt=Als je doorgaat, wordt je gebruikersaccount permanent verwijderd. Dit KAN NIET ongedaan gemaakt worden. confirm_delete_account=Bevestig verwijdering delete_account_title=Verwijder gebruikers account delete_account_desc=Weet je zeker dat je dit gebruikersaccount permanent wil verwijderen? @@ -518,13 +521,19 @@ visibility_helper_forced=De sitebeheerder verplicht alle repositories om privé visibility_fork_helper=(Verandering van deze waarde zal van invloed zijn op alle forks) fork_repo=Repository forken fork_from=Afsplitsing van +fork_visibility_helper=De zichtbaarheid van een geforkte repository kan niet worden veranderd. repo_desc=Omschrijving repo_lang=Taal +repo_gitignore_helper=Selecteer .gitignore templates. license=Licentie +license_helper=Selecteer een licentie bestand. readme=README +readme_helper=Selecteer een README-bestandssjabloon. +auto_init=Initialiseer repository (voegt .gitignore, License en README toe) create_repo=Nieuwe repository default_branch=Standaard branch mirror_prune=Opschonen +mirror_prune_desc=Verwijder verouderde remote-tracking-referenties mirror_address=Klonen van URL mirror_last_synced=Laatst gesynchroniseerd watchers=Volgers @@ -536,18 +545,28 @@ reactions_more=en %d meer form.reach_limit_of_creation=U hebt uw limiet van %d repositories al bereikt. form.name_reserved=Repositorienaam '%s' is gereserveerd. +form.name_pattern_not_allowed=Het patroon '%s' is niet toegestaan in de naam van een repository. migrate_type=Migratie type migrate_type_helper=Deze repository zal een kopie zijn +migrate_items_wiki=Wiki +migrate_items_milestones=Mijlpalen +migrate_items_labels=Labels migrate_repo=Migreer repository +migrate.clone_address=Migreer / kloon van URL +migrate.clone_address_desc=De HTTP(s)- of 'git clone'-URL van een bestaande repository migrate.clone_local_path=of een lokaal pad migrate.permission_denied=U bent niet gemachtigd om deze lokale repositories te importeren. +migrate.invalid_local_path=Het lokale pad is ongeldig, bestaat niet of is geen map. migrate.failed=Migratie is mislukt: %v +migrate.lfs_mirror_unsupported=Het kopiëren van LFS-objecten wordt niet ondersteund - gebruik in plaats daarvan 'git lfs fetch --all' en 'git lfs push --all'. mirror_from=kopie van forked_from=geforked van +fork_from_self=U kunt geen repository forken die u al heeft. copy_link=Kopieer copy_link_success=De link is gekopieerd +copy_link_error=Druk op ⌘-C of Ctrl-C om te kopiëren copied=Gekopieerd unwatch=Negeren watch=Volgen @@ -561,8 +580,10 @@ quick_guide=Snelstart gids clone_this_repo=Kloon deze repository create_new_repo_command=Maak een nieuwe repository aan vanaf de console push_exist_repo=Push een bestaande repositorie vanaf de console +empty_message=Deze repository bevat geen inhoud. code=Code +code.desc=Toegang tot broncode, bestanden, commits en branches. branch=Branch tree=Tree filter_branch_and_tag=Filter op branch of tag @@ -579,6 +600,9 @@ file_raw=Ruw file_history=Geschiedenis file_view_raw=Weergave ruw bestand file_permalink=Permalink +file_too_large=Dit bestand is te groot om te tonen. +video_not_supported_in_browser=Je browser ondersteunt de HTML5 'video'-tag niet. +audio_not_supported_in_browser=Je browser ondersteunt de HTML5 'audio'-tag niet. stored_lfs=Opgeslagen met Git LFS commit_graph=Commit grafiek @@ -586,6 +610,7 @@ editor.new_file=Nieuw bestand editor.upload_file=Upload bestand editor.edit_file=Bewerk bestand editor.preview_changes=Voorbeeld tonen +editor.cannot_edit_non_text_files=Binaire bestanden kunnen niet worden bewerkt in de webinterface. editor.edit_this_file=Bewerk bestand editor.delete_this_file=Verwijder bestand editor.file_delete_success=Bestand '%s' is verwijderd. @@ -770,9 +795,13 @@ issues.dependency.add=Voeg afhankelijkheid toe… issues.dependency.cancel=Annuleer issues.dependency.remove=Verwijder issues.dependency.remove_info=Verwijder afhankelijkheid +issues.dependency.blocks_short=Blokkeert issues.dependency.blocked_by_short=Afhankelijk van issues.dependency.remove_header=Verwijder afhankelijkheid +issues.dependency.add_error_dep_not_exist=Afhankelijkheid bestaat niet. +issues.dependency.add_error_dep_exists=Afhankelijkheid bestaat al. issues.review.comment=beoordeeld %s +issues.review.content.empty=Je moet een reactie achterlaten die de gewenste verandering(en) beschrijft. issues.review.pending=In behandeling issues.review.review=Review issues.review.reviewers=Reviewers @@ -780,6 +809,7 @@ issues.review.show_outdated=Toon verouderd issues.review.hide_outdated=Verouderde verbergen pulls.new=Nieuwe Pull aanvraag +pulls.compare_changes_desc=Selecteer de samen te voegen doel- en bron-branch. pulls.compare_base=samenvoegen met pulls.compare_compare=trekken van pulls.filter_branch=Filter branch @@ -804,12 +834,14 @@ milestones.closed=%s werd gesloten milestones.no_due_date=Geen vervaldatum milestones.open=Open milestones.close=Sluit +milestones.new_subheader=Gebruik mijlpalen om kwesties te organiseren en om voortgang bij te houden. milestones.completeness=%d%% Voltooid milestones.create=Mijlpaal maken milestones.title=Titel milestones.desc=Beschrijving milestones.due_date=Vervaldatum (optioneel) milestones.clear=Leegmaken +milestones.invalid_due_date_format=Het formaat van de deadline is moet 'jjjj-mm-dd' zijn. milestones.create_success=De mijlpaal '%s' is aangemaakt. milestones.edit=Bewerk mijlpaal milestones.cancel=Annuleer @@ -908,10 +940,13 @@ settings.tracker_url_format=URL-formaat externe issuetracker settings.tracker_issue_style.numeric=Nummeriek settings.tracker_issue_style.alphanumeric=Alfanummeriek settings.enable_timetracker=Tijdregistratie inschakelen +settings.admin_settings=Beheerdersinstellingen settings.danger_zone=Gevaren zone settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repository met deze naam +settings.convert=Converteren naar gewone repository settings.convert_confirm=Converteer Repository settings.transfer=Eigendom overdragen +settings.transfer_form_title=Voer de repository naam in als bevestiging: settings.wiki_delete=Wiki-gegevens verwijderen settings.confirm_wiki_delete=Wiki-gegevens verwijderen settings.delete=Verwijder deze repository @@ -929,7 +964,9 @@ settings.collaborator_deletion=Verwijder medewerker settings.search_user_placeholder=Zoek gebruiker… settings.add_webhook=Webhook toevoegen settings.webhook_deletion=Verwijder webhook +settings.webhook_deletion_success=Webhook is verwijderd. settings.webhook.test_delivery=Test-bezorging +settings.webhook.test_delivery_desc=Test deze webhook met een nep-gebeurtenis. settings.webhook.request=Verzoek settings.webhook.response=Antwoord settings.webhook.headers=Headers @@ -951,15 +988,20 @@ settings.event_send_everything=Alle gebeurtenissen settings.event_create=Creëer settings.event_create_desc=Branch, of tag aangemaakt. settings.event_delete=Verwijder +settings.event_delete_desc=Branch of tag verwijderd settings.event_fork=Fork settings.event_fork_desc=Repository geforked settings.event_issues=Kwesties settings.event_release=Release settings.event_pull_request=Pull request settings.event_push=Push +settings.event_push_desc=Git push naar een repository. settings.event_repository=Repository +settings.event_repository_desc=Repository gemaakt of verwijderd. settings.active=Actief +settings.add_hook_success=De webhook is toegevoegd. settings.update_webhook=Bewerk webhook +settings.update_hook_success=Webhook is bijgewerkt. settings.delete_webhook=Verwijder webhook settings.recent_deliveries=Recente bezorgingen settings.hook_type=Type hook @@ -977,13 +1019,16 @@ settings.protected_branch=Branch bescherming settings.protected_branch_can_push=Push toestaan? settings.protected_branch_can_push_yes=U mag pushen settings.protected_branch_can_push_no=U mag niet pushen +settings.protect_this_branch=Branch bescherming inschakelen settings.protect_whitelist_search_users=Zoek gebruiker… settings.protect_whitelist_search_teams=Zoek teams… settings.protect_required_approvals=Vereiste goedkeuringen: settings.add_protected_branch=Bescherming aanzetten settings.delete_protected_branch=Bescherming uitzetten +settings.protected_branch_deletion=Branch bescherming uitschakelen settings.choose_branch=Kies een branch… settings.edit_protected_branch=Bewerken +settings.chat_id=Chat-ID diff.browse_source=Bladeren bron diff.parent=bovenliggende @@ -994,18 +1039,22 @@ diff.show_split_view=Zij-aan-zij weergave diff.show_unified_view=Gecombineerde weergave diff.whitespace_button=Witregel diff.whitespace_show_everything=Toon alle wijzigingen +diff.whitespace_ignore_at_eol=Negeren van wijzigingen in witruimte op EOL diff.stats_desc=%d gewijzigde bestanden met toevoegingen van %d en %d verwijderingen diff.bin=BIN diff.view_file=Bestand weergeven diff.file_suppressed=Diff onderdrukt omdat het te groot bestand diff.comment.placeholder=Opmerking toevoegen +diff.comment.markdown_info=Styling met markdown wordt ondersteund. diff.comment.add_single_comment=Één reactie toevoegen diff.comment.add_review_comment=Voeg commentaar toe +diff.comment.start_review=Review starten diff.comment.reply=Reageer diff.review=Review diff.review.header=Review versturen diff.review.comment=Opmerking diff.review.approve=Goedkeuren +diff.review.reject=Wijzigingen aanvragen release.releases=Publicaties release.new_release=Nieuwe release @@ -1017,25 +1066,33 @@ release.ahead=%d aanpassingen aan %s sinds deze versie release.source_code=Broncode release.tag_name=Tagnaam release.target=Doel +release.tag_helper=Kies een bestaande tag, of creëer een nieuwe tag bij publiceren. release.title=Titel release.content=Inhoud release.prerelease_desc=Markeren als voorlopige versie +release.prerelease_helper=Markeer deze release als ongeschikt voor productiedoeleinden. release.cancel=Annuleren release.publish=Release publiceren release.save_draft=Concept opslaan release.edit_release=Update release release.delete_release=Verwijder release release.deletion=Verwijder release +release.tag_name_already_exist=Een versie met deze naam bestaat al. release.downloads=Downloads branch.name=Branch naam branch.search=Zoek branches +branch.already_exists=Een branch genaamd '%s' bestaat al. branch.delete_head=Verwijder branch.delete=Verwijder branch '%s' branch.delete_html=Verwijder branch +branch.deletion_success=Branch '%s' is verwijderd. branch.create_branch=Maak branch %s branch.create_from=van '%s' +branch.create_success=Branch '%s' is aangemaakt. +branch.branch_already_exists=Branch '%s' bestaat al in deze repository. branch.deleted_by=Verwijderd door %s +branch.restore_success=Branch '%s' is hersteld. topic.manage_topics=Beheer topics topic.done=Klaar @@ -1056,15 +1113,18 @@ team_name=Teamnaam team_desc=Omschrijving team_permission_desc=Machtiging +form.create_org_not_allowed=U mag geen organisaties maken. settings=Instellingen settings.options=Organisatie settings.full_name=Volledige naam settings.website=Website settings.location=Locatie +settings.visibility.public=Publiek settings.update_settings=Instellingen bijwerken settings.update_setting_success=Organisatie instellingen zijn succesvol bijgewerkt. +settings.update_avatar_success=De avatar van de organisatie is aangepast. settings.delete=Verwijder organisatie settings.delete_account=Verwijder deze organisatie settings.confirm_delete_account=Bevestig verwijdering @@ -1100,6 +1160,7 @@ teams.search_repo_placeholder=Repository zoeken… teams.add_team_repository=Nieuwe teamrepositorie aanmaken teams.remove_repo=Verwijder teams.add_nonexistent_repo=De opslagplaats die u probeert toe te voegen bestaat niet: maak deze eerst aan. +teams.add_duplicate_users=Gebruiker is al een teamlid. [admin] dashboard=Overzicht @@ -1262,12 +1323,16 @@ config.show_registration_button=Registeren knop weergeven config.disable_key_size_check=Controle op key-lengte uitschakelen config.enable_captcha=CAPTCHA inschakelen config.active_code_lives=Actieve Code leven +config.default_allow_create_organization=Standaard toestaan om organisaties aan te maken +config.enable_timetracking=Tijdregistratie inschakelen +config.default_enable_timetracking=Tijdregistratie standaard inschakelen config.no_reply_address=Verborgen e-maildomein config.webhook_config=Webhook configuratie config.queue_length=Lengte van wachtrij config.deliver_timeout=Bezorging verlooptijd +config.mailer_config=SMTP Mailerconfiguatie config.mailer_enabled=Ingeschakeld config.mailer_disable_helo=Schakel HELO uit config.mailer_name=Naam @@ -1275,7 +1340,10 @@ config.mailer_host=Host config.mailer_user=Gebruiker config.mailer_use_sendmail=Gebruik Sendmail config.mailer_sendmail_path=Sendmail pad +config.mailer_sendmail_args=Extra argumenten voor Sendmail config.send_test_mail=Test e-mail verzenden +config.test_mail_failed=Verzenden van een testmail naar '%s' is mislukt: %v +config.test_mail_sent=Test-email is verstuurd naar '%s'. config.oauth_config=OAuth-configuratie config.oauth_enabled=Ingeschakeld @@ -1295,8 +1363,10 @@ config.session_life_time=Sessie duur config.https_only=Alleen HTTPS config.cookie_life_time=Cookie duur leeftijd +config.picture_config=Foto en avatar configuratie config.picture_service=Foto service config.disable_gravatar=Gravatar uitschakelen +config.enable_federated_avatar=Federated avatars toestaan config.git_config=Git configuratie config.git_gc_args=GC Parameters @@ -1365,6 +1435,8 @@ raw_seconds=seconden raw_minutes=minuten [dropzone] +default_message=Sleep bestanden hier heen of klik om te uploaden. +invalid_input_type=U kunt geen bestanden van dit type uploaden. file_too_big=Bestandsgrootte ({{filesize}} MB) overschrijdt de maximale grootte ({{maxFilesize}} MB). remove_file=Verwijder bestand From f03e5b7c3e4d0b01f3832d4fbb54b4917f4f2d1b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 9 Jul 2019 14:27:02 +0800 Subject: [PATCH 217/220] fix vendor (#7394) --- go.mod | 2 +- go.sum | 4 ++-- vendor/modules.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 088f987b4d..0820c0a8e9 100644 --- a/go.mod +++ b/go.mod @@ -135,4 +135,4 @@ require ( xorm.io/core v0.6.3 ) -replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 +replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 diff --git a/go.sum b/go.sum index e074914c8c..47d096be50 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 h1:x0uHqLQTSEL9LKic8sWDt3ASkq07ve5ojIIUl5uF64M= -github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 h1:DWxZh2sImfCFn/79OUBhzFkPTKnsdDzXH/JTxpw5n6w= +github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= diff --git a/vendor/modules.txt b/vendor/modules.txt index 539a57697f..f19057e8ac 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -87,7 +87,7 @@ github.com/couchbase/vellum/utf8 github.com/couchbaselabs/go-couchbase # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 +# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp # github.com/dgrijalva/jwt-go v3.2.0+incompatible From 877df0f9fbb3872f9af06067ea6371d14eecd3b3 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 9 Jul 2019 06:30:32 +0000 Subject: [PATCH 218/220] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index aee909e059..1eb82ef403 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -620,6 +620,8 @@ migrate.invalid_local_path=无效的本地路径,不存在或不是一个目 migrate.failed=迁移失败:%v migrate.lfs_mirror_unsupported=不支持镜像 LFS 对象 - 使用 'git lfs fetch --all' 和 'git lfs push --all' 替代。 migrate.migrate_items_options=当从 github 迁移并且输入了用户名时,迁移选项将会显示。 +migrated_from=从 %[2]s 迁移 +migrated_from_fake=从 %[1]s 迁移成功 mirror_from=镜像自地址 forked_from=派生自 @@ -1031,6 +1033,9 @@ wiki.save_page=保存页面 wiki.last_commit_info=%s 于 %s 修改了此页面 wiki.edit_page_button=修改 wiki.new_page_button=新的页面 +wiki.file_revision=页面历史 +wiki.wiki_page_revisions=页面历史 +wiki.back_to_wiki=返回百科 wiki.delete_page_button=删除页面 wiki.delete_page_notice_1=百科页面 '%s' 删除后无法恢复,是否继续? wiki.page_already_exists=相同名称的 Wiki 页面已经存在。 From b84a251fca78784682d49e3699eaae51203f8ffd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 10 Jul 2019 13:26:42 +0800 Subject: [PATCH 219/220] upgrade macaron/captcha to fix random error problem (#7407) --- go.mod | 2 +- go.sum | 4 +-- .../github.com/go-macaron/captcha/.travis.yml | 14 ++++------ .../github.com/go-macaron/captcha/captcha.go | 26 ++++++++++++++----- vendor/github.com/go-macaron/captcha/image.go | 25 +++++++++++------- vendor/modules.txt | 2 +- 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index 0820c0a8e9..8fdf57b3fc 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 - github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab + github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f diff --git a/go.sum b/go.sum index 47d096be50..8a617be49c 100644 --- a/go.sum +++ b/go.sum @@ -113,8 +113,8 @@ github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76u github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM= github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw= github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok= -github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI= -github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA= +github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df h1:MdgvtI3Y1u/DHNj7xUGOqAv+KGoTikjy8xQtCm12L78= +github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA= github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8= github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E= github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo= diff --git a/vendor/github.com/go-macaron/captcha/.travis.yml b/vendor/github.com/go-macaron/captcha/.travis.yml index 2774fb35d5..81680f0f02 100644 --- a/vendor/github.com/go-macaron/captcha/.travis.yml +++ b/vendor/github.com/go-macaron/captcha/.travis.yml @@ -1,14 +1,10 @@ sudo: false language: go - go: - - 1.3 - - 1.4 - - 1.5 - - tip + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x script: go test -v -cover -race - -notifications: - email: - - u@gogs.io diff --git a/vendor/github.com/go-macaron/captcha/captcha.go b/vendor/github.com/go-macaron/captcha/captcha.go index dc97f0fddd..91e6386651 100644 --- a/vendor/github.com/go-macaron/captcha/captcha.go +++ b/vendor/github.com/go-macaron/captcha/captcha.go @@ -19,6 +19,7 @@ package captcha import ( "fmt" "html/template" + "image/color" "path" "strings" @@ -49,6 +50,7 @@ type Captcha struct { ChallengeNums int Expiration int64 CachePrefix string + ColorPalette color.Palette } // generate key string @@ -61,16 +63,21 @@ func (c *Captcha) genRandChars() string { return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...)) } -// tempalte func for output html -func (c *Captcha) CreateHtml() template.HTML { +// CreateHTML outputs HTML for display and fetch new captcha images. +func (c *Captcha) CreateHTML() template.HTML { value, err := c.CreateCaptcha() if err != nil { panic(fmt.Errorf("fail to create captcha: %v", err)) } - return template.HTML(fmt.Sprintf(` - - - `, c.FieldIdName, value, c.SubURL, c.URLPrefix, value, c.SubURL, c.URLPrefix, value)) + return template.HTML(fmt.Sprintf(` + + + `, c.FieldIdName, value, c.SubURL, c.URLPrefix)) +} + +// DEPRECATED +func (c *Captcha) CreateHtml() template.HTML { + return c.CreateHTML() } // create a new captcha id @@ -139,6 +146,9 @@ type Options struct { Expiration int64 // Cache key prefix captcha characters. Default is "captcha_". CachePrefix string + // ColorPalette holds a collection of primary colors used for + // the captcha's text. If not defined, a random color will be generated. + ColorPalette color.Palette } func prepareOptions(options []Options) Options { @@ -192,6 +202,7 @@ func NewCaptcha(opt Options) *Captcha { ChallengeNums: opt.ChallengeNums, Expiration: opt.Expiration, CachePrefix: opt.CachePrefix, + ColorPalette: opt.ColorPalette, } } @@ -229,9 +240,10 @@ func Captchaer(options ...Options) macaron.Handler { } } - if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight).WriteTo(ctx.Resp); err != nil { + if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight, cpt.ColorPalette).WriteTo(ctx.Resp); err != nil { panic(fmt.Errorf("write captcha: %v", err)) } + ctx.Status(200) return } diff --git a/vendor/github.com/go-macaron/captcha/image.go b/vendor/github.com/go-macaron/captcha/image.go index 0bd5cb536f..abe087437a 100644 --- a/vendor/github.com/go-macaron/captcha/image.go +++ b/vendor/github.com/go-macaron/captcha/image.go @@ -265,16 +265,22 @@ func randFloat(from, to float64) float64 { return (to-from)*prng.Float64() + from } -func randomPalette() color.Palette { +func randomPalette(primary color.Palette) color.Palette { p := make([]color.Color, circleCount+1) // Transparent color. p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00} // Primary color. - prim := color.RGBA{ - uint8(randIntn(129)), - uint8(randIntn(129)), - uint8(randIntn(129)), - 0xFF, + var prim color.RGBA + if len(primary) == 0 { + prim = color.RGBA{ + uint8(randIntn(129)), + uint8(randIntn(129)), + uint8(randIntn(129)), + 0xFF, + } + } else { + r, g, b, a := primary[randIntn(len(primary)-1)].RGBA() + prim = color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)} } p[1] = prim // Circle colors. @@ -285,10 +291,11 @@ func randomPalette() color.Palette { } // NewImage returns a new captcha image of the given width and height with the -// given digits, where each digit must be in range 0-9. -func NewImage(digits []byte, width, height int) *Image { +// given digits, where each digit must be in range 0-9. The digit's color is +// chosen by random from the colorPalette. +func NewImage(digits []byte, width, height int, colorPalette color.Palette) *Image { m := new(Image) - m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette()) + m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette(colorPalette)) m.calculateSizes(width, height, len(digits)) // Randomly position captcha inside the image. maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize diff --git a/vendor/modules.txt b/vendor/modules.txt index f19057e8ac..0e9d3c3163 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -124,7 +124,7 @@ github.com/go-macaron/binding github.com/go-macaron/cache github.com/go-macaron/cache/memcache github.com/go-macaron/cache/redis -# github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab +# github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df github.com/go-macaron/captcha # github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 github.com/go-macaron/cors From a0820e09fbf78f84722b44563b5f44a92a8a5a0e Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Thu, 11 Jul 2019 07:27:57 +0200 Subject: [PATCH 220/220] Add section about customizing mail (#7419) See https://github.com/go-gitea/gitea/issues/6037 --- .../doc/advanced/customizing-gitea.en-us.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md index 69cf58b3bf..460ea61eac 100644 --- a/docs/content/doc/advanced/customizing-gitea.en-us.md +++ b/docs/content/doc/advanced/customizing-gitea.en-us.md @@ -98,6 +98,20 @@ Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful temp - `body_outer_post.tmpl`, before the bottom `