mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-10 15:32:55 +09:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bafa9ff432 | ||
|
|
bac388d27c | ||
|
|
4ff6effe04 | ||
|
|
84a5b81d27 | ||
|
|
84f41d9d92 | ||
|
|
acb9ae4c4d | ||
|
|
b76d899f7a | ||
|
|
9f33aa61bd | ||
|
|
d0bbfd835f | ||
|
|
c7bbfd8f5e | ||
|
|
59a64c0e1d | ||
|
|
6a86a82368 |
16
.drone.yml
16
.drone.yml
@@ -82,7 +82,7 @@ pipeline:
|
||||
when:
|
||||
event: [ push, tag, pull_request ]
|
||||
|
||||
test:
|
||||
unit-test:
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
@@ -94,7 +94,7 @@ pipeline:
|
||||
event: [ push, pull_request ]
|
||||
branch: [ master ]
|
||||
|
||||
test:
|
||||
release-test:
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
@@ -106,7 +106,7 @@ pipeline:
|
||||
event: [ push, pull_request ]
|
||||
branch: [ release/* ]
|
||||
|
||||
test:
|
||||
tag-test:
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
@@ -146,7 +146,7 @@ pipeline:
|
||||
event: [ push, pull_request ]
|
||||
branch: [ master ]
|
||||
|
||||
test-mysql:
|
||||
tag-test-mysql:
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
@@ -240,12 +240,13 @@ pipeline:
|
||||
event: [ push ]
|
||||
branch: [ master ]
|
||||
|
||||
docker:
|
||||
release-docker:
|
||||
image: plugins/docker:17.12
|
||||
pull: true
|
||||
secrets: [ docker_username, docker_password ]
|
||||
repo: gitea/gitea
|
||||
tags: [ '${DRONE_BRANCH##release/v}' ]
|
||||
cache_from: gitea/gitea
|
||||
when:
|
||||
event: [ push ]
|
||||
branch: [ release/* ]
|
||||
@@ -255,6 +256,7 @@ pipeline:
|
||||
secrets: [ docker_username, docker_password ]
|
||||
pull: true
|
||||
repo: gitea/gitea
|
||||
cache_from: gitea/gitea
|
||||
default_tags: true
|
||||
when:
|
||||
event: [ push, tag ]
|
||||
@@ -271,7 +273,7 @@ pipeline:
|
||||
when:
|
||||
event: [ push, tag ]
|
||||
|
||||
release:
|
||||
tag-release:
|
||||
image: plugins/s3:1
|
||||
pull: true
|
||||
secrets: [ aws_access_key_id, aws_secret_access_key ]
|
||||
@@ -285,7 +287,7 @@ pipeline:
|
||||
when:
|
||||
event: [ tag ]
|
||||
|
||||
release:
|
||||
release-branch-release:
|
||||
image: plugins/s3:1
|
||||
pull: true
|
||||
secrets: [ aws_access_key_id, aws_secret_access_key ]
|
||||
|
||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -4,6 +4,27 @@ 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.7.6](https://github.com/go-gitea/gitea/releases/tag/v1.7.6) - 2019-04-12
|
||||
* SECURITY
|
||||
* Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6595)
|
||||
* BUGFIXES
|
||||
* Allow resend of confirmation email when logged in (#6482) (#6487)
|
||||
|
||||
## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27
|
||||
* BUGFIXES
|
||||
* Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423)
|
||||
* Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383)
|
||||
* Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332)
|
||||
|
||||
## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12
|
||||
* SECURITY
|
||||
* Fix potential XSS vulnerability in repository description. (#6306) (#6308)
|
||||
* BUGFIXES
|
||||
* Fix wrong release commit id (#6224) (#6300)
|
||||
* Fix panic on empty signed commits (#6292) (#6300)
|
||||
* Fix organization dropdown not being scrollable when using mouse wheel (#5988) (#6246)
|
||||
* Fix displaying dashboard even if required to change password (#6214) (#6215)
|
||||
|
||||
## [1.7.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27
|
||||
* BUGFIXES
|
||||
* Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197)
|
||||
|
||||
14
Gopkg.lock
generated
14
Gopkg.lock
generated
@@ -3,11 +3,11 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ab875622908a804a327a95a1701002b150806a3c5406df51ec231eac16d3a1ca"
|
||||
digest = "1:e1fa64238b0a2dbf1edf98c4af8d1b8cb65179e286d7f28006b50fa9f508ee9d"
|
||||
name = "code.gitea.io/git"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "389d3c803e12a30dffcbb54a15c2242521bc4333"
|
||||
revision = "74d7c14dd4a3ed9c5def0dc3c1aeede399ddc5c5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -666,6 +666,14 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:63953ffb90bbc880c612d576fcfd973a5904277d25ec9e2d8d5719bf67969662"
|
||||
name = "github.com/mvdan/xurls"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "e52e821cbfe8fe163ff6f8628ab5869b11fc05af"
|
||||
version = "v2.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2be1d891535ce3d6d2a3db9087f07415e909744e9eff1a30f8f0b2519df60ae6"
|
||||
name = "github.com/nfnt/resize"
|
||||
@@ -1173,7 +1181,6 @@
|
||||
"github.com/keybase/go-crypto/openpgp",
|
||||
"github.com/keybase/go-crypto/openpgp/armor",
|
||||
"github.com/keybase/go-crypto/openpgp/packet",
|
||||
"github.com/klauspost/compress/gzip",
|
||||
"github.com/lafriks/xormstore",
|
||||
"github.com/lib/pq",
|
||||
"github.com/lunny/dingtalk_webhook",
|
||||
@@ -1191,6 +1198,7 @@
|
||||
"github.com/mcuadros/go-version",
|
||||
"github.com/microcosm-cc/bluemonday",
|
||||
"github.com/msteinert/pam",
|
||||
"github.com/mvdan/xurls",
|
||||
"github.com/nfnt/resize",
|
||||
"github.com/pquerna/otp",
|
||||
"github.com/pquerna/otp/totp",
|
||||
|
||||
@@ -550,7 +550,12 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
||||
beg := len(cmdDiffHead)
|
||||
a := line[beg+2 : middle]
|
||||
b := line[middle+3:]
|
||||
|
||||
if hasQuote {
|
||||
// Keep the entire string in double quotes for now
|
||||
a = line[beg:middle]
|
||||
b = line[middle+1:]
|
||||
|
||||
var err error
|
||||
a, err = strconv.Unquote(a)
|
||||
if err != nil {
|
||||
@@ -560,6 +565,10 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unquote: %v", err)
|
||||
}
|
||||
// Now remove the /a /b
|
||||
a = a[2:]
|
||||
b = b[2:]
|
||||
|
||||
}
|
||||
|
||||
curFile = &DiffFile{
|
||||
@@ -637,6 +646,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -99,6 +101,59 @@ func ExampleCutDiffAroundLine() {
|
||||
println(result)
|
||||
}
|
||||
|
||||
func TestParsePatch(t *testing.T) {
|
||||
var diff = `diff --git "a/README.md" "b/README.md"
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -1,3 +1,6 @@
|
||||
# gitea-github-migrator
|
||||
+
|
||||
+ Build Status
|
||||
- Latest Release
|
||||
Docker Pulls
|
||||
+ cut off
|
||||
+ cut off`
|
||||
result, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
|
||||
if err != nil {
|
||||
t.Errorf("ParsePatch failed: %s", err)
|
||||
}
|
||||
println(result)
|
||||
|
||||
var diff2 = `diff --git "a/A \\ B" "b/A \\ B"
|
||||
--- "a/A \\ B"
|
||||
+++ "b/A \\ B"
|
||||
@@ -1,3 +1,6 @@
|
||||
# gitea-github-migrator
|
||||
+
|
||||
+ Build Status
|
||||
- Latest Release
|
||||
Docker Pulls
|
||||
+ cut off
|
||||
+ cut off`
|
||||
result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2))
|
||||
if err != nil {
|
||||
t.Errorf("ParsePatch failed: %s", err)
|
||||
}
|
||||
println(result)
|
||||
|
||||
var diff3 = `diff --git a/README.md b/README.md
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -1,3 +1,6 @@
|
||||
# gitea-github-migrator
|
||||
+
|
||||
+ Build Status
|
||||
- Latest Release
|
||||
Docker Pulls
|
||||
+ cut off
|
||||
+ cut off`
|
||||
result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3))
|
||||
if err != nil {
|
||||
t.Errorf("ParsePatch failed: %s", err)
|
||||
}
|
||||
println(result)
|
||||
}
|
||||
|
||||
func setupDefaultDiff() *Diff {
|
||||
return &Diff{
|
||||
Files: []*DiffFile{
|
||||
|
||||
@@ -616,9 +616,9 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !user.IsActive {
|
||||
return nil, ErrUserInactive{user.ID, user.Name}
|
||||
} else if user.ProhibitLogin {
|
||||
// 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 {
|
||||
return nil, ErrUserProhibitLogin{user.ID, user.Name}
|
||||
}
|
||||
|
||||
@@ -658,9 +658,9 @@ func UserSignIn(username, password string) (*User, error) {
|
||||
switch user.LoginType {
|
||||
case LoginNoType, LoginPlain, LoginOAuth2:
|
||||
if user.IsPasswordSet() && user.ValidatePassword(password) {
|
||||
if !user.IsActive {
|
||||
return nil, ErrUserInactive{user.ID, user.Name}
|
||||
} else if user.ProhibitLogin {
|
||||
// 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 {
|
||||
return nil, ErrUserProhibitLogin{user.ID, user.Name}
|
||||
}
|
||||
|
||||
|
||||
@@ -719,10 +719,12 @@ var (
|
||||
|
||||
// DescriptionHTML does special handles to description and return HTML string.
|
||||
func (repo *Repository) DescriptionHTML() template.HTML {
|
||||
sanitize := func(s string) string {
|
||||
return fmt.Sprintf(`<a href="%[1]s" target="_blank" rel="noopener noreferrer">%[1]s</a>`, s)
|
||||
desc, err := markup.RenderDescriptionHTML([]byte(repo.Description), repo.HTMLURL(), repo.ComposeMetas())
|
||||
if err != nil {
|
||||
log.Error(4, "Failed to render description for %s (ID: %d): %v", repo.Name, repo.ID, err)
|
||||
return template.HTML(markup.Sanitize(repo.Description))
|
||||
}
|
||||
return template.HTML(descPattern.ReplaceAllStringFunc(markup.Sanitize(repo.Description), sanitize))
|
||||
return template.HTML(markup.Sanitize(string(desc)))
|
||||
}
|
||||
|
||||
// LocalCopyPath returns the local repository copy path.
|
||||
@@ -1064,9 +1066,11 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := cleanUpMigrateGitConfig(repo.GitConfigPath()); err != nil {
|
||||
return repo, fmt.Errorf("cleanUpMigrateGitConfig: %v", err)
|
||||
_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err)
|
||||
}
|
||||
|
||||
if repo.HasWiki() {
|
||||
if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil {
|
||||
return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err)
|
||||
|
||||
@@ -70,10 +70,6 @@ func (repo *Repository) CheckBranchName(name string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := gitRepo.GetTag(name); err == nil {
|
||||
return ErrTagAlreadyExists{name}
|
||||
}
|
||||
|
||||
branches, err := repo.GetBranches()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -87,6 +83,11 @@ func (repo *Repository) CheckBranchName(name string) error {
|
||||
return ErrBranchNameConflict{branch.Name}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := gitRepo.GetTag(name); err == nil {
|
||||
return ErrTagAlreadyExists{name}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// MirrorQueue holds an UniqueQueue object of the mirror
|
||||
@@ -71,11 +70,18 @@ func (m *Mirror) ScheduleNextUpdate() {
|
||||
}
|
||||
|
||||
func remoteAddress(repoPath string) (string, error) {
|
||||
cfg, err := ini.Load(GitConfigPath(repoPath))
|
||||
cmd := git.NewCommand("remote", "get-url", "origin")
|
||||
result, err := cmd.RunInDir(repoPath)
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return cfg.Section("remote \"origin\"").Key("url").Value(), nil
|
||||
if len(result) > 0 {
|
||||
return result[:len(result)-1], nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (m *Mirror) readAddress() {
|
||||
@@ -115,14 +121,15 @@ func (m *Mirror) FullAddress() string {
|
||||
|
||||
// SaveAddress writes new address to Git repository config.
|
||||
func (m *Mirror) SaveAddress(addr string) error {
|
||||
configPath := m.Repo.GitConfigPath()
|
||||
cfg, err := ini.Load(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Load: %v", err)
|
||||
repoPath := m.Repo.RepoPath()
|
||||
// Remove old origin
|
||||
_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.Section("remote \"origin\"").Key("url").SetValue(addr)
|
||||
return cfg.SaveToIndent(configPath, "\t")
|
||||
_, err = git.NewCommand("remote", "add", "origin", addr).RunInDir(repoPath)
|
||||
return err
|
||||
}
|
||||
|
||||
// gitShortEmptySha Git short empty SHA
|
||||
|
||||
@@ -238,7 +238,7 @@ func accessLevelUnit(e Engine, user *User, repo *Repository, unitType UnitType)
|
||||
if err != nil {
|
||||
return AccessModeNone, err
|
||||
}
|
||||
return perm.UnitAccessMode(UnitTypeCode), nil
|
||||
return perm.UnitAccessMode(unitType), nil
|
||||
}
|
||||
|
||||
func hasAccessUnit(e Engine, user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) {
|
||||
|
||||
@@ -44,21 +44,17 @@ func Toggle(options *ToggleOptions) macaron.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
// prevent infinite redirection
|
||||
// also make sure that the form cannot be accessed by
|
||||
// users who don't need this
|
||||
if ctx.Req.URL.Path == "/user/settings/change_password" {
|
||||
if !ctx.User.MustChangePassword {
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.User.MustChangePassword {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
||||
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
|
||||
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
||||
if ctx.Req.URL.Path != "/user/settings/change_password" {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
||||
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
|
||||
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
||||
return
|
||||
}
|
||||
} else if ctx.Req.URL.Path == "/user/settings/change_password" {
|
||||
// make sure that the form cannot be accessed by users who don't need this
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +234,23 @@ func RenderCommitMessage(
|
||||
return ctx.postProcess(rawHTML)
|
||||
}
|
||||
|
||||
// RenderDescriptionHTML will use similar logic as PostProcess, but will
|
||||
// use a single special linkProcessor.
|
||||
func RenderDescriptionHTML(
|
||||
rawHTML []byte,
|
||||
urlPrefix string,
|
||||
metas map[string]string,
|
||||
) ([]byte, error) {
|
||||
ctx := &postProcessCtx{
|
||||
metas: metas,
|
||||
urlPrefix: urlPrefix,
|
||||
procs: []processor{
|
||||
descriptionLinkProcessor,
|
||||
},
|
||||
}
|
||||
return ctx.postProcess(rawHTML)
|
||||
}
|
||||
|
||||
var byteBodyTag = []byte("<body>")
|
||||
var byteBodyTagClosing = []byte("</body>")
|
||||
|
||||
@@ -668,3 +685,34 @@ func genDefaultLinkProcessor(defaultLink string) processor {
|
||||
node.FirstChild, node.LastChild = ch, ch
|
||||
}
|
||||
}
|
||||
|
||||
// descriptionLinkProcessor creates links for DescriptionHTML
|
||||
func descriptionLinkProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||
m := linkRegex.FindStringIndex(node.Data)
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
uri := node.Data[m[0]:m[1]]
|
||||
replaceContent(node, m[0], m[1], createDescriptionLink(uri, uri))
|
||||
}
|
||||
|
||||
func createDescriptionLink(href, content string) *html.Node {
|
||||
textNode := &html.Node{
|
||||
Type: html.TextNode,
|
||||
Data: content,
|
||||
}
|
||||
linkNode := &html.Node{
|
||||
FirstChild: textNode,
|
||||
LastChild: textNode,
|
||||
Type: html.ElementNode,
|
||||
Data: "a",
|
||||
DataAtom: atom.A,
|
||||
Attr: []html.Attribute{
|
||||
{Key: "href", Val: href},
|
||||
{Key: "target", Val: "_blank"},
|
||||
{Key: "rel", Val: "noopener noreferrer"},
|
||||
},
|
||||
}
|
||||
textNode.Parent = linkNode
|
||||
return linkNode
|
||||
}
|
||||
|
||||
@@ -528,7 +528,9 @@ mirror_prune_desc = Remove obsolete remote-tracking references
|
||||
mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync.
|
||||
mirror_interval_invalid = The mirror interval is not valid.
|
||||
mirror_address = Clone From URL
|
||||
mirror_address_desc = Include any required authorization credentials in the URL.
|
||||
mirror_address_desc = Include any required authorization credentials in the URL. These must be url escaped as appropriate
|
||||
mirror_address_url_invalid = The provided url is invalid. You must escape all components of the url correctly.
|
||||
mirror_address_protocol_invalid = The provided url is invalid. Only http(s):// or git:// locations can be mirrored from.
|
||||
mirror_last_synced = Last Synchronized
|
||||
watchers = Watchers
|
||||
stargazers = Stargazers
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -384,33 +384,12 @@ pre, code {
|
||||
|
||||
}
|
||||
|
||||
.overflow.menu {
|
||||
.items {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
.item {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
border: none;
|
||||
height: auto;
|
||||
border-top: none;
|
||||
line-height: 1em;
|
||||
color: rgba(0,0,0,.8);
|
||||
padding: .71428571em 1.14285714em !important;
|
||||
font-size: 1rem;
|
||||
text-transform: none;
|
||||
font-weight: 400;
|
||||
box-shadow: none;
|
||||
-webkit-touch-callout: none;
|
||||
&.active {
|
||||
font-weight: 700;
|
||||
}
|
||||
&:hover {
|
||||
background: rgba(0,0,0,.05);
|
||||
color: rgba(0,0,0,.8);
|
||||
z-index: 13;
|
||||
}
|
||||
.ui.floating.dropdown {
|
||||
.overflow.menu {
|
||||
.scrolling.menu.items {
|
||||
border-radius: 0px !important;
|
||||
box-shadow: none !important;
|
||||
border-bottom: 1px solid rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package routers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
@@ -43,6 +44,11 @@ func Home(ctx *context.Context) {
|
||||
log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr())
|
||||
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
||||
ctx.HTML(200, "user/auth/prohibit_login")
|
||||
} else if ctx.User.MustChangePassword {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
||||
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
|
||||
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
||||
} else {
|
||||
user.Dashboard(ctx)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ package repo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -21,6 +23,8 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
|
||||
"github.com/mvdan/xurls"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -33,6 +37,8 @@ const (
|
||||
tplProtectedBranch base.TplName = "repo/settings/protected_branch"
|
||||
)
|
||||
|
||||
var validFormAddress *regexp.Regexp
|
||||
|
||||
// Settings show a repository's settings page
|
||||
func Settings(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
||||
@@ -140,7 +146,38 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil {
|
||||
|
||||
// Validate the form.MirrorAddress
|
||||
u, err := url.Parse(form.MirrorAddress)
|
||||
if err != nil {
|
||||
ctx.Data["Err_MirrorAddress"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
|
||||
return
|
||||
}
|
||||
|
||||
if u.Opaque != "" || !(u.Scheme == "http" || u.Scheme == "https" || u.Scheme == "git") {
|
||||
ctx.Data["Err_MirrorAddress"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, &form)
|
||||
return
|
||||
}
|
||||
|
||||
// Now use xurls
|
||||
address := validFormAddress.FindString(form.MirrorAddress)
|
||||
if address != form.MirrorAddress && form.MirrorAddress != "" {
|
||||
ctx.Data["Err_MirrorAddress"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
|
||||
return
|
||||
}
|
||||
|
||||
if u.EscapedPath() == "" || u.Host == "" || !u.IsAbs() {
|
||||
ctx.Data["Err_MirrorAddress"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
|
||||
return
|
||||
}
|
||||
|
||||
address = u.String()
|
||||
|
||||
if err := ctx.Repo.Mirror.SaveAddress(address); err != nil {
|
||||
ctx.ServerError("SaveAddress", err)
|
||||
return
|
||||
}
|
||||
@@ -618,3 +655,11 @@ func DeleteDeployKey(ctx *context.Context) {
|
||||
"redirect": ctx.Repo.RepoLink + "/settings/keys",
|
||||
})
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
validFormAddress, err = xurls.StrictMatchingScheme(`(https?)|(git)://`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
|
||||
}
|
||||
entries.CustomSort(base.NaturalSortLess)
|
||||
|
||||
ctx.Data["Files"], err = entries.GetCommitsInfo(ctx.Repo.Commit, ctx.Repo.TreePath)
|
||||
ctx.Data["Files"], err = entries.GetCommitsInfo(ctx.Repo.Commit, ctx.Repo.TreePath, nil)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommitsInfo", err)
|
||||
return
|
||||
|
||||
@@ -296,7 +296,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
|
||||
m.Group("/user", func() {
|
||||
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
|
||||
m.Any("/activate", user.Activate)
|
||||
m.Any("/activate", user.Activate, reqSignIn)
|
||||
m.Any("/activate_email", user.ActivateEmail)
|
||||
m.Get("/email2user", user.Email2User)
|
||||
m.Get("/forgot_password", user.ForgotPasswd)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>
|
||||
<link rel="manifest" href="{{AppSubUrl}}/manifest.json">
|
||||
<link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials">
|
||||
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<label for="interval">{{.i18n.Tr "repo.mirror_interval"}}</label>
|
||||
<input id="interval" name="interval" value="{{.MirrorInterval}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="field {{if .Err_MirrorAddress}}error{{end}}">
|
||||
<label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label>
|
||||
<input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}" required>
|
||||
<p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="ui header">
|
||||
{{.i18n.Tr "home.switch_dashboard_context"}}
|
||||
</div>
|
||||
<div class="items">
|
||||
<div class="scrolling menu items">
|
||||
<a class="{{if eq .ContextUser.ID .SignedUser.ID}}active selected{{end}} item" href="{{AppSubUrl}}/{{if .PageIsIssues}}issues{{else if .PageIsPulls}}pulls{{end}}">
|
||||
<img class="ui avatar image" src="{{.SignedUser.RelAvatarLink}}">
|
||||
{{.SignedUser.Name}}
|
||||
|
||||
11
vendor/code.gitea.io/git/cache.go
generated
vendored
Normal file
11
vendor/code.gitea.io/git/cache.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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
|
||||
|
||||
// LastCommitCache cache
|
||||
type LastCommitCache interface {
|
||||
Get(repoPath, ref, entryPath string) (*Commit, error)
|
||||
Put(repoPath, ref, entryPath string, commit *Commit) error
|
||||
}
|
||||
53
vendor/code.gitea.io/git/commit.go
generated
vendored
53
vendor/code.gitea.io/git/commit.go
generated
vendored
@@ -1,4 +1,5 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -16,6 +18,7 @@ import (
|
||||
|
||||
// Commit represents a git commit.
|
||||
type Commit struct {
|
||||
Branch string // Branch this commit belongs to
|
||||
Tree
|
||||
ID SHA1 // The ID of this commit object
|
||||
Author *Signature
|
||||
@@ -279,6 +282,56 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CommitFileStatus represents status of files in a commit.
|
||||
type CommitFileStatus struct {
|
||||
Added []string
|
||||
Removed []string
|
||||
Modified []string
|
||||
}
|
||||
|
||||
// NewCommitFileStatus creates a CommitFileStatus
|
||||
func NewCommitFileStatus() *CommitFileStatus {
|
||||
return &CommitFileStatus{
|
||||
[]string{}, []string{}, []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// GetCommitFileStatus returns file status of commit in given repository.
|
||||
func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) {
|
||||
stdout, w := io.Pipe()
|
||||
done := make(chan struct{})
|
||||
fileStatus := NewCommitFileStatus()
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch fields[0][0] {
|
||||
case 'A':
|
||||
fileStatus.Added = append(fileStatus.Added, fields[1])
|
||||
case 'D':
|
||||
fileStatus.Removed = append(fileStatus.Removed, fields[1])
|
||||
case 'M':
|
||||
fileStatus.Modified = append(fileStatus.Modified, fields[1])
|
||||
}
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
stderr := new(bytes.Buffer)
|
||||
err := NewCommand("show", "--name-status", "--pretty=format:''", commitID).RunInDirPipeline(repoPath, w, stderr)
|
||||
w.Close() // Close writer to exit parsing goroutine
|
||||
if err != nil {
|
||||
return nil, concatenateError(err, stderr.String())
|
||||
}
|
||||
|
||||
<-done
|
||||
return fileStatus, nil
|
||||
}
|
||||
|
||||
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
|
||||
func GetFullCommitID(repoPath, shortID string) (string, error) {
|
||||
if len(shortID) >= 40 {
|
||||
|
||||
20
vendor/code.gitea.io/git/commit_info.go
generated
vendored
20
vendor/code.gitea.io/git/commit_info.go
generated
vendored
@@ -72,13 +72,20 @@ func (state *getCommitsInfoState) getTargetedEntryPath() string {
|
||||
}
|
||||
|
||||
// repeatedly perform targeted searches for unpopulated entries
|
||||
func targetedSearch(state *getCommitsInfoState, done chan error) {
|
||||
func targetedSearch(state *getCommitsInfoState, done chan error, cache LastCommitCache) {
|
||||
for {
|
||||
entryPath := state.getTargetedEntryPath()
|
||||
if len(entryPath) == 0 {
|
||||
done <- nil
|
||||
return
|
||||
}
|
||||
if cache != nil {
|
||||
commit, err := cache.Get(state.headCommit.repo.Path, state.headCommit.ID.String(), entryPath)
|
||||
if err == nil && commit != nil {
|
||||
state.update(entryPath, commit)
|
||||
continue
|
||||
}
|
||||
}
|
||||
command := NewCommand("rev-list", "-1", state.headCommit.ID.String(), "--", entryPath)
|
||||
output, err := command.RunInDir(state.headCommit.repo.Path)
|
||||
if err != nil {
|
||||
@@ -96,6 +103,9 @@ func targetedSearch(state *getCommitsInfoState, done chan error) {
|
||||
return
|
||||
}
|
||||
state.update(entryPath, commit)
|
||||
if cache != nil {
|
||||
cache.Put(state.headCommit.repo.Path, state.headCommit.ID.String(), entryPath, commit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +128,9 @@ func initGetCommitInfoState(entries Entries, headCommit *Commit, treePath string
|
||||
}
|
||||
|
||||
// GetCommitsInfo gets information of all commits that are corresponding to these entries
|
||||
func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interface{}, error) {
|
||||
func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCommitCache) ([][]interface{}, error) {
|
||||
state := initGetCommitInfoState(tes, commit, treePath)
|
||||
if err := getCommitsInfo(state); err != nil {
|
||||
if err := getCommitsInfo(state, cache); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(state.commits) < len(state.entryPaths) {
|
||||
@@ -188,7 +198,7 @@ func (state *getCommitsInfoState) update(entryPath string, commit *Commit) bool
|
||||
|
||||
const getCommitsInfoPretty = "--pretty=format:%H %ct %s"
|
||||
|
||||
func getCommitsInfo(state *getCommitsInfoState) error {
|
||||
func getCommitsInfo(state *getCommitsInfoState, cache LastCommitCache) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
@@ -215,7 +225,7 @@ func getCommitsInfo(state *getCommitsInfoState) error {
|
||||
numThreads := runtime.NumCPU()
|
||||
done := make(chan error, numThreads)
|
||||
for i := 0; i < numThreads; i++ {
|
||||
go targetedSearch(state, done)
|
||||
go targetedSearch(state, done, cache)
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(readCloser)
|
||||
|
||||
31
vendor/code.gitea.io/git/repo_commit.go
generated
vendored
31
vendor/code.gitea.io/git/repo_commit.go
generated
vendored
@@ -10,7 +10,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mcuadros/go-version"
|
||||
version "github.com/mcuadros/go-version"
|
||||
)
|
||||
|
||||
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
||||
@@ -32,7 +32,14 @@ func (repo *Repository) GetBranchCommitID(name string) (string, error) {
|
||||
|
||||
// GetTagCommitID returns last commit ID string of given tag.
|
||||
func (repo *Repository) GetTagCommitID(name string) (string, error) {
|
||||
return repo.GetRefCommitID(TagPrefix + name)
|
||||
stdout, err := NewCommand("rev-list", "-n", "1", name).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unknown revision or path") {
|
||||
return "", ErrNotExist{name, ""}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(stdout), nil
|
||||
}
|
||||
|
||||
// parseCommitData parses commit information from the (uncompressed) raw
|
||||
@@ -94,7 +101,11 @@ l:
|
||||
sig, err := newGPGSignatureFromCommitline(data, (nextline+1)+sigindex, true)
|
||||
if err == nil && sig != nil {
|
||||
// remove signature from commit message
|
||||
cm = cm[:sigindex-1]
|
||||
if sigindex == 0 {
|
||||
cm = ""
|
||||
} else {
|
||||
cm = cm[:sigindex-1]
|
||||
}
|
||||
commit.Signature = sig
|
||||
}
|
||||
}
|
||||
@@ -130,6 +141,14 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
|
||||
commit.repo = repo
|
||||
commit.ID = id
|
||||
|
||||
data, err = NewCommand("name-rev", id.String()).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// name-rev commitID ouput will be "COMMIT_ID master" or "COMMIT_ID master~12"
|
||||
commit.Branch = strings.Split(strings.Split(string(data), " ")[1], "~")[0]
|
||||
|
||||
repo.commitCache.Set(id.String(), commit)
|
||||
return commit, nil
|
||||
}
|
||||
@@ -138,10 +157,14 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
|
||||
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
|
||||
if len(commitID) != 40 {
|
||||
var err error
|
||||
commitID, err = NewCommand("rev-parse", commitID).RunInDir(repo.Path)
|
||||
actualCommitID, err := NewCommand("rev-parse", commitID).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unknown revision or path") {
|
||||
return nil, ErrNotExist{commitID, ""}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
commitID = actualCommitID
|
||||
}
|
||||
id, err := NewIDFromString(commitID)
|
||||
if err != nil {
|
||||
|
||||
20
vendor/code.gitea.io/git/repo_tag.go
generated
vendored
20
vendor/code.gitea.io/git/repo_tag.go
generated
vendored
@@ -76,12 +76,12 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) {
|
||||
|
||||
// GetTag returns a Git tag by given name.
|
||||
func (repo *Repository) GetTag(name string) (*Tag, error) {
|
||||
stdout, err := NewCommand("show-ref", "--tags", name).RunInDir(repo.Path)
|
||||
idStr, err := repo.GetTagCommitID(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, err := NewIDFromString(strings.Split(stdout, " ")[0])
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -103,26 +103,18 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) {
|
||||
}
|
||||
|
||||
tagNames := strings.Split(stdout, "\n")
|
||||
var tags []*Tag
|
||||
var tags = make([]*Tag, 0, len(tagNames))
|
||||
for _, tagName := range tagNames {
|
||||
tagName = strings.TrimSpace(tagName)
|
||||
if len(tagName) == 0 {
|
||||
continue
|
||||
}
|
||||
commitID, err := NewCommand("rev-parse", tagName).RunInDir(repo.Path)
|
||||
|
||||
tag, err := repo.GetTag(tagName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commit, err := repo.GetCommit(commitID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tags = append(tags, &Tag{
|
||||
Name: tagName,
|
||||
Message: commit.Message(),
|
||||
Object: commit.ID,
|
||||
Tagger: commit.Author,
|
||||
})
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
sortTagsByTime(tags)
|
||||
return tags, nil
|
||||
|
||||
16
vendor/code.gitea.io/git/submodule.go
generated
vendored
16
vendor/code.gitea.io/git/submodule.go
generated
vendored
@@ -29,13 +29,12 @@ func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile {
|
||||
}
|
||||
}
|
||||
|
||||
// RefURL guesses and returns reference URL.
|
||||
func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
|
||||
if sf.refURL == "" {
|
||||
func getRefURL(refURL, urlPrefix, parentPath string) string {
|
||||
if refURL == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
url := strings.TrimSuffix(sf.refURL, ".git")
|
||||
url := strings.TrimSuffix(refURL, ".git")
|
||||
|
||||
// git://xxx/user/repo
|
||||
if strings.HasPrefix(url, "git://") {
|
||||
@@ -67,12 +66,21 @@ func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
|
||||
if strings.Contains(urlPrefix, url[i+1:j]) {
|
||||
return urlPrefix + url[j+1:]
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// RefURL guesses and returns reference URL.
|
||||
func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
|
||||
return getRefURL(sf.refURL, urlPrefix, parentPath)
|
||||
}
|
||||
|
||||
// RefID returns reference ID.
|
||||
func (sf *SubModuleFile) RefID() string {
|
||||
return sf.refID
|
||||
|
||||
22
vendor/code.gitea.io/git/tree.go
generated
vendored
22
vendor/code.gitea.io/git/tree.go
generated
vendored
@@ -18,6 +18,9 @@ type Tree struct {
|
||||
|
||||
entries Entries
|
||||
entriesParsed bool
|
||||
|
||||
entriesRecursive Entries
|
||||
entriesRecursiveParsed bool
|
||||
}
|
||||
|
||||
// NewTree create a new tree according the repository and commit id
|
||||
@@ -67,20 +70,29 @@ func (t *Tree) ListEntries() (Entries, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.entries, err = parseTreeEntries(stdout, t)
|
||||
if err == nil {
|
||||
t.entriesParsed = true
|
||||
}
|
||||
|
||||
return t.entries, err
|
||||
}
|
||||
|
||||
// ListEntriesRecursive returns all entries of current tree recursively including all subtrees
|
||||
func (t *Tree) ListEntriesRecursive() (Entries, error) {
|
||||
if t.entriesParsed {
|
||||
return t.entries, nil
|
||||
if t.entriesRecursiveParsed {
|
||||
return t.entriesRecursive, nil
|
||||
}
|
||||
stdout, err := NewCommand("ls-tree", "-t", "-r", t.ID.String()).RunInDirBytes(t.repo.Path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.entries, err = parseTreeEntries(stdout, t)
|
||||
return t.entries, err
|
||||
|
||||
t.entriesRecursive, err = parseTreeEntries(stdout, t)
|
||||
if err == nil {
|
||||
t.entriesRecursiveParsed = true
|
||||
}
|
||||
|
||||
return t.entriesRecursive, err
|
||||
}
|
||||
|
||||
27
vendor/github.com/mvdan/xurls/LICENSE
generated
vendored
Normal file
27
vendor/github.com/mvdan/xurls/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2015, Daniel Martí. 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 the copyright holder 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.
|
||||
299
vendor/github.com/mvdan/xurls/schemes.go
generated
vendored
Normal file
299
vendor/github.com/mvdan/xurls/schemes.go
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
// Generated by schemesgen
|
||||
|
||||
package xurls
|
||||
|
||||
// Schemes is a sorted list of all IANA assigned schemes.
|
||||
//
|
||||
// Source:
|
||||
// https://www.iana.org/assignments/uri-schemes/uri-schemes-1.csv
|
||||
var Schemes = []string{
|
||||
`aaa`,
|
||||
`aaas`,
|
||||
`about`,
|
||||
`acap`,
|
||||
`acct`,
|
||||
`acr`,
|
||||
`adiumxtra`,
|
||||
`afp`,
|
||||
`afs`,
|
||||
`aim`,
|
||||
`appdata`,
|
||||
`apt`,
|
||||
`attachment`,
|
||||
`aw`,
|
||||
`barion`,
|
||||
`beshare`,
|
||||
`bitcoin`,
|
||||
`bitcoincash`,
|
||||
`blob`,
|
||||
`bolo`,
|
||||
`browserext`,
|
||||
`callto`,
|
||||
`cap`,
|
||||
`chrome`,
|
||||
`chrome-extension`,
|
||||
`cid`,
|
||||
`coap`,
|
||||
`coap+tcp`,
|
||||
`coap+ws`,
|
||||
`coaps`,
|
||||
`coaps+tcp`,
|
||||
`coaps+ws`,
|
||||
`com-eventbrite-attendee`,
|
||||
`content`,
|
||||
`conti`,
|
||||
`crid`,
|
||||
`cvs`,
|
||||
`data`,
|
||||
`dav`,
|
||||
`diaspora`,
|
||||
`dict`,
|
||||
`did`,
|
||||
`dis`,
|
||||
`dlna-playcontainer`,
|
||||
`dlna-playsingle`,
|
||||
`dns`,
|
||||
`dntp`,
|
||||
`dtn`,
|
||||
`dvb`,
|
||||
`ed2k`,
|
||||
`elsi`,
|
||||
`example`,
|
||||
`facetime`,
|
||||
`fax`,
|
||||
`feed`,
|
||||
`feedready`,
|
||||
`file`,
|
||||
`filesystem`,
|
||||
`finger`,
|
||||
`fish`,
|
||||
`ftp`,
|
||||
`geo`,
|
||||
`gg`,
|
||||
`git`,
|
||||
`gizmoproject`,
|
||||
`go`,
|
||||
`gopher`,
|
||||
`graph`,
|
||||
`gtalk`,
|
||||
`h323`,
|
||||
`ham`,
|
||||
`hcap`,
|
||||
`hcp`,
|
||||
`http`,
|
||||
`https`,
|
||||
`hxxp`,
|
||||
`hxxps`,
|
||||
`hydrazone`,
|
||||
`iax`,
|
||||
`icap`,
|
||||
`icon`,
|
||||
`im`,
|
||||
`imap`,
|
||||
`info`,
|
||||
`iotdisco`,
|
||||
`ipn`,
|
||||
`ipp`,
|
||||
`ipps`,
|
||||
`irc`,
|
||||
`irc6`,
|
||||
`ircs`,
|
||||
`iris`,
|
||||
`iris.beep`,
|
||||
`iris.lwz`,
|
||||
`iris.xpc`,
|
||||
`iris.xpcs`,
|
||||
`isostore`,
|
||||
`itms`,
|
||||
`jabber`,
|
||||
`jar`,
|
||||
`jms`,
|
||||
`keyparc`,
|
||||
`lastfm`,
|
||||
`ldap`,
|
||||
`ldaps`,
|
||||
`lvlt`,
|
||||
`magnet`,
|
||||
`mailserver`,
|
||||
`mailto`,
|
||||
`maps`,
|
||||
`market`,
|
||||
`message`,
|
||||
`microsoft.windows.camera`,
|
||||
`microsoft.windows.camera.multipicker`,
|
||||
`microsoft.windows.camera.picker`,
|
||||
`mid`,
|
||||
`mms`,
|
||||
`modem`,
|
||||
`mongodb`,
|
||||
`moz`,
|
||||
`ms-access`,
|
||||
`ms-browser-extension`,
|
||||
`ms-drive-to`,
|
||||
`ms-enrollment`,
|
||||
`ms-excel`,
|
||||
`ms-gamebarservices`,
|
||||
`ms-gamingoverlay`,
|
||||
`ms-getoffice`,
|
||||
`ms-help`,
|
||||
`ms-infopath`,
|
||||
`ms-inputapp`,
|
||||
`ms-lockscreencomponent-config`,
|
||||
`ms-media-stream-id`,
|
||||
`ms-mixedrealitycapture`,
|
||||
`ms-officeapp`,
|
||||
`ms-people`,
|
||||
`ms-project`,
|
||||
`ms-powerpoint`,
|
||||
`ms-publisher`,
|
||||
`ms-restoretabcompanion`,
|
||||
`ms-screenclip`,
|
||||
`ms-screensketch`,
|
||||
`ms-search`,
|
||||
`ms-search-repair`,
|
||||
`ms-secondary-screen-controller`,
|
||||
`ms-secondary-screen-setup`,
|
||||
`ms-settings`,
|
||||
`ms-settings-airplanemode`,
|
||||
`ms-settings-bluetooth`,
|
||||
`ms-settings-camera`,
|
||||
`ms-settings-cellular`,
|
||||
`ms-settings-cloudstorage`,
|
||||
`ms-settings-connectabledevices`,
|
||||
`ms-settings-displays-topology`,
|
||||
`ms-settings-emailandaccounts`,
|
||||
`ms-settings-language`,
|
||||
`ms-settings-location`,
|
||||
`ms-settings-lock`,
|
||||
`ms-settings-nfctransactions`,
|
||||
`ms-settings-notifications`,
|
||||
`ms-settings-power`,
|
||||
`ms-settings-privacy`,
|
||||
`ms-settings-proximity`,
|
||||
`ms-settings-screenrotation`,
|
||||
`ms-settings-wifi`,
|
||||
`ms-settings-workplace`,
|
||||
`ms-spd`,
|
||||
`ms-sttoverlay`,
|
||||
`ms-transit-to`,
|
||||
`ms-useractivityset`,
|
||||
`ms-virtualtouchpad`,
|
||||
`ms-visio`,
|
||||
`ms-walk-to`,
|
||||
`ms-whiteboard`,
|
||||
`ms-whiteboard-cmd`,
|
||||
`ms-word`,
|
||||
`msnim`,
|
||||
`msrp`,
|
||||
`msrps`,
|
||||
`mtqp`,
|
||||
`mumble`,
|
||||
`mupdate`,
|
||||
`mvn`,
|
||||
`news`,
|
||||
`nfs`,
|
||||
`ni`,
|
||||
`nih`,
|
||||
`nntp`,
|
||||
`notes`,
|
||||
`ocf`,
|
||||
`oid`,
|
||||
`onenote`,
|
||||
`onenote-cmd`,
|
||||
`opaquelocktoken`,
|
||||
`openpgp4fpr`,
|
||||
`pack`,
|
||||
`palm`,
|
||||
`paparazzi`,
|
||||
`pkcs11`,
|
||||
`platform`,
|
||||
`pop`,
|
||||
`pres`,
|
||||
`prospero`,
|
||||
`proxy`,
|
||||
`pwid`,
|
||||
`psyc`,
|
||||
`qb`,
|
||||
`query`,
|
||||
`redis`,
|
||||
`rediss`,
|
||||
`reload`,
|
||||
`res`,
|
||||
`resource`,
|
||||
`rmi`,
|
||||
`rsync`,
|
||||
`rtmfp`,
|
||||
`rtmp`,
|
||||
`rtsp`,
|
||||
`rtsps`,
|
||||
`rtspu`,
|
||||
`secondlife`,
|
||||
`service`,
|
||||
`session`,
|
||||
`sftp`,
|
||||
`sgn`,
|
||||
`shttp`,
|
||||
`sieve`,
|
||||
`simpleledger`,
|
||||
`sip`,
|
||||
`sips`,
|
||||
`skype`,
|
||||
`smb`,
|
||||
`sms`,
|
||||
`smtp`,
|
||||
`snews`,
|
||||
`snmp`,
|
||||
`soap.beep`,
|
||||
`soap.beeps`,
|
||||
`soldat`,
|
||||
`spiffe`,
|
||||
`spotify`,
|
||||
`ssh`,
|
||||
`steam`,
|
||||
`stun`,
|
||||
`stuns`,
|
||||
`submit`,
|
||||
`svn`,
|
||||
`tag`,
|
||||
`teamspeak`,
|
||||
`tel`,
|
||||
`teliaeid`,
|
||||
`telnet`,
|
||||
`tftp`,
|
||||
`things`,
|
||||
`thismessage`,
|
||||
`tip`,
|
||||
`tn3270`,
|
||||
`tool`,
|
||||
`turn`,
|
||||
`turns`,
|
||||
`tv`,
|
||||
`udp`,
|
||||
`unreal`,
|
||||
`urn`,
|
||||
`ut2004`,
|
||||
`v-event`,
|
||||
`vemmi`,
|
||||
`ventrilo`,
|
||||
`videotex`,
|
||||
`vnc`,
|
||||
`view-source`,
|
||||
`wais`,
|
||||
`webcal`,
|
||||
`wpid`,
|
||||
`ws`,
|
||||
`wss`,
|
||||
`wtai`,
|
||||
`wyciwyg`,
|
||||
`xcon`,
|
||||
`xcon-userid`,
|
||||
`xfire`,
|
||||
`xmlrpc.beep`,
|
||||
`xmlrpc.beeps`,
|
||||
`xmpp`,
|
||||
`xri`,
|
||||
`ymsgr`,
|
||||
`z39.50`,
|
||||
`z39.50r`,
|
||||
`z39.50s`,
|
||||
}
|
||||
1557
vendor/github.com/mvdan/xurls/tlds.go
generated
vendored
Normal file
1557
vendor/github.com/mvdan/xurls/tlds.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
24
vendor/github.com/mvdan/xurls/tlds_pseudo.go
generated
vendored
Normal file
24
vendor/github.com/mvdan/xurls/tlds_pseudo.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
|
||||
// See LICENSE for licensing information
|
||||
|
||||
package xurls
|
||||
|
||||
// PseudoTLDs is a sorted list of some widely used unofficial TLDs.
|
||||
//
|
||||
// Sources:
|
||||
// * https://en.wikipedia.org/wiki/Pseudo-top-level_domain
|
||||
// * https://en.wikipedia.org/wiki/Category:Pseudo-top-level_domains
|
||||
// * https://tools.ietf.org/html/draft-grothoff-iesg-special-use-p2p-names-00
|
||||
// * https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
|
||||
var PseudoTLDs = []string{
|
||||
`bit`, // Namecoin
|
||||
`example`, // Example domain
|
||||
`exit`, // Tor exit node
|
||||
`gnu`, // GNS by public key
|
||||
`i2p`, // I2P network
|
||||
`invalid`, // Invalid domain
|
||||
`local`, // Local network
|
||||
`localhost`, // Local network
|
||||
`test`, // Test domain
|
||||
`zkey`, // GNS domain name
|
||||
}
|
||||
107
vendor/github.com/mvdan/xurls/xurls.go
generated
vendored
Normal file
107
vendor/github.com/mvdan/xurls/xurls.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
|
||||
// See LICENSE for licensing information
|
||||
|
||||
// Package xurls extracts urls from plain text using regular expressions.
|
||||
package xurls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
//go:generate go run generate/tldsgen/main.go
|
||||
//go:generate go run generate/schemesgen/main.go
|
||||
|
||||
const (
|
||||
letter = `\p{L}`
|
||||
mark = `\p{M}`
|
||||
number = `\p{N}`
|
||||
iriChar = letter + mark + number
|
||||
currency = `\p{Sc}`
|
||||
otherSymb = `\p{So}`
|
||||
endChar = iriChar + `/\-+_&~*%=#` + currency + otherSymb
|
||||
otherPunc = `\p{Po}`
|
||||
midChar = endChar + `|` + otherPunc
|
||||
wellParen = `\([` + midChar + `]*(\([` + midChar + `]*\)[` + midChar + `]*)*\)`
|
||||
wellBrack = `\[[` + midChar + `]*(\[[` + midChar + `]*\][` + midChar + `]*)*\]`
|
||||
wellBrace = `\{[` + midChar + `]*(\{[` + midChar + `]*\}[` + midChar + `]*)*\}`
|
||||
wellAll = wellParen + `|` + wellBrack + `|` + wellBrace
|
||||
pathCont = `([` + midChar + `]*(` + wellAll + `|[` + endChar + `])+)+`
|
||||
|
||||
iri = `[` + iriChar + `]([` + iriChar + `\-]*[` + iriChar + `])?`
|
||||
domain = `(` + iri + `\.)+`
|
||||
octet = `(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])`
|
||||
ipv4Addr = `\b` + octet + `\.` + octet + `\.` + octet + `\.` + octet + `\b`
|
||||
ipv6Addr = `([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:[0-9a-fA-F]{0,4}|:[0-9a-fA-F]{1,4})?|(:[0-9a-fA-F]{1,4}){0,2})|(:[0-9a-fA-F]{1,4}){0,3})|(:[0-9a-fA-F]{1,4}){0,4})|:(:[0-9a-fA-F]{1,4}){0,5})((:[0-9a-fA-F]{1,4}){2}|:(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])(\.(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])){3})|(([0-9a-fA-F]{1,4}:){1,6}|:):[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){7}:`
|
||||
ipAddr = `(` + ipv4Addr + `|` + ipv6Addr + `)`
|
||||
port = `(:[0-9]*)?`
|
||||
)
|
||||
|
||||
// AnyScheme can be passed to StrictMatchingScheme to match any possibly valid
|
||||
// scheme, and not just the known ones.
|
||||
var AnyScheme = `([a-zA-Z][a-zA-Z.\-+]*://|` + anyOf(SchemesNoAuthority...) + `:)`
|
||||
|
||||
// SchemesNoAuthority is a sorted list of some well-known url schemes that are
|
||||
// followed by ":" instead of "://".
|
||||
var SchemesNoAuthority = []string{
|
||||
`bitcoin`, // Bitcoin
|
||||
`file`, // Files
|
||||
`magnet`, // Torrent magnets
|
||||
`mailto`, // Mail
|
||||
`sms`, // SMS
|
||||
`tel`, // Telephone
|
||||
`xmpp`, // XMPP
|
||||
}
|
||||
|
||||
func anyOf(strs ...string) string {
|
||||
var b bytes.Buffer
|
||||
b.WriteByte('(')
|
||||
for i, s := range strs {
|
||||
if i != 0 {
|
||||
b.WriteByte('|')
|
||||
}
|
||||
b.WriteString(regexp.QuoteMeta(s))
|
||||
}
|
||||
b.WriteByte(')')
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func strictExp() string {
|
||||
schemes := `(` + anyOf(Schemes...) + `://|` + anyOf(SchemesNoAuthority...) + `:)`
|
||||
return `(?i)` + schemes + `(?-i)` + pathCont
|
||||
}
|
||||
|
||||
func relaxedExp() string {
|
||||
site := domain + `(?i)` + anyOf(append(TLDs, PseudoTLDs...)...) + `(?-i)`
|
||||
hostName := `(` + site + `|` + ipAddr + `)`
|
||||
webURL := hostName + port + `(/|/` + pathCont + `?|\b|$)`
|
||||
return strictExp() + `|` + webURL
|
||||
}
|
||||
|
||||
// Strict produces a regexp that matches any URL with a scheme in either the
|
||||
// Schemes or SchemesNoAuthority lists.
|
||||
func Strict() *regexp.Regexp {
|
||||
re := regexp.MustCompile(strictExp())
|
||||
re.Longest()
|
||||
return re
|
||||
}
|
||||
|
||||
// Relaxed produces a regexp that matches any URL matched by Strict, plus any
|
||||
// URL with no scheme.
|
||||
func Relaxed() *regexp.Regexp {
|
||||
re := regexp.MustCompile(relaxedExp())
|
||||
re.Longest()
|
||||
return re
|
||||
}
|
||||
|
||||
// StrictMatchingScheme produces a regexp similar to Strict, but requiring that
|
||||
// the scheme match the given regular expression. See AnyScheme too.
|
||||
func StrictMatchingScheme(exp string) (*regexp.Regexp, error) {
|
||||
strictMatching := `(?i)(` + exp + `)(?-i)` + pathCont
|
||||
re, err := regexp.Compile(strictMatching)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
re.Longest()
|
||||
return re, nil
|
||||
}
|
||||
Reference in New Issue
Block a user