summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2019-07-16 08:13:03 +0800
committertechknowlogick <techknowlogick@gitea.io>2019-07-15 20:13:03 -0400
commitd2958d9f4633ddbde2202952d665b3d562eb0415 (patch)
tree59f6d1c0ed6c886ba0caa6d96d5a175debf376b7
parent760c47389696e97131a3d13629a0a5a4576e5283 (diff)
downloadgitea-d2958d9f4633ddbde2202952d665b3d562eb0415.tar.gz
gitea-d2958d9f4633ddbde2202952d665b3d562eb0415.zip
Move status table to cron package (#7370)
-rw-r--r--go.mod4
-rw-r--r--go.sum11
-rw-r--r--models/branches.go5
-rw-r--r--models/repo.go25
-rw-r--r--models/repo_mirror.go5
-rw-r--r--models/user.go7
-rw-r--r--modules/cron/cron.go56
-rw-r--r--vendor/github.com/gogits/cron/parser.go234
-rw-r--r--vendor/github.com/gogs/cron/.gitignore (renamed from vendor/github.com/gogits/cron/.gitignore)0
-rw-r--r--vendor/github.com/gogs/cron/.travis.yml (renamed from vendor/github.com/gogits/cron/.travis.yml)0
-rw-r--r--vendor/github.com/gogs/cron/LICENSE (renamed from vendor/github.com/gogits/cron/LICENSE)0
-rw-r--r--vendor/github.com/gogs/cron/README.md (renamed from vendor/github.com/gogits/cron/README.md)0
-rw-r--r--vendor/github.com/gogs/cron/constantdelay.go (renamed from vendor/github.com/gogits/cron/constantdelay.go)0
-rw-r--r--vendor/github.com/gogs/cron/cron.go (renamed from vendor/github.com/gogits/cron/cron.go)92
-rw-r--r--vendor/github.com/gogs/cron/doc.go (renamed from vendor/github.com/gogits/cron/doc.go)8
-rw-r--r--vendor/github.com/gogs/cron/parser.go380
-rw-r--r--vendor/github.com/gogs/cron/spec.go (renamed from vendor/github.com/gogits/cron/spec.go)1
-rw-r--r--vendor/golang.org/x/oauth2/README.md54
-rw-r--r--vendor/golang.org/x/oauth2/go.mod10
-rw-r--r--vendor/golang.org/x/oauth2/go.sum12
-rw-r--r--vendor/golang.org/x/oauth2/internal/token.go216
-rw-r--r--vendor/golang.org/x/oauth2/oauth2.go53
-rw-r--r--vendor/golang.org/x/oauth2/token.go7
-rw-r--r--vendor/modules.txt6
24 files changed, 686 insertions, 500 deletions
diff --git a/go.mod b/go.mod
index 182f8aca98..2a5ecd7d23 100644
--- a/go.mod
+++ b/go.mod
@@ -57,7 +57,7 @@ require (
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/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
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
@@ -111,7 +111,7 @@ require (
go.etcd.io/bbolt v1.3.2 // indirect
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b
- golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759
+ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45
golang.org/x/text v0.3.2
golang.org/x/tools v0.0.0-20190620154339-431033348dd0 // indirect
diff --git a/go.sum b/go.sum
index 5256f0ce80..7b23846adc 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,4 @@
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=
@@ -141,9 +140,9 @@ github.com/go-xorm/xorm v0.7.3-0.20190620151208-f1b4f8368459 h1:JGEuhH169J7Wtm1h
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=
-github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183/go.mod h1:pX+V62FFmklia2fhP3P4YSY6iJdPO5jIDKFQ5fEd5QE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8=
+github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
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=
@@ -220,7 +219,6 @@ 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/lafriks/xormstore v1.0.0 h1:P/IJzNSIpjXl/Up3o2Td5ZU/x4v6DEKLMaPQJGtmJCk=
github.com/lafriks/xormstore v1.0.0/go.mod h1:dD8vHNRfEp3Uy+JvX9cMi2SXcRKJ0x4pYKsZuy843Ic=
-github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0 h1:/5u4a+KGJptBRqGzPvYQL9p0d/tPR4S31+Tnzj9lEO4=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -366,6 +364,7 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
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-20190108225652-1e06a53dbb7e/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=
@@ -373,8 +372,8 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b h1:lkjdUzSyJ5P1+eal9fxXX9Xg2
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=
-golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
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=
diff --git a/models/branches.go b/models/branches.go
index fa4215d6a0..c09e72e988 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -458,11 +458,6 @@ func (deletedBranch *DeletedBranch) LoadUser() {
// RemoveOldDeletedBranches removes old deleted branches
func RemoveOldDeletedBranches() {
- if !taskStatusTable.StartIfNotRunning(`deleted_branches_cleanup`) {
- return
- }
- defer taskStatusTable.Stop(`deleted_branches_cleanup`)
-
log.Trace("Doing: DeletedBranchesCleanup")
deleteBefore := time.Now().Add(-setting.Cron.DeletedBranchesCleanup.OlderThan)
diff --git a/models/repo.go b/models/repo.go
index 9bedeba952..fc5f81eb5c 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -2056,11 +2056,6 @@ func DeleteRepositoryArchives() error {
// DeleteOldRepositoryArchives deletes old repository archives.
func DeleteOldRepositoryArchives() {
- if !taskStatusTable.StartIfNotRunning(archiveCleanup) {
- return
- }
- defer taskStatusTable.Stop(archiveCleanup)
-
log.Trace("Doing: ArchiveCleanup")
if err := x.Where("id > 0").Iterate(new(Repository), deleteOldRepositoryArchives); err != nil {
@@ -2187,23 +2182,8 @@ func SyncRepositoryHooks() error {
})
}
-// Prevent duplicate running tasks.
-var taskStatusTable = sync.NewStatusTable()
-
-const (
- mirrorUpdate = "mirror_update"
- gitFsck = "git_fsck"
- checkRepos = "check_repos"
- archiveCleanup = "archive_cleanup"
-)
-
// GitFsck calls 'git fsck' to check repository health.
func GitFsck() {
- if !taskStatusTable.StartIfNotRunning(gitFsck) {
- return
- }
- defer taskStatusTable.Stop(gitFsck)
-
log.Trace("Doing: GitFsck")
if err := x.
@@ -2272,11 +2252,6 @@ func repoStatsCheck(checker *repoChecker) {
// CheckRepoStats checks the repository stats
func CheckRepoStats() {
- if !taskStatusTable.StartIfNotRunning(checkRepos) {
- return
- }
- defer taskStatusTable.Stop(checkRepos)
-
log.Trace("Doing: CheckRepoStats")
checkers := []*repoChecker{
diff --git a/models/repo_mirror.go b/models/repo_mirror.go
index c62834f6fb..528e9daa8b 100644
--- a/models/repo_mirror.go
+++ b/models/repo_mirror.go
@@ -315,11 +315,6 @@ func DeleteMirrorByRepoID(repoID int64) error {
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
- if !taskStatusTable.StartIfNotRunning(mirrorUpdate) {
- return
- }
- defer taskStatusTable.Stop(mirrorUpdate)
-
log.Trace("Doing: MirrorUpdate")
if err := x.
diff --git a/models/user.go b/models/user.go
index fc0dfee187..1d80f7836a 100644
--- a/models/user.go
+++ b/models/user.go
@@ -60,8 +60,6 @@ const (
algoPbkdf2 = "pbkdf2"
)
-const syncExternalUsers = "sync_external_users"
-
var (
// ErrUserNotKeyOwner user does not own this key error
ErrUserNotKeyOwner = errors.New("User does not own this public key")
@@ -1643,11 +1641,6 @@ func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, sshPublicKeys []str
// SyncExternalUsers is used to synchronize users with external authorization source
func SyncExternalUsers() {
- if !taskStatusTable.StartIfNotRunning(syncExternalUsers) {
- return
- }
- defer taskStatusTable.Stop(syncExternalUsers)
-
log.Trace("Doing: SyncExternalUsers")
ls, err := LoginSources()
diff --git a/modules/cron/cron.go b/modules/cron/cron.go
index 24457f5013..fe87f86e02 100644
--- a/modules/cron/cron.go
+++ b/modules/cron/cron.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.
@@ -7,15 +8,42 @@ package cron
import (
"time"
- "github.com/gogits/cron"
-
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/sync"
+
+ "github.com/gogs/cron"
+)
+
+const (
+ mirrorUpdate = "mirror_update"
+ gitFsck = "git_fsck"
+ checkRepos = "check_repos"
+ archiveCleanup = "archive_cleanup"
+ syncExternalUsers = "sync_external_users"
+ deletedBranchesCleanup = "deleted_branches_cleanup"
)
var c = cron.New()
+// Prevent duplicate running tasks.
+var taskStatusTable = sync.NewStatusTable()
+
+// Func defines a cron function body
+type Func func()
+
+// WithUnique wrap a cron func with an unique running check
+func WithUnique(name string, body Func) Func {
+ return func() {
+ if !taskStatusTable.StartIfNotRunning(name) {
+ return
+ }
+ defer taskStatusTable.Stop(name)
+ body()
+ }
+}
+
// NewContext begins cron tasks
func NewContext() {
var (
@@ -23,69 +51,69 @@ func NewContext() {
err error
)
if setting.Cron.UpdateMirror.Enabled {
- entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, models.MirrorUpdate)
+ entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, WithUnique(mirrorUpdate, models.MirrorUpdate))
if err != nil {
log.Fatal("Cron[Update mirrors]: %v", err)
}
if setting.Cron.UpdateMirror.RunAtStart {
entry.Prev = time.Now()
entry.ExecTimes++
- go models.MirrorUpdate()
+ go WithUnique(mirrorUpdate, models.MirrorUpdate)()
}
}
if setting.Cron.RepoHealthCheck.Enabled {
- entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, models.GitFsck)
+ entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, WithUnique(gitFsck, models.GitFsck))
if err != nil {
log.Fatal("Cron[Repository health check]: %v", err)
}
if setting.Cron.RepoHealthCheck.RunAtStart {
entry.Prev = time.Now()
entry.ExecTimes++
- go models.GitFsck()
+ go WithUnique(gitFsck, models.GitFsck)()
}
}
if setting.Cron.CheckRepoStats.Enabled {
- entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, models.CheckRepoStats)
+ entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, WithUnique(checkRepos, models.CheckRepoStats))
if err != nil {
log.Fatal("Cron[Check repository statistics]: %v", err)
}
if setting.Cron.CheckRepoStats.RunAtStart {
entry.Prev = time.Now()
entry.ExecTimes++
- go models.CheckRepoStats()
+ go WithUnique(checkRepos, models.CheckRepoStats)()
}
}
if setting.Cron.ArchiveCleanup.Enabled {
- entry, err = c.AddFunc("Clean up old repository archives", setting.Cron.ArchiveCleanup.Schedule, models.DeleteOldRepositoryArchives)
+ entry, err = c.AddFunc("Clean up old repository archives", setting.Cron.ArchiveCleanup.Schedule, WithUnique(archiveCleanup, models.DeleteOldRepositoryArchives))
if err != nil {
log.Fatal("Cron[Clean up old repository archives]: %v", err)
}
if setting.Cron.ArchiveCleanup.RunAtStart {
entry.Prev = time.Now()
entry.ExecTimes++
- go models.DeleteOldRepositoryArchives()
+ go WithUnique(archiveCleanup, models.DeleteOldRepositoryArchives)()
}
}
if setting.Cron.SyncExternalUsers.Enabled {
- entry, err = c.AddFunc("Synchronize external users", setting.Cron.SyncExternalUsers.Schedule, models.SyncExternalUsers)
+ entry, err = c.AddFunc("Synchronize external users", setting.Cron.SyncExternalUsers.Schedule, WithUnique(syncExternalUsers, models.SyncExternalUsers))
if err != nil {
log.Fatal("Cron[Synchronize external users]: %v", err)
}
if setting.Cron.SyncExternalUsers.RunAtStart {
entry.Prev = time.Now()
entry.ExecTimes++
- go models.SyncExternalUsers()
+ go WithUnique(syncExternalUsers, models.SyncExternalUsers)()
}
}
if setting.Cron.DeletedBranchesCleanup.Enabled {
- entry, err = c.AddFunc("Remove old deleted branches", setting.Cron.DeletedBranchesCleanup.Schedule, models.RemoveOldDeletedBranches)
+ entry, err = c.AddFunc("Remove old deleted branches", setting.Cron.DeletedBranchesCleanup.Schedule, WithUnique(deletedBranchesCleanup, models.RemoveOldDeletedBranches))
if err != nil {
log.Fatal("Cron[Remove old deleted branches]: %v", err)
}
if setting.Cron.DeletedBranchesCleanup.RunAtStart {
entry.Prev = time.Now()
entry.ExecTimes++
- go models.RemoveOldDeletedBranches()
+ go WithUnique(deletedBranchesCleanup, models.RemoveOldDeletedBranches)()
}
}
c.Start()
diff --git a/vendor/github.com/gogits/cron/parser.go b/vendor/github.com/gogits/cron/parser.go
deleted file mode 100644
index fd217c92db..0000000000
--- a/vendor/github.com/gogits/cron/parser.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package cron
-
-import (
- "fmt"
- "log"
- "math"
- "strconv"
- "strings"
- "time"
-)
-
-// Parse returns a new crontab schedule representing the given spec.
-// It returns a descriptive error if the spec is not valid.
-//
-// It accepts
-// - Full crontab specs, e.g. "* * * * * ?"
-// - Descriptors, e.g. "@midnight", "@every 1h30m"
-func Parse(spec string) (_ Schedule, err error) {
- // Convert panics into errors
- defer func() {
- if recovered := recover(); recovered != nil {
- err = fmt.Errorf("%v", recovered)
- }
- }()
-
- if spec[0] == '@' {
- return parseDescriptor(spec), nil
- }
-
- // Split on whitespace. We require 5 or 6 fields.
- // (second) (minute) (hour) (day of month) (month) (day of week, optional)
- fields := strings.Fields(spec)
- if len(fields) != 5 && len(fields) != 6 {
- log.Panicf("Expected 5 or 6 fields, found %d: %s", len(fields), spec)
- }
-
- // If a sixth field is not provided (DayOfWeek), then it is equivalent to star.
- if len(fields) == 5 {
- fields = append(fields, "*")
- }
-
- schedule := &SpecSchedule{
- Second: getField(fields[0], seconds),
- Minute: getField(fields[1], minutes),
- Hour: getField(fields[2], hours),
- Dom: getField(fields[3], dom),
- Month: getField(fields[4], months),
- Dow: getField(fields[5], dow),
- }
-
- return schedule, nil
-}
-
-// getField returns an Int with the bits set representing all of the times that
-// the field represents. A "field" is a comma-separated list of "ranges".
-func getField(field string, r bounds) uint64 {
- // list = range {"," range}
- var bits uint64
- ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' })
- for _, expr := range ranges {
- bits |= getRange(expr, r)
- }
- return bits
-}
-
-// getRange returns the bits indicated by the given expression:
-// number | number "-" number [ "/" number ]
-func getRange(expr string, r bounds) uint64 {
-
- var (
- start, end, step uint
- rangeAndStep = strings.Split(expr, "/")
- lowAndHigh = strings.Split(rangeAndStep[0], "-")
- singleDigit = len(lowAndHigh) == 1
- )
-
- var extra_star uint64
- if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
- start = r.min
- end = r.max
- extra_star = starBit
- } else {
- start = parseIntOrName(lowAndHigh[0], r.names)
- switch len(lowAndHigh) {
- case 1:
- end = start
- case 2:
- end = parseIntOrName(lowAndHigh[1], r.names)
- default:
- log.Panicf("Too many hyphens: %s", expr)
- }
- }
-
- switch len(rangeAndStep) {
- case 1:
- step = 1
- case 2:
- step = mustParseInt(rangeAndStep[1])
-
- // Special handling: "N/step" means "N-max/step".
- if singleDigit {
- end = r.max
- }
- default:
- log.Panicf("Too many slashes: %s", expr)
- }
-
- if start < r.min {
- log.Panicf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr)
- }
- if end > r.max {
- log.Panicf("End of range (%d) above maximum (%d): %s", end, r.max, expr)
- }
- if start > end {
- log.Panicf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr)
- }
- if step == 0 {
- log.Panicf("Step of range should be a positive number: %s", expr)
- }
-
- return getBits(start, end, step) | extra_star
-}
-
-// parseIntOrName returns the (possibly-named) integer contained in expr.
-func parseIntOrName(expr string, names map[string]uint) uint {
- if names != nil {
- if namedInt, ok := names[strings.ToLower(expr)]; ok {
- return namedInt
- }
- }
- return mustParseInt(expr)
-}
-
-// mustParseInt parses the given expression as an int or panics.
-func mustParseInt(expr string) uint {
- num, err := strconv.Atoi(expr)
- if err != nil {
- log.Panicf("Failed to parse int from %s: %s", expr, err)
- }
- if num < 0 {
- log.Panicf("Negative number (%d) not allowed: %s", num, expr)
- }
-
- return uint(num)
-}
-
-// getBits sets all bits in the range [min, max], modulo the given step size.
-func getBits(min, max, step uint) uint64 {
- var bits uint64
-
- // If step is 1, use shifts.
- if step == 1 {
- return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
- }
-
- // Else, use a simple loop.
- for i := min; i <= max; i += step {
- bits |= 1 << i
- }
- return bits
-}
-
-// all returns all bits within the given bounds. (plus the star bit)
-func all(r bounds) uint64 {
- return getBits(r.min, r.max, 1) | starBit
-}
-
-// parseDescriptor returns a pre-defined schedule for the expression, or panics
-// if none matches.
-func parseDescriptor(spec string) Schedule {
- switch spec {
- case "@yearly", "@annually":
- return &SpecSchedule{
- Second: 1 << seconds.min,
- Minute: 1 << minutes.min,
- Hour: 1 << hours.min,
- Dom: 1 << dom.min,
- Month: 1 << months.min,
- Dow: all(dow),
- }
-
- case "@monthly":
- return &SpecSchedule{
- Second: 1 << seconds.min,
- Minute: 1 << minutes.min,
- Hour: 1 << hours.min,
- Dom: 1 << dom.min,
- Month: all(months),
- Dow: all(dow),
- }
-
- case "@weekly":
- return &SpecSchedule{
- Second: 1 << seconds.min,
- Minute: 1 << minutes.min,
- Hour: 1 << hours.min,
- Dom: all(dom),
- Month: all(months),
- Dow: 1 << dow.min,
- }
-
- case "@daily", "@midnight":
- return &SpecSchedule{
- Second: 1 << seconds.min,
- Minute: 1 << minutes.min,
- Hour: 1 << hours.min,
- Dom: all(dom),
- Month: all(months),
- Dow: all(dow),
- }
-
- case "@hourly":
- return &SpecSchedule{
- Second: 1 << seconds.min,
- Minute: 1 << minutes.min,
- Hour: all(hours),
- Dom: all(dom),
- Month: all(months),
- Dow: all(dow),
- }
- }
-
- const every = "@every "
- if strings.HasPrefix(spec, every) {
- duration, err := time.ParseDuration(spec[len(every):])
- if err != nil {
- log.Panicf("Failed to parse duration %s: %s", spec, err)
- }
- return Every(duration)
- }
-
- log.Panicf("Unrecognized descriptor: %s", spec)
- return nil
-}
diff --git a/vendor/github.com/gogits/cron/.gitignore b/vendor/github.com/gogs/cron/.gitignore
index 00268614f0..00268614f0 100644
--- a/vendor/github.com/gogits/cron/.gitignore
+++ b/vendor/github.com/gogs/cron/.gitignore
diff --git a/vendor/github.com/gogits/cron/.travis.yml b/vendor/github.com/gogs/cron/.travis.yml
index 4f2ee4d973..4f2ee4d973 100644
--- a/vendor/github.com/gogits/cron/.travis.yml
+++ b/vendor/github.com/gogs/cron/.travis.yml
diff --git a/vendor/github.com/gogits/cron/LICENSE b/vendor/github.com/gogs/cron/LICENSE
index 3a0f627ffe..3a0f627ffe 100644
--- a/vendor/github.com/gogits/cron/LICENSE
+++ b/vendor/github.com/gogs/cron/LICENSE
diff --git a/vendor/github.com/gogits/cron/README.md b/vendor/github.com/gogs/cron/README.md
index 157ed082d4..157ed082d4 100644
--- a/vendor/github.com/gogits/cron/README.md
+++ b/vendor/github.com/gogs/cron/README.md
diff --git a/vendor/github.com/gogits/cron/constantdelay.go b/vendor/github.com/gogs/cron/constantdelay.go
index cd6e7b1be9..cd6e7b1be9 100644
--- a/vendor/github.com/gogits/cron/constantdelay.go
+++ b/vendor/github.com/gogs/cron/constantdelay.go
diff --git a/vendor/github.com/gogits/cron/cron.go b/vendor/github.com/gogs/cron/cron.go
index ed6ad21c1b..4da9f4ae6c 100644
--- a/vendor/github.com/gogits/cron/cron.go
+++ b/vendor/github.com/gogs/cron/cron.go
@@ -1,5 +1,3 @@
-// This library implements a cron spec parser and runner. See the README for
-// more details.
package cron
import (
@@ -19,6 +17,7 @@ type Cron struct {
snapshot chan []*Entry
running bool
ErrorLog *log.Logger
+ location *time.Location
}
// Job is an interface for submitted cron jobs.
@@ -74,8 +73,13 @@ func (s byTime) Less(i, j int) bool {
return s[i].Next.Before(s[j].Next)
}
-// New returns a new Cron job runner.
+// New returns a new Cron job runner, in the Local time zone.
func New() *Cron {
+ return NewWithLocation(time.Now().Location())
+}
+
+// NewWithLocation returns a new Cron job runner.
+func NewWithLocation(location *time.Location) *Cron {
return &Cron{
entries: nil,
add: make(chan *Entry),
@@ -83,6 +87,7 @@ func New() *Cron {
snapshot: make(chan []*Entry),
running: false,
ErrorLog: nil,
+ location: location,
}
}
@@ -131,6 +136,11 @@ func (c *Cron) Entries() []*Entry {
return c.entrySnapshot()
}
+// Location gets the time zone location
+func (c *Cron) Location() *time.Location {
+ return c.location
+}
+
// Start the cron scheduler in its own go-routine, or no-op if already started.
func (c *Cron) Start() {
if c.running {
@@ -140,6 +150,15 @@ func (c *Cron) Start() {
go c.run()
}
+// Run the cron scheduler, or no-op if already running.
+func (c *Cron) Run() {
+ if c.running {
+ return
+ }
+ c.running = true
+ c.run()
+}
+
func (c *Cron) runWithRecovery(j Job) {
defer func() {
if r := recover(); r != nil {
@@ -152,11 +171,11 @@ func (c *Cron) runWithRecovery(j Job) {
j.Run()
}
-// Run the scheduler.. this is private just due to the need to synchronize
+// Run the scheduler. this is private just due to the need to synchronize
// access to the 'running' state variable.
func (c *Cron) run() {
// Figure out the next activation times for each entry.
- now := time.Now().Local()
+ now := c.now()
for _, entry := range c.entries {
entry.Next = entry.Schedule.Next(now)
}
@@ -165,45 +184,47 @@ func (c *Cron) run() {
// Determine the next entry to run.
sort.Sort(byTime(c.entries))
- var effective time.Time
+ var timer *time.Timer
if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
// If there are no entries yet, just sleep - it still handles new entries
// and stop requests.
- effective = now.AddDate(10, 0, 0)
+ timer = time.NewTimer(100000 * time.Hour)
} else {
- effective = c.entries[0].Next
+ timer = time.NewTimer(c.entries[0].Next.Sub(now))
}
- timer := time.NewTimer(effective.Sub(now))
- select {
- case now = <-timer.C:
- // Run every entry whose next time was this effective time.
- for _, e := range c.entries {
- if e.Next != effective {
- break
+ for {
+ select {
+ case now = <-timer.C:
+ now = now.In(c.location)
+ // Run every entry whose next time was less than now
+ for _, e := range c.entries {
+ if e.Next.After(now) || e.Next.IsZero() {
+ break
+ }
+ go c.runWithRecovery(e.Job)
+ e.ExecTimes++
+ e.Prev = e.Next
+ e.Next = e.Schedule.Next(now)
}
- go c.runWithRecovery(e.Job)
- e.ExecTimes++
- e.Prev = e.Next
- e.Next = e.Schedule.Next(now)
- }
- continue
- case newEntry := <-c.add:
- c.entries = append(c.entries, newEntry)
- newEntry.Next = newEntry.Schedule.Next(time.Now().Local())
+ case newEntry := <-c.add:
+ timer.Stop()
+ now = c.now()
+ newEntry.Next = newEntry.Schedule.Next(now)
+ c.entries = append(c.entries, newEntry)
- case <-c.snapshot:
- c.snapshot <- c.entrySnapshot()
+ case <-c.snapshot:
+ c.snapshot <- c.entrySnapshot()
+ continue
- case <-c.stop:
- timer.Stop()
- return
- }
+ case <-c.stop:
+ timer.Stop()
+ return
+ }
- // 'now' should be updated after newEntry and snapshot cases.
- now = time.Now().Local()
- timer.Stop()
+ break
+ }
}
}
@@ -241,3 +262,8 @@ func (c *Cron) entrySnapshot() []*Entry {
}
return entries
}
+
+// now returns current time in c location
+func (c *Cron) now() time.Time {
+ return time.Now().In(c.location)
+}
diff --git a/vendor/github.com/gogits/cron/doc.go b/vendor/github.com/gogs/cron/doc.go
index dbdf50127a..3700cf655a 100644
--- a/vendor/github.com/gogits/cron/doc.go
+++ b/vendor/github.com/gogs/cron/doc.go
@@ -84,16 +84,16 @@ You may use one of several pre-defined schedules in place of a cron expression.
Intervals
-You may also schedule a job to execute at fixed intervals. This is supported by
-formatting the cron spec like this:
+You may also schedule a job to execute at fixed intervals, starting at the time it's added
+or cron is run. This is supported by formatting the cron spec like this:
@every <duration>
where "duration" is a string accepted by time.ParseDuration
(http://golang.org/pkg/time/#ParseDuration).
-For example, "@every 1h30m10s" would indicate a schedule that activates every
-1 hour, 30 minutes, 10 seconds.
+For example, "@every 1h30m10s" would indicate a schedule that activates immediately,
+and then every 1 hour, 30 minutes, 10 seconds.
Note: The interval does not take the job runtime into account. For example,
if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
diff --git a/vendor/github.com/gogs/cron/parser.go b/vendor/github.com/gogs/cron/parser.go
new file mode 100644
index 0000000000..a5e83c0a8d
--- /dev/null
+++ b/vendor/github.com/gogs/cron/parser.go
@@ -0,0 +1,380 @@
+package cron
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Configuration options for creating a parser. Most options specify which
+// fields should be included, while others enable features. If a field is not
+// included the parser will assume a default value. These options do not change
+// the order fields are parse in.
+type ParseOption int
+
+const (
+ Second ParseOption = 1 << iota // Seconds field, default 0
+ Minute // Minutes field, default 0
+ Hour // Hours field, default 0
+ Dom // Day of month field, default *
+ Month // Month field, default *
+ Dow // Day of week field, default *
+ DowOptional // Optional day of week field, default *
+ Descriptor // Allow descriptors such as @monthly, @weekly, etc.
+)
+
+var places = []ParseOption{
+ Second,
+ Minute,
+ Hour,
+ Dom,
+ Month,
+ Dow,
+}
+
+var defaults = []string{
+ "0",
+ "0",
+ "0",
+ "*",
+ "*",
+ "*",
+}
+
+// A custom Parser that can be configured.
+type Parser struct {
+ options ParseOption
+ optionals int
+}
+
+// Creates a custom Parser with custom options.
+//
+// // Standard parser without descriptors
+// specParser := NewParser(Minute | Hour | Dom | Month | Dow)
+// sched, err := specParser.Parse("0 0 15 */3 *")
+//
+// // Same as above, just excludes time fields
+// subsParser := NewParser(Dom | Month | Dow)
+// sched, err := specParser.Parse("15 */3 *")
+//
+// // Same as above, just makes Dow optional
+// subsParser := NewParser(Dom | Month | DowOptional)
+// sched, err := specParser.Parse("15 */3")
+//
+func NewParser(options ParseOption) Parser {
+ optionals := 0
+ if options&DowOptional > 0 {
+ options |= Dow
+ optionals++
+ }
+ return Parser{options, optionals}
+}
+
+// Parse returns a new crontab schedule representing the given spec.
+// It returns a descriptive error if the spec is not valid.
+// It accepts crontab specs and features configured by NewParser.
+func (p Parser) Parse(spec string) (Schedule, error) {
+ if len(spec) == 0 {
+ return nil, fmt.Errorf("Empty spec string")
+ }
+ if spec[0] == '@' && p.options&Descriptor > 0 {
+ return parseDescriptor(spec)
+ }
+
+ // Figure out how many fields we need
+ max := 0
+ for _, place := range places {
+ if p.options&place > 0 {
+ max++
+ }
+ }
+ min := max - p.optionals
+
+ // Split fields on whitespace
+ fields := strings.Fields(spec)
+
+ // Validate number of fields
+ if count := len(fields); count < min || count > max {
+ if min == max {
+ return nil, fmt.Errorf("Expected exactly %d fields, found %d: %s", min, count, spec)
+ }
+ return nil, fmt.Errorf("Expected %d to %d fields, found %d: %s", min, max, count, spec)
+ }
+
+ // Fill in missing fields
+ fields = expandFields(fields, p.options)
+
+ var err error
+ field := func(field string, r bounds) uint64 {
+ if err != nil {
+ return 0
+ }
+ var bits uint64
+ bits, err = getField(field, r)
+ return bits
+ }
+
+ var (
+ second = field(fields[0], seconds)
+ minute = field(fields[1], minutes)
+ hour = field(fields[2], hours)
+ dayofmonth = field(fields[3], dom)
+ month = field(fields[4], months)
+ dayofweek = field(fields[5], dow)
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ return &SpecSchedule{
+ Second: second,
+ Minute: minute,
+ Hour: hour,
+ Dom: dayofmonth,
+ Month: month,
+ Dow: dayofweek,
+ }, nil
+}
+
+func expandFields(fields []string, options ParseOption) []string {
+ n := 0
+ count := len(fields)
+ expFields := make([]string, len(places))
+ copy(expFields, defaults)
+ for i, place := range places {
+ if options&place > 0 {
+ expFields[i] = fields[n]
+ n++
+ }
+ if n == count {
+ break
+ }
+ }
+ return expFields
+}
+
+var standardParser = NewParser(
+ Minute | Hour | Dom | Month | Dow | Descriptor,
+)
+
+// ParseStandard returns a new crontab schedule representing the given standardSpec
+// (https://en.wikipedia.org/wiki/Cron). It differs from Parse requiring to always
+// pass 5 entries representing: minute, hour, day of month, month and day of week,
+// in that order. It returns a descriptive error if the spec is not valid.
+//
+// It accepts
+// - Standard crontab specs, e.g. "* * * * ?"
+// - Descriptors, e.g. "@midnight", "@every 1h30m"
+func ParseStandard(standardSpec string) (Schedule, error) {
+ return standardParser.Parse(standardSpec)
+}
+
+var defaultParser = NewParser(
+ Second | Minute | Hour | Dom | Month | DowOptional | Descriptor,
+)
+
+// Parse returns a new crontab schedule representing the given spec.
+// It returns a descriptive error if the spec is not valid.
+//
+// It accepts
+// - Full crontab specs, e.g. "* * * * * ?"
+// - Descriptors, e.g. "@midnight", "@every 1h30m"
+func Parse(spec string) (Schedule, error) {
+ return defaultParser.Parse(spec)
+}
+
+// getField returns an Int with the bits set representing all of the times that
+// the field represents or error parsing field value. A "field" is a comma-separated
+// list of "ranges".
+func getField(field string, r bounds) (uint64, error) {
+ var bits uint64
+ ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' })
+ for _, expr := range ranges {
+ bit, err := getRange(expr, r)
+ if err != nil {
+ return bits, err
+ }
+ bits |= bit
+ }
+ return bits, nil
+}
+
+// getRange returns the bits indicated by the given expression:
+// number | number "-" number [ "/" number ]
+// or error parsing range.
+func getRange(expr string, r bounds) (uint64, error) {
+ var (
+ start, end, step uint
+ rangeAndStep = strings.Split(expr, "/")
+ lowAndHigh = strings.Split(rangeAndStep[0], "-")
+ singleDigit = len(lowAndHigh) == 1
+ err error
+ )
+
+ var extra uint64
+ if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
+ start = r.min
+ end = r.max
+ extra = starBit
+ } else {
+ start, err = parseIntOrName(lowAndHigh[0], r.names)
+ if err != nil {
+ return 0, err
+ }
+ switch len(lowAndHigh) {
+ case 1:
+ end = start
+ case 2:
+ end, err = parseIntOrName(lowAndHigh[1], r.names)
+ if err != nil {
+ return 0, err
+ }
+ default:
+ return 0, fmt.Errorf("Too many hyphens: %s", expr)
+ }
+ }
+
+ switch len(rangeAndStep) {
+ case 1:
+ step = 1
+ case 2:
+ step, err = mustParseInt(rangeAndStep[1])
+ if err != nil {
+ return 0, err
+ }
+
+ // Special handling: "N/step" means "N-max/step".
+ if singleDigit {
+ end = r.max
+ }
+ default:
+ return 0, fmt.Errorf("Too many slashes: %s", expr)
+ }
+
+ if start < r.min {
+ return 0, fmt.Errorf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr)
+ }
+ if end > r.max {
+ return 0, fmt.Errorf("End of range (%d) above maximum (%d): %s", end, r.max, expr)
+ }
+ if start > end {
+ return 0, fmt.Errorf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr)
+ }
+ if step == 0 {
+ return 0, fmt.Errorf("Step of range should be a positive number: %s", expr)
+ }
+
+ return getBits(start, end, step) | extra, nil
+}
+
+// parseIntOrName returns the (possibly-named) integer contained in expr.
+func parseIntOrName(expr string, names map[string]uint) (uint, error) {
+ if names != nil {
+ if namedInt, ok := names[strings.ToLower(expr)]; ok {
+ return namedInt, nil
+ }
+ }
+ return mustParseInt(expr)
+}
+
+// mustParseInt parses the given expression as an int or returns an error.
+func mustParseInt(expr string) (uint, error) {
+ num, err := strconv.Atoi(expr)
+ if err != nil {
+ return 0, fmt.Errorf("Failed to parse int from %s: %s", expr, err)
+ }
+ if num < 0 {
+ return 0, fmt.Errorf("Negative number (%d) not allowed: %s", num, expr)
+ }
+
+ return uint(num), nil
+}
+
+// getBits sets all bits in the range [min, max], modulo the given step size.
+func getBits(min, max, step uint) uint64 {
+ var bits uint64
+
+ // If step is 1, use shifts.
+ if step == 1 {
+ return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
+ }
+
+ // Else, use a simple loop.
+ for i := min; i <= max; i += step {
+ bits |= 1 << i
+ }
+ return bits
+}
+
+// all returns all bits within the given bounds. (plus the star bit)
+func all(r bounds) uint64 {
+ return getBits(r.min, r.max, 1) | starBit
+}
+
+// parseDescriptor returns a predefined schedule for the expression, or error if none matches.
+func parseDescriptor(descriptor string) (Schedule, error) {
+ switch descriptor {
+ case "@yearly", "@annually":
+ return &SpecSchedule{
+ Second: 1 << seconds.min,
+ Minute: 1 << minutes.min,
+ Hour: 1 << hours.min,
+ Dom: 1 << dom.min,
+ Month: 1 << months.min,
+ Dow: all(dow),
+ }, nil
+
+ case "@monthly":
+ return &SpecSchedule{
+ Second: 1 << seconds.min,
+ Minute: 1 << minutes.min,
+ Hour: 1 << hours.min,
+ Dom: 1 << dom.min,
+ Month: all(months),
+ Dow: all(dow),
+ }, nil
+
+ case "@weekly":
+ return &SpecSchedule{
+ Second: 1 << seconds.min,
+ Minute: 1 << minutes.min,
+ Hour: 1 << hours.min,
+ Dom: all(dom),
+ Month: all(months),
+ Dow: 1 << dow.min,
+ }, nil
+
+ case "@daily", "@midnight":
+ return &SpecSchedule{
+ Second: 1 << seconds.min,
+ Minute: 1 << minutes.min,
+ Hour: 1 << hours.min,
+ Dom: all(dom),
+ Month: all(months),
+ Dow: all(dow),
+ }, nil
+
+ case "@hourly":
+ return &SpecSchedule{
+ Second: 1 << seconds.min,
+ Minute: 1 << minutes.min,
+ Hour: all(hours),
+ Dom: all(dom),
+ Month: all(months),
+ Dow: all(dow),
+ }, nil
+ }
+
+ const every = "@every "
+ if strings.HasPrefix(descriptor, every) {
+ duration, err := time.ParseDuration(descriptor[len(every):])
+ if err != nil {
+ return nil, fmt.Errorf("Failed to parse duration %s: %s", descriptor, err)
+ }
+ return Every(duration), nil
+ }
+
+ return nil, fmt.Errorf("Unrecognized descriptor: %s", descriptor)
+}
diff --git a/vendor/github.com/gogits/cron/spec.go b/vendor/github.com/gogs/cron/spec.go
index 2b54126952..aac9a60b95 100644
--- a/vendor/github.com/gogits/cron/spec.go
+++ b/vendor/github.com/gogs/cron/spec.go
@@ -151,7 +151,6 @@ func dayMatches(s *SpecSchedule, t time.Time) bool {
domMatch bool = 1<<uint(t.Day())&s.Dom > 0
dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0
)
-
if s.Dom&starBit > 0 || s.Dow&starBit > 0 {
return domMatch && dowMatch
}
diff --git a/vendor/golang.org/x/oauth2/README.md b/vendor/golang.org/x/oauth2/README.md
index 94ffd7326a..0f443e6934 100644
--- a/vendor/golang.org/x/oauth2/README.md
+++ b/vendor/golang.org/x/oauth2/README.md
@@ -19,56 +19,12 @@ See godoc for further documentation and examples.
* [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2)
* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google)
+## Policy for new packages
-## App Engine
-
-In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor
-of the [`context.Context`](https://golang.org/x/net/context#Context) type from
-the `golang.org/x/net/context` package. Later replaced by the standard `context` package
-of the [`context.Context`](https://golang.org/pkg/context#Context) type.
-
-
-This means it's no longer possible to use the "Classic App Engine"
-`appengine.Context` type with the `oauth2` package. (You're using
-Classic App Engine if you import the package `"appengine"`.)
-
-To work around this, you may use the new `"google.golang.org/appengine"`
-package. This package has almost the same API as the `"appengine"` package,
-but it can be fetched with `go get` and used on "Managed VMs" and well as
-Classic App Engine.
-
-See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app)
-for information on updating your app.
-
-If you don't want to update your entire app to use the new App Engine packages,
-you may use both sets of packages in parallel, using only the new packages
-with the `oauth2` package.
-
-```go
-import (
- "context"
- "golang.org/x/oauth2"
- "golang.org/x/oauth2/google"
- newappengine "google.golang.org/appengine"
- newurlfetch "google.golang.org/appengine/urlfetch"
-
- "appengine"
-)
-
-func handler(w http.ResponseWriter, r *http.Request) {
- var c appengine.Context = appengine.NewContext(r)
- c.Infof("Logging a message with the old package")
-
- var ctx context.Context = newappengine.NewContext(r)
- client := &http.Client{
- Transport: &oauth2.Transport{
- Source: google.AppEngineTokenSource(ctx, "scope"),
- Base: &newurlfetch.Transport{Context: ctx},
- },
- }
- client.Get("...")
-}
-```
+We no longer accept new provider-specific packages in this repo. For
+defining provider endpoints and provider-specific OAuth2 behavior, we
+encourage you to create packages elsewhere. We'll keep the existing
+packages for compatibility.
## Report Issues / Send Patches
diff --git a/vendor/golang.org/x/oauth2/go.mod b/vendor/golang.org/x/oauth2/go.mod
new file mode 100644
index 0000000000..b345781552
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/go.mod
@@ -0,0 +1,10 @@
+module golang.org/x/oauth2
+
+go 1.11
+
+require (
+ cloud.google.com/go v0.34.0
+ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e
+ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
+ google.golang.org/appengine v1.4.0
+)
diff --git a/vendor/golang.org/x/oauth2/go.sum b/vendor/golang.org/x/oauth2/go.sum
new file mode 100644
index 0000000000..6f0079b0d7
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/go.sum
@@ -0,0 +1,12 @@
+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/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+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=
+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/golang.org/x/oauth2/internal/token.go b/vendor/golang.org/x/oauth2/internal/token.go
index 5ab17b9a5f..83f7847e49 100644
--- a/vendor/golang.org/x/oauth2/internal/token.go
+++ b/vendor/golang.org/x/oauth2/internal/token.go
@@ -11,11 +11,13 @@ import (
"fmt"
"io"
"io/ioutil"
+ "math"
"mime"
"net/http"
"net/url"
"strconv"
"strings"
+ "sync"
"time"
"golang.org/x/net/context/ctxhttp"
@@ -77,6 +79,9 @@ func (e *tokenJSON) expiry() (t time.Time) {
type expirationTime int32
func (e *expirationTime) UnmarshalJSON(b []byte) error {
+ if len(b) == 0 || string(b) == "null" {
+ return nil
+ }
var n json.Number
err := json.Unmarshal(b, &n)
if err != nil {
@@ -86,103 +91,78 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error {
if err != nil {
return err
}
+ if i > math.MaxInt32 {
+ i = math.MaxInt32
+ }
*e = expirationTime(i)
return nil
}
-var brokenAuthHeaderProviders = []string{
- "https://accounts.google.com/",
- "https://api.codeswholesale.com/oauth/token",
- "https://api.dropbox.com/",
- "https://api.dropboxapi.com/",
- "https://api.instagram.com/",
- "https://api.netatmo.net/",
- "https://api.odnoklassniki.ru/",
- "https://api.pushbullet.com/",
- "https://api.soundcloud.com/",
- "https://api.twitch.tv/",
- "https://id.twitch.tv/",
- "https://app.box.com/",
- "https://api.box.com/",
- "https://connect.stripe.com/",
- "https://login.mailchimp.com/",
- "https://login.microsoftonline.com/",
- "https://login.salesforce.com/",
- "https://login.windows.net",
- "https://login.live.com/",
- "https://login.live-int.com/",
- "https://oauth.sandbox.trainingpeaks.com/",
- "https://oauth.trainingpeaks.com/",
- "https://oauth.vk.com/",
- "https://openapi.baidu.com/",
- "https://slack.com/",
- "https://test-sandbox.auth.corp.google.com",
- "https://test.salesforce.com/",
- "https://user.gini.net/",
- "https://www.douban.com/",
- "https://www.googleapis.com/",
- "https://www.linkedin.com/",
- "https://www.strava.com/oauth/",
- "https://www.wunderlist.com/oauth/",
- "https://api.patreon.com/",
- "https://sandbox.codeswholesale.com/oauth/token",
- "https://api.sipgate.com/v1/authorization/oauth",
- "https://api.medium.com/v1/tokens",
- "https://log.finalsurge.com/oauth/token",
- "https://multisport.todaysplan.com.au/rest/oauth/access_token",
- "https://whats.todaysplan.com.au/rest/oauth/access_token",
- "https://stackoverflow.com/oauth/access_token",
- "https://account.health.nokia.com",
- "https://accounts.zoho.com",
-}
+// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
+//
+// Deprecated: this function no longer does anything. Caller code that
+// wants to avoid potential extra HTTP requests made during
+// auto-probing of the provider's auth style should set
+// Endpoint.AuthStyle.
+func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
+
+// AuthStyle is a copy of the golang.org/x/oauth2 package's AuthStyle type.
+type AuthStyle int
-// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints.
-var brokenAuthHeaderDomains = []string{
- ".auth0.com",
- ".force.com",
- ".myshopify.com",
- ".okta.com",
- ".oktapreview.com",
+const (
+ AuthStyleUnknown AuthStyle = 0
+ AuthStyleInParams AuthStyle = 1
+ AuthStyleInHeader AuthStyle = 2
+)
+
+// authStyleCache is the set of tokenURLs we've successfully used via
+// RetrieveToken and which style auth we ended up using.
+// It's called a cache, but it doesn't (yet?) shrink. It's expected that
+// the set of OAuth2 servers a program contacts over time is fixed and
+// small.
+var authStyleCache struct {
+ sync.Mutex
+ m map[string]AuthStyle // keyed by tokenURL
}
-func RegisterBrokenAuthHeaderProvider(tokenURL string) {
- brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
+// ResetAuthCache resets the global authentication style cache used
+// for AuthStyleUnknown token requests.
+func ResetAuthCache() {
+ authStyleCache.Lock()
+ defer authStyleCache.Unlock()
+ authStyleCache.m = nil
}
-// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
-// implements the OAuth2 spec correctly
-// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
-// In summary:
-// - Reddit only accepts client secret in the Authorization header
-// - Dropbox accepts either it in URL param or Auth header, but not both.
-// - Google only accepts URL param (not spec compliant?), not Auth header
-// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
-func providerAuthHeaderWorks(tokenURL string) bool {
- for _, s := range brokenAuthHeaderProviders {
- if strings.HasPrefix(tokenURL, s) {
- // Some sites fail to implement the OAuth2 spec fully.
- return false
- }
- }
+// lookupAuthStyle reports which auth style we last used with tokenURL
+// when calling RetrieveToken and whether we have ever done so.
+func lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) {
+ authStyleCache.Lock()
+ defer authStyleCache.Unlock()
+ style, ok = authStyleCache.m[tokenURL]
+ return
+}
- if u, err := url.Parse(tokenURL); err == nil {
- for _, s := range brokenAuthHeaderDomains {
- if strings.HasSuffix(u.Host, s) {
- return false
- }
- }
+// setAuthStyle adds an entry to authStyleCache, documented above.
+func setAuthStyle(tokenURL string, v AuthStyle) {
+ authStyleCache.Lock()
+ defer authStyleCache.Unlock()
+ if authStyleCache.m == nil {
+ authStyleCache.m = make(map[string]AuthStyle)
}
-
- // Assume the provider implements the spec properly
- // otherwise. We can add more exceptions as they're
- // discovered. We will _not_ be adding configurable hooks
- // to this package to let users select server bugs.
- return true
+ authStyleCache.m[tokenURL] = v
}
-func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
- bustedAuth := !providerAuthHeaderWorks(tokenURL)
- if bustedAuth {
+// newTokenRequest returns a new *http.Request to retrieve a new token
+// from tokenURL using the provided clientID, clientSecret, and POST
+// body parameters.
+//
+// inParams is whether the clientID & clientSecret should be encoded
+// as the POST body. An 'inParams' value of true means to send it in
+// the POST body (along with any values in v); false means to send it
+// in the Authorization header.
+func newTokenRequest(tokenURL, clientID, clientSecret string, v url.Values, authStyle AuthStyle) (*http.Request, error) {
+ if authStyle == AuthStyleInParams {
+ v = cloneURLValues(v)
if clientID != "" {
v.Set("client_id", clientID)
}
@@ -195,15 +175,70 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- if !bustedAuth {
+ if authStyle == AuthStyleInHeader {
req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
}
+ return req, nil
+}
+
+func cloneURLValues(v url.Values) url.Values {
+ v2 := make(url.Values, len(v))
+ for k, vv := range v {
+ v2[k] = append([]string(nil), vv...)
+ }
+ return v2
+}
+
+func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*Token, error) {
+ needsAuthStyleProbe := authStyle == 0
+ if needsAuthStyleProbe {
+ if style, ok := lookupAuthStyle(tokenURL); ok {
+ authStyle = style
+ needsAuthStyleProbe = false
+ } else {
+ authStyle = AuthStyleInHeader // the first way we'll try
+ }
+ }
+ req, err := newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
+ if err != nil {
+ return nil, err
+ }
+ token, err := doTokenRoundTrip(ctx, req)
+ if err != nil && needsAuthStyleProbe {
+ // If we get an error, assume the server wants the
+ // clientID & clientSecret in a different form.
+ // See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
+ // In summary:
+ // - Reddit only accepts client secret in the Authorization header
+ // - Dropbox accepts either it in URL param or Auth header, but not both.
+ // - Google only accepts URL param (not spec compliant?), not Auth header
+ // - Stripe only accepts client secret in Auth header with Bearer method, not Basic
+ //
+ // We used to maintain a big table in this code of all the sites and which way
+ // they went, but maintaining it didn't scale & got annoying.
+ // So just try both ways.
+ authStyle = AuthStyleInParams // the second way we'll try
+ req, _ = newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
+ token, err = doTokenRoundTrip(ctx, req)
+ }
+ if needsAuthStyleProbe && err == nil {
+ setAuthStyle(tokenURL, authStyle)
+ }
+ // Don't overwrite `RefreshToken` with an empty value
+ // if this was a token refreshing request.
+ if token != nil && token.RefreshToken == "" {
+ token.RefreshToken = v.Get("refresh_token")
+ }
+ return token, err
+}
+
+func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
r, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
if err != nil {
return nil, err
}
- defer r.Body.Close()
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
+ r.Body.Close()
if err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
}
@@ -229,7 +264,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
Raw: vals,
}
e := vals.Get("expires_in")
- if e == "" {
+ if e == "" || e == "null" {
// TODO(jbd): Facebook's OAuth2 implementation is broken and
// returns expires_in field in expires. Remove the fallback to expires,
// when Facebook fixes their implementation.
@@ -253,13 +288,8 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
}
json.Unmarshal(body, &token.Raw) // no error checks for optional fields
}
- // Don't overwrite `RefreshToken` with an empty value
- // if this was a token refreshing request.
- if token.RefreshToken == "" {
- token.RefreshToken = v.Get("refresh_token")
- }
if token.AccessToken == "" {
- return token, errors.New("oauth2: server response missing access_token")
+ return nil, errors.New("oauth2: server response missing access_token")
}
return token, nil
}
diff --git a/vendor/golang.org/x/oauth2/oauth2.go b/vendor/golang.org/x/oauth2/oauth2.go
index 0a3c1e1632..428283f0b0 100644
--- a/vendor/golang.org/x/oauth2/oauth2.go
+++ b/vendor/golang.org/x/oauth2/oauth2.go
@@ -26,17 +26,13 @@ import (
// Deprecated: Use context.Background() or context.TODO() instead.
var NoContext = context.TODO()
-// RegisterBrokenAuthHeaderProvider registers an OAuth2 server
-// identified by the tokenURL prefix as an OAuth2 implementation
-// which doesn't support the HTTP Basic authentication
-// scheme to authenticate with the authorization server.
-// Once a server is registered, credentials (client_id and client_secret)
-// will be passed as query parameters rather than being present
-// in the Authorization header.
-// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
-func RegisterBrokenAuthHeaderProvider(tokenURL string) {
- internal.RegisterBrokenAuthHeaderProvider(tokenURL)
-}
+// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
+//
+// Deprecated: this function no longer does anything. Caller code that
+// wants to avoid potential extra HTTP requests made during
+// auto-probing of the provider's auth style should set
+// Endpoint.AuthStyle.
+func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
// Config describes a typical 3-legged OAuth2 flow, with both the
// client application information and the server's endpoint URLs.
@@ -71,13 +67,38 @@ type TokenSource interface {
Token() (*Token, error)
}
-// Endpoint contains the OAuth 2.0 provider's authorization and token
+// Endpoint represents an OAuth 2.0 provider's authorization and token
// endpoint URLs.
type Endpoint struct {
AuthURL string
TokenURL string
+
+ // AuthStyle optionally specifies how the endpoint wants the
+ // client ID & client secret sent. The zero value means to
+ // auto-detect.
+ AuthStyle AuthStyle
}
+// AuthStyle represents how requests for tokens are authenticated
+// to the server.
+type AuthStyle int
+
+const (
+ // AuthStyleAutoDetect means to auto-detect which authentication
+ // style the provider wants by trying both ways and caching
+ // the successful way for the future.
+ AuthStyleAutoDetect AuthStyle = 0
+
+ // AuthStyleInParams sends the "client_id" and "client_secret"
+ // in the POST body as application/x-www-form-urlencoded parameters.
+ AuthStyleInParams AuthStyle = 1
+
+ // AuthStyleInHeader sends the client_id and client_password
+ // using HTTP Basic Authorization. This is an optional style
+ // described in the OAuth2 RFC 6749 section 2.3.1.
+ AuthStyleInHeader AuthStyle = 2
+)
+
var (
// AccessTypeOnline and AccessTypeOffline are options passed
// to the Options.AuthCodeURL method. They modify the
@@ -124,7 +145,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
//
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
// as ApprovalForce.
-// It can also be used to pass the PKCE challange.
+// It can also be used to pass the PKCE challenge.
// See https://www.oauth.com/oauth2-servers/pkce/ for more info.
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
var buf bytes.Buffer
@@ -164,8 +185,7 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
// and when other authorization grant types are not available."
// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
//
-// The HTTP client to use is derived from the context.
-// If nil, http.DefaultClient is used.
+// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
v := url.Values{
"grant_type": {"password"},
@@ -183,8 +203,7 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
// It is used after a resource provider redirects the user back
// to the Redirect URI (the URL obtained from AuthCodeURL).
//
-// The HTTP client to use is derived from the context.
-// If a client is not provided via the context, http.DefaultClient is used.
+// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
//
// The code will be in the *http.Request.FormValue("code"). Before
// calling Exchange, be sure to validate FormValue("state").
diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go
index 9be1ae5373..822720341a 100644
--- a/vendor/golang.org/x/oauth2/token.go
+++ b/vendor/golang.org/x/oauth2/token.go
@@ -118,13 +118,16 @@ func (t *Token) Extra(key string) interface{} {
return v
}
+// timeNow is time.Now but pulled out as a variable for tests.
+var timeNow = time.Now
+
// expired reports whether the token is expired.
// t must be non-nil.
func (t *Token) expired() bool {
if t.Expiry.IsZero() {
return false
}
- return t.Expiry.Round(0).Add(-expiryDelta).Before(time.Now())
+ return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
}
// Valid reports whether t is non-nil, has an AccessToken, and is not expired.
@@ -151,7 +154,7 @@ func tokenFromInternal(t *internal.Token) *Token {
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
// with an error..
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
- tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v)
+ tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle))
if err != nil {
if rErr, ok := err.(*internal.RetrieveError); ok {
return nil, (*RetrieveError)(rErr)
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 567ace1877..9756887a52 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -158,8 +158,8 @@ github.com/go-sql-driver/mysql
github.com/go-xorm/xorm
# github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
github.com/gogits/chardet
-# github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183
-github.com/gogits/cron
+# github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
+github.com/gogs/cron
# github.com/golang/protobuf v1.3.1
github.com/golang/protobuf/proto
# github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
@@ -369,7 +369,7 @@ golang.org/x/net/context/ctxhttp
golang.org/x/net/proxy
golang.org/x/net/context
golang.org/x/net/internal/socks
-# golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759
+# golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
golang.org/x/oauth2
golang.org/x/oauth2/internal
# golang.org/x/sys v0.0.0-20190620070143-6f217b454f45