├── .dockerignore ├── scripts ├── savedep.sh └── gen_license.sh ├── pkg ├── worker │ ├── utilities.go │ ├── executor.go │ ├── external_worker.go │ ├── utility_rlimit.go │ ├── worker.go │ ├── shell_script_executor.go │ ├── executor_invoke_worker.go │ └── worker_test.go ├── helper │ ├── disk_usage.go │ ├── helper_test.go │ └── max_length_slice.go ├── manager │ ├── manager_test.go │ ├── json_rest.go │ └── manager.go ├── config │ ├── config.go │ └── config_test.go └── exporter │ └── exporter.go ├── autocompletion └── zsh │ ├── usage.md │ └── _lug ├── Dockerfile ├── docs └── api-mocks │ └── manager │ └── summary ├── .gitignore ├── .github └── workflows │ ├── test.yml │ └── release.yml ├── config.example.yaml ├── go.mod ├── README.md ├── cli └── lug │ ├── main.go │ └── license.go ├── go.sum └── LICENSE /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | /lug 3 | -------------------------------------------------------------------------------- /scripts/savedep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | godep save . ./manager ./worker ./config ./helper 3 | -------------------------------------------------------------------------------- /pkg/worker/utilities.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | type utility interface { 4 | preHook() error 5 | postHook() error 6 | } 7 | -------------------------------------------------------------------------------- /autocompletion/zsh/usage.md: -------------------------------------------------------------------------------- 1 | Copy `_lug` to an arbitrary directory(e.g. `~/zsh-completion`), then add the directory to your `fpath` in `.zshrc`: `fpath=(~/zsh-completion $fpath)`. 2 | -------------------------------------------------------------------------------- /scripts/gen_license.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Genetate license.go 4 | find ./vendor -name 'LICENSE' | xargs tail -n +1 > temp.license && echo -e "package main \n /* Generated by script scripts/gen_license.sh */ \n const licenseText = \` `cat temp.license` \`" > license.go && rm -f temp.license 5 | -------------------------------------------------------------------------------- /pkg/worker/executor.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import "github.com/sirupsen/logrus" 4 | 5 | type execResult struct { 6 | Stdout string 7 | Stderr string 8 | } 9 | 10 | // executor is a layer beneath worker, called by executorInvokeWorker 11 | type executor interface { 12 | // When called, the executor performs sync for one time 13 | RunOnce(logger *logrus.Entry, utilities []utility) (execResult, error) 14 | } 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23 AS build-env 2 | # The GOPATH in the image is /go. 3 | ADD . /go/src/github.com/sjtug/lug 4 | WORKDIR /go/src/github.com/sjtug/lug 5 | RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 6 | RUN dep ensure 7 | RUN go build github.com/sjtug/lug/cli/lug 8 | 9 | FROM debian:12 10 | WORKDIR /app 11 | COPY --from=build-env /go/src/github.com/sjtug/lug/lug /app/ 12 | ENTRYPOINT ["./lug"] 13 | -------------------------------------------------------------------------------- /docs/api-mocks/manager/summary: -------------------------------------------------------------------------------- 1 | { 2 | "Running": true, 3 | "WorkerStatus": { 4 | "putty": { 5 | "Result": true, 6 | "LastFinished": "2018-01-16T21:45:56.27813641+08:00", 7 | "Idle": false 8 | }, 9 | "vim": { 10 | "Result": false, 11 | "LastFinished": "2018-01-16T21:45:53.27813641+08:00", 12 | "Idle": true 13 | }, 14 | "docker": { 15 | "Result": true, 16 | "LastFinished": "2018-01-16T21:45:51.27813641+08:00", 17 | "Idle": true 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Compiled binary files and configuration 7 | /lug 8 | config.yaml 9 | checkpoint.json 10 | 11 | # Folders 12 | _obj 13 | _test 14 | 15 | # Architecture specific extensions/prefixes 16 | *.[568vq] 17 | [568vq].out 18 | 19 | *.cgo1.go 20 | *.cgo2.c 21 | _cgo_defun.c 22 | _cgo_gotypes.go 23 | _cgo_export.* 24 | 25 | _testmain.go 26 | 27 | *.exe 28 | *.test 29 | *.prof 30 | 31 | /.idea 32 | 33 | /vendor 34 | /lug.zip 35 | /Caddyfile 36 | /gomplate* 37 | /_vendor* 38 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: 6 | branches: 7 | - master 8 | 9 | name: Test 10 | 11 | jobs: 12 | test: 13 | name: Test 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: actions/setup-go@v2 18 | with: 19 | go-version: '^1.23' 20 | # TODO: import coveralls key 21 | # - run: go get github.com/mattn/goveralls 22 | - run: go build -o lug github.com/sjtug/lug/cli/lug 23 | - run: go test $(go list ./... | grep -v /vendor/) 24 | # - run: goveralls -v 25 | -------------------------------------------------------------------------------- /autocompletion/zsh/_lug: -------------------------------------------------------------------------------- 1 | #compdef lug 2 | local -a options arguments 3 | #options=('-c:Path of config.yaml' '-cert:Cert for JSON API' '-key:Key for JSON API' '-j:JSON API Address' '-license:Prints license' '-v:Prints version of lug' '-h:Show help') 4 | #_describe 'values' options 5 | _arguments '-c[Path of config]:path_of_config:->config' '-cert[Cert for JSON API]:cert:_files' '-key[Key for JSON API]:key:_files' '-j[JSON API Address]:jaddr' '-license[License]' '-v[Version of lug]' '-h[Show help]' '-u[User for JSON API]' '-p[Password for JSON API]' 6 | 7 | case "$state" in 8 | config) 9 | local -a configs 10 | configs=( *.{yml,yaml} ) 11 | _multi_parts / configs 12 | esac 13 | -------------------------------------------------------------------------------- /pkg/helper/disk_usage.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "os" 5 | "path" 6 | ) 7 | 8 | // DiskUsage counts the disk usage of a directory. The call is synchronous 9 | func DiskUsage(curPath string) (int64, error) { 10 | var size int64 11 | 12 | dir, err := os.Open(curPath) 13 | if err != nil { 14 | return size, err 15 | } 16 | defer dir.Close() 17 | 18 | files, err := dir.Readdir(-1) 19 | if err != nil { 20 | return size, err 21 | } 22 | 23 | for _, file := range files { 24 | if file.IsDir() { 25 | s, err := DiskUsage(path.Join(curPath, file.Name())) 26 | if err != nil { 27 | return size, err 28 | } 29 | size += s 30 | } else { 31 | size += file.Size() 32 | } 33 | } 34 | return size, nil 35 | } 36 | -------------------------------------------------------------------------------- /pkg/manager/manager_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | log "github.com/sirupsen/logrus" 9 | "github.com/stretchr/testify/assert" 10 | 11 | "github.com/sjtug/lug/pkg/config" 12 | ) 13 | 14 | func TestManagerStartUp(t *testing.T) { 15 | manager, err := NewManager(&config.Config{ 16 | Interval: 3, 17 | Repos: []config.RepoConfig{}, 18 | }) 19 | assert.Nil(t, err) 20 | if assert.NotNil(t, manager) { 21 | log.Debugf("Manager: %+v", manager) 22 | go manager.Run() 23 | ch := time.NewTicker(5 * time.Second).C 24 | <-ch 25 | status := manager.GetStatus() 26 | assert.True(t, status.Running) 27 | fmt.Printf("Manager status before Stop():\n%v\n", status) 28 | manager.Stop() 29 | manager.Exit() 30 | // Because Stop() and Exit() are currently async, we should wait first. 31 | ch = time.NewTicker(1 * time.Second).C 32 | <-ch 33 | status = manager.GetStatus() 34 | assert.False(t, status.Running) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - release 5 | tags: 6 | - "v*" 7 | 8 | name: Release 9 | 10 | jobs: 11 | release: 12 | name: Release 13 | runs-on: ubuntu-24.04 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: actions/setup-go@v2 17 | with: 18 | go-version: '^1.23' 19 | - run: go build -o lug github.com/sjtug/lug/cli/lug 20 | - name: create tar 21 | run: tar -cvzf lug.tar.gz lug 22 | - uses: actions/create-release@latest 23 | id: create_release 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | with: 27 | tag_name: ${{ github.ref }} 28 | release_name: Release ${{ github.ref }} 29 | body: ${{ github.event.head_commit.message }} 30 | draft: false 31 | prerelease: true 32 | - name: upload release (tar) 33 | uses: actions/upload-release-asset@v1.0.1 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | with: 37 | upload_url: ${{ steps.create_release.outputs.upload_url }} 38 | asset_path: lug.tar.gz 39 | asset_name: lug.tar.gz 40 | asset_content_type: application/tar+gzip 41 | -------------------------------------------------------------------------------- /config.example.yaml: -------------------------------------------------------------------------------- 1 | interval: 3 # Interval between pollings 2 | loglevel: 5 # 1-5 3 | concurrent_limit: 1 # Maximum worker that can run at the same time 4 | # Prometheus metrics are exposed at http://exporter_address/metrics 5 | exporter_address: :8081 6 | checkpoint: checkpoint.json 7 | 8 | #logstash: 9 | # address: listener.logz.io:5050 # logstash sink. Lug will send all logs to this address 10 | # additional_fields: 11 | # token: "" # Additional fields sent to logstash server 12 | 13 | # Address where JSON API will be served 14 | json_api: 15 | address: :7001 16 | 17 | repos: 18 | - type: shell_script 19 | script: rsync -av rsync://rsync.chiark.greenend.org.uk/ftp/users/sgtatham/putty-website-mirror/ /tmp/putty 20 | name: putty 21 | interval: 600 22 | - type: shell_script 23 | script: bash -c 'printenv | grep ^LUG' 24 | name: printenv 25 | any_option: any_value 26 | any_switch: true # This will be set to 1 27 | any_switch_2: false # unset 28 | interval: 10 29 | - type: external 30 | name: ubuntu 31 | proxy_to: http://ftp.sjtu.edu.cn/ubuntu/ 32 | # Since interval is not set for this target, this will only be triggered at startup 33 | -------------------------------------------------------------------------------- /pkg/worker/external_worker.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | log "github.com/sirupsen/logrus" 8 | 9 | "github.com/sjtug/lug/pkg/config" 10 | ) 11 | 12 | // ExternalWorker is a stub worker which always returns 13 | // {Idle: false, Result: true}. 14 | type ExternalWorker struct { 15 | name string 16 | logger *log.Entry 17 | cfg config.RepoConfig 18 | } 19 | 20 | func NewExternalWorker(cfg config.RepoConfig) (*ExternalWorker, error) { 21 | rawName, ok := cfg["name"] 22 | if !ok { 23 | return nil, errors.New("Name is required for external worker") 24 | } 25 | name := rawName.(string) 26 | return &ExternalWorker{ 27 | name: name, 28 | logger: log.WithField("worker", name), 29 | cfg: cfg, 30 | }, nil 31 | } 32 | 33 | func (ew *ExternalWorker) GetStatus() Status { 34 | return Status{ 35 | Result: true, 36 | LastFinished: time.Now(), 37 | Idle: true, 38 | Stdout: []string{}, 39 | Stderr: []string{}, 40 | } 41 | } 42 | 43 | func (ew *ExternalWorker) RunSync() { 44 | // a for {} should not be used here since it occupies 100% CPU 45 | select {} 46 | } 47 | 48 | func (ew *ExternalWorker) TriggerSync() { 49 | } 50 | 51 | func (ew *ExternalWorker) GetConfig() config.RepoConfig { 52 | return ew.cfg 53 | } 54 | -------------------------------------------------------------------------------- /pkg/worker/utility_rlimit.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | 7 | "github.com/dustin/go-humanize" 8 | ) 9 | 10 | type rlimit struct { 11 | oldRlimit syscall.Rlimit 12 | w Worker 13 | } 14 | 15 | func newRlimit(w Worker) *rlimit { 16 | return &rlimit{ 17 | w: w, 18 | } 19 | } 20 | 21 | type rlimitError string 22 | 23 | func (re rlimitError) Error() string { 24 | return string(re) 25 | } 26 | 27 | func (r *rlimit) preHook() error { 28 | cfg := r.w.GetConfig() 29 | if err := syscall.Getrlimit(syscall.RLIMIT_AS, &r.oldRlimit); err != nil { 30 | return rlimitError(fmt.Sprint("Failed to getrlimit:", err)) 31 | } 32 | if rlimitMem, ok := cfg["rlimit_mem"]; ok { 33 | if bytes, err := humanize.ParseBytes(rlimitMem.(string)); err == nil { 34 | var rlimitNew syscall.Rlimit 35 | rlimitNew = r.oldRlimit 36 | rlimitNew.Cur = bytes 37 | err := syscall.Setrlimit(syscall.RLIMIT_AS, &rlimitNew) 38 | if err != nil { 39 | return rlimitError(fmt.Sprint("Failed to setrlimit:", err)) 40 | } 41 | } else { 42 | return rlimitError(fmt.Sprint("Invalid rlimit_mem: must be size:", err)) 43 | } 44 | } 45 | return nil 46 | } 47 | 48 | func (r *rlimit) postHook() error { 49 | err := syscall.Setrlimit(syscall.RLIMIT_AS, &r.oldRlimit) 50 | if err != nil { 51 | return rlimitError(fmt.Sprint("Failed to restore rlimit:", err)) 52 | } 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sjtug/lug 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.7 6 | 7 | require ( 8 | github.com/ant0ine/go-json-rest v3.3.2+incompatible 9 | github.com/cheshir/logrustash v0.0.0-20230213210745-aca6961b250d 10 | github.com/davecgh/go-spew v1.1.1 11 | github.com/dustin/go-humanize v1.0.1 12 | github.com/prometheus/client_golang v1.21.1 13 | github.com/sirupsen/logrus v1.9.3 14 | github.com/spf13/pflag v1.0.6 15 | github.com/spf13/viper v1.20.0 16 | github.com/stretchr/testify v1.10.0 17 | mvdan.cc/sh/v3 v3.11.0 18 | ) 19 | 20 | require ( 21 | github.com/beorn7/perks v1.0.1 // indirect 22 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 23 | github.com/fsnotify/fsnotify v1.8.0 // indirect 24 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect 25 | github.com/klauspost/compress v1.18.0 // indirect 26 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 27 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect 28 | github.com/pmezard/go-difflib v1.0.0 // indirect 29 | github.com/prometheus/client_model v0.6.1 // indirect 30 | github.com/prometheus/common v0.63.0 // indirect 31 | github.com/prometheus/procfs v0.16.0 // indirect 32 | github.com/sagikazarmark/locafero v0.8.0 // indirect 33 | github.com/sourcegraph/conc v0.3.0 // indirect 34 | github.com/spf13/afero v1.14.0 // indirect 35 | github.com/spf13/cast v1.7.1 // indirect 36 | github.com/subosito/gotenv v1.6.0 // indirect 37 | go.uber.org/multierr v1.11.0 // indirect 38 | golang.org/x/sys v0.31.0 // indirect 39 | golang.org/x/text v0.23.0 // indirect 40 | google.golang.org/protobuf v1.36.5 // indirect 41 | gopkg.in/yaml.v3 v3.0.1 // indirect 42 | ) 43 | -------------------------------------------------------------------------------- /pkg/helper/helper_test.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestMaxLengthStringSliceAdaptor(t *testing.T) { 11 | asrt := assert.New(t) 12 | raw := []string{"foo", "bar"} 13 | mlss := NewMaxLengthStringSliceAdaptor(raw, 3) 14 | news := mlss.GetAll() 15 | asrt.True(reflect.DeepEqual(raw, news)) 16 | asrt.Equal(2, mlss.Len()) 17 | asrt.Equal(3, mlss.MaxLen()) 18 | 19 | raw[1] = "foobar" 20 | news = mlss.GetAll() 21 | asrt.True(reflect.DeepEqual(raw, news), "Raw=%v\tMLSS=%v", raw, mlss) 22 | 23 | mlss.Put("2") 24 | asrt.Equal(3, mlss.Len()) 25 | asrt.True(reflect.DeepEqual([]string{"foo", "foobar", "2"}, mlss.GetAll())) 26 | asrt.False(reflect.DeepEqual(mlss, raw)) 27 | 28 | mlss.Put("3") 29 | asrt.Equal(3, mlss.Len()) 30 | asrt.True(reflect.DeepEqual([]string{"foobar", "2", "3"}, mlss.GetAll())) 31 | asrt.False(reflect.DeepEqual(mlss, raw)) 32 | } 33 | 34 | func TestMaxLengthSlice(t *testing.T) { 35 | asrt := assert.New(t) 36 | raw := []string{"foo", "bar"} 37 | mlss := NewMaxLengthSlice(raw, 3) 38 | news := mlss.GetAll() 39 | asrt.True(reflect.DeepEqual(raw, news)) 40 | asrt.Equal(2, mlss.Len()) 41 | asrt.Equal(3, mlss.MaxLen()) 42 | 43 | raw[1] = "foobar" 44 | news = mlss.GetAll() 45 | asrt.True(reflect.DeepEqual([]string{"foo", "bar"}, news)) 46 | 47 | mlss.Put("2") 48 | asrt.Equal(3, mlss.Len()) 49 | asrt.True(reflect.DeepEqual([]string{"foo", "bar", "2"}, mlss.GetAll()), "MLSS=%v", mlss.GetAll()) 50 | asrt.True(reflect.DeepEqual([]string{"foo", "foobar"}, raw)) 51 | 52 | mlss.Put("3") 53 | asrt.Equal(3, mlss.Len()) 54 | asrt.True(reflect.DeepEqual([]string{"bar", "2", "3"}, mlss.GetAll())) 55 | asrt.True(reflect.DeepEqual([]string{"foo", "foobar"}, raw)) 56 | } 57 | 58 | func TestDiskUsage(t *testing.T) { 59 | asrt := assert.New(t) 60 | size, err := DiskUsage(".") 61 | asrt.True(err == nil) 62 | asrt.True(size > 0) 63 | } 64 | -------------------------------------------------------------------------------- /pkg/helper/max_length_slice.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | // MaxLengthStringSliceAdaptor wrap the given slice with several methods for MaxLenSlice. 8 | // Note that this adaptor does not own that slice at all, so keep the content of slice unchanged! 9 | type MaxLengthStringSliceAdaptor struct { 10 | s []string 11 | maxlen int 12 | lock sync.RWMutex 13 | } 14 | 15 | // NewMaxLengthStringSliceAdaptor creates an adaptor for given string slice 16 | func NewMaxLengthStringSliceAdaptor(s []string, maxlen int) *MaxLengthStringSliceAdaptor { 17 | result := &MaxLengthStringSliceAdaptor{ 18 | s: s, 19 | maxlen: maxlen, 20 | } 21 | result.removeExceededItems() 22 | return result 23 | } 24 | 25 | // MaxLen returns the maximum length of given maxlenslice 26 | func (m *MaxLengthStringSliceAdaptor) MaxLen() int { 27 | return m.maxlen 28 | } 29 | 30 | // Use it when you acquire the lock 31 | func (m *MaxLengthStringSliceAdaptor) removeExceededItems() { 32 | if len(m.s) > m.MaxLen() { 33 | m.s = m.s[len(m.s)-m.MaxLen():] 34 | } 35 | } 36 | 37 | // Put adds a new item into slice, and may remove exceeded item(s) 38 | func (m *MaxLengthStringSliceAdaptor) Put(str string) { 39 | m.lock.Lock() 40 | defer m.lock.Unlock() 41 | m.s = append(m.s, str) 42 | m.removeExceededItems() 43 | } 44 | 45 | // GetAll creates a duplicate of current slice and returns it 46 | func (m *MaxLengthStringSliceAdaptor) GetAll() []string { 47 | m.lock.RLock() 48 | defer m.lock.RUnlock() 49 | result := make([]string, len(m.s)) 50 | copy(result, m.s) 51 | return result 52 | } 53 | 54 | // Len returns current length of slice 55 | func (m *MaxLengthStringSliceAdaptor) Len() int { 56 | m.lock.RLock() 57 | defer m.lock.RUnlock() 58 | return len(m.s) 59 | } 60 | 61 | // NewMaxLengthSlice copies and inits a new max length string slice 62 | func NewMaxLengthSlice(s []string, maxlen int) *MaxLengthStringSliceAdaptor { 63 | news := make([]string, len(s)) 64 | copy(news, s) 65 | return NewMaxLengthStringSliceAdaptor(news, maxlen) 66 | } 67 | -------------------------------------------------------------------------------- /pkg/worker/worker.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | "github.com/sjtug/lug/pkg/config" 8 | ) 9 | 10 | // Worker declares interface for workers using diffenent ways of sync. 11 | type Worker interface { 12 | // This call should be thread-safe 13 | GetStatus() Status 14 | // This should block forever 15 | RunSync() 16 | // This call should be thread-safe 17 | TriggerSync() 18 | 19 | GetConfig() config.RepoConfig 20 | } 21 | 22 | // Status shows sync result and last timestamp. 23 | type Status struct { 24 | // Result is true if sync succeed, else false 25 | Result bool 26 | // LastFinished indicates last success time 27 | LastFinished time.Time 28 | // Idle stands for whether worker is idle, false if syncing 29 | Idle bool 30 | // Last stdout(s) for admin. Internal implementation may vary to provide it in Status() 31 | Stdout []string 32 | // Last stderr(s) for admin. Internal implementation may vary to provide it in Status() 33 | Stderr []string 34 | } 35 | 36 | // NewWorker generates a worker by config and log. 37 | func NewWorker(cfg config.RepoConfig, lastFinished time.Time, Result bool) (Worker, error) { 38 | if syncType, ok := cfg["type"]; ok { 39 | switch syncType { 40 | case "rsync": 41 | return nil, errors.New("rsync worker has been removed since 0.10. " + 42 | "Use rsync.sh with shell_script worker at https://github.com/sjtug/mirror-docker instead") 43 | case "shell_script": 44 | w, err := NewExecutorInvokeWorker( 45 | newShellScriptExecutor(cfg), 46 | Status{ 47 | Result: Result, 48 | LastFinished: lastFinished, 49 | Idle: true, 50 | Stdout: make([]string, 0), 51 | Stderr: make([]string, 0), 52 | }, 53 | cfg, 54 | make(chan int)) 55 | if err != nil { 56 | return nil, err 57 | } 58 | return w, nil 59 | case "external": 60 | w, err := NewExternalWorker(cfg) 61 | if err != nil { 62 | return nil, err 63 | } 64 | return w, nil 65 | } 66 | } 67 | return nil, errors.New("Fail to create a new worker") 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lug 2 | [![release](https://img.shields.io/github/release/sjtug/lug.svg)](https://github.com/sjtug/lug/releases) 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/sjtug/lug)](https://goreportcard.com/report/github.com/sjtug/lug) 4 | [![Build Status](https://travis-ci.org/sjtug/lug.svg)](https://travis-ci.org/sjtug/lug) 5 | [![Docker pulls](https://img.shields.io/docker/pulls/htfy96/lug.svg)](https://hub.docker.com/r/htfy96/lug/) 6 | [![Apache License](https://img.shields.io/github/license/sjtug/lug.svg)](https://github.com/sjtug/lug/blob/master/LICENSE) 7 | 8 | Extensible backend of software mirror. Read our [Wiki](https://github.com/sjtug/lug/wiki) for usage and guides for developmenet. 9 | 10 | ## Use it in docker 11 | ``` 12 | docker run -d -v {{host_path}}:{{docker_path}} -v {{absolute_path_of_config.yaml}}:/go/src/github.com/sjtug/lug/config.yaml htfy96/lug {other args...} 13 | ``` 14 | 15 | ### config.yaml 16 | 17 | The below configuration may be outdated. Refer to [config.example.yaml](https://github.com/sjtug/lug/blob/master/config.example.yaml) 18 | and [Wiki](https://github.com/sjtug/lug/wiki/Configuration) for the latest version. 19 | 20 | ``` 21 | interval: 3 # Interval between pollings 22 | loglevel: 5 # 0-5. 0 for ERROR and 5 for DEBUG 23 | logstashaddr: "172.0.0.4:6000" # TCP Address of logstash. empty means no logstash support 24 | dummy: # place your anchor here! 25 | common_interval: &common_interval 26 | interval: 3600 27 | common_retry: &commone_retry 28 | retry: 3 29 | repos: 30 | - type: shell_script 31 | script: rsync -av rsync://rsync.chiark.greenend.org.uk/ftp/users/sgtatham/putty-website-mirror/ /tmp/putty 32 | name: putty 33 | rlimit: 300M 34 | <<: *common_interval # interval: 3600 will be inserted here 35 | - type: external 36 | name: ubuntu 37 | proxy_to: http://ftp.sjtu.edu.cn/ubuntu/ 38 | <<: [*common_interval, *common_retry] # use array for importing multiple anchors 39 | # You can add more repos here, different repos may have different worker types, 40 | # refer to Worker Types section for detailed explanation 41 | ``` 42 | 43 | ## Development 44 | 45 | Contributors should push to their own branch. Reviewed code will be merged to `master` branch. 46 | 47 | Currently this project assumes Go >= 1.23. 48 | 49 | 1. set your `GOPATH` to a directory: `export GOPATH=/home/go`. Set `$GOPATH/bin` to your `$PATH`: `export PATH=$PATH:$GOPATH/bin` 50 | 2. `go get github.com/sjtug/lug` 51 | 3. Install dep by `curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh` 52 | 3. `cd $GOPATH/src/github.com/sjtug/lug && dep ensure` 53 | 4. Modify code, then use `go build .` to build binary, or test with `go test $(go list ./... | grep -v /vendor/)` 54 | 5. Run `scripts/gen_license.sh` before committing your code 55 | 56 | NOTICE: Please attach test files when contributing to your module 57 | 58 | -------------------------------------------------------------------------------- /pkg/manager/json_rest.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/ant0ine/go-json-rest/rest" 8 | log "github.com/sirupsen/logrus" 9 | ) 10 | 11 | // RestfulAPI is a JSON-like API of given manager 12 | type RestfulAPI struct { 13 | manager *Manager 14 | } 15 | 16 | // NewRestfulAPI returns a pointer to RestfulAPI of given manager 17 | func NewRestfulAPI(m *Manager) *RestfulAPI { 18 | return &RestfulAPI{ 19 | manager: m, 20 | } 21 | } 22 | 23 | // GetAPIHandler returns handler that could be used for http package 24 | func (r *RestfulAPI) GetAPIHandler() http.Handler { 25 | api := rest.NewApi() 26 | api.Use(rest.DefaultDevStack...) 27 | router, err := rest.MakeRouter( 28 | rest.Get("/lug/v1/admin/manager/detail", r.getManagerStatusDetail), 29 | rest.Get("/lug/v1/manager/summary", r.getManagerStatusSummary), 30 | rest.Post("/lug/v1/admin/manager/start", r.startManager), 31 | rest.Post("/lug/v1/admin/manager/stop", r.stopManager), 32 | rest.Delete("/lug/v1/admin/manager", r.exitManager), 33 | ) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | api.SetApp(router) 38 | return api.MakeHandler() 39 | } 40 | 41 | type WorkerStatusSimple struct { 42 | // Result is true if sync succeed, else false 43 | Result bool 44 | // LastFinished indicates last success time 45 | LastFinished time.Time 46 | // Idle stands for whether worker is idle, false if syncing 47 | Idle bool 48 | } 49 | 50 | type MangerStatusSimple struct { 51 | Running bool 52 | WorkerStatus map[string]WorkerStatusSimple 53 | } 54 | 55 | func (r *RestfulAPI) getManagerStatusCommon(w rest.ResponseWriter, req *rest.Request, detailed bool) { 56 | rawStatus := r.manager.GetStatus() 57 | if detailed { 58 | w.WriteJson(rawStatus) 59 | return 60 | } 61 | managerStatusSimple := MangerStatusSimple{ 62 | Running: rawStatus.Running, 63 | WorkerStatus: map[string]WorkerStatusSimple{}, 64 | } 65 | // summary mode 66 | for workerKey, rawWorkerStatus := range rawStatus.WorkerStatus { 67 | managerStatusSimple.WorkerStatus[workerKey] = WorkerStatusSimple{ 68 | Result: rawWorkerStatus.Result, 69 | LastFinished: rawWorkerStatus.LastFinished, 70 | Idle: rawWorkerStatus.Idle, 71 | } 72 | } 73 | w.WriteJson(managerStatusSimple) 74 | } 75 | 76 | func (r *RestfulAPI) getManagerStatusDetail(w rest.ResponseWriter, req *rest.Request) { 77 | r.getManagerStatusCommon(w, req, true) 78 | } 79 | 80 | func (r *RestfulAPI) getManagerStatusSummary(w rest.ResponseWriter, req *rest.Request) { 81 | r.getManagerStatusCommon(w, req, false) 82 | } 83 | 84 | func (r *RestfulAPI) startManager(w rest.ResponseWriter, req *rest.Request) { 85 | r.manager.Start() 86 | } 87 | 88 | func (r *RestfulAPI) stopManager(w rest.ResponseWriter, req *rest.Request) { 89 | r.manager.Stop() 90 | } 91 | 92 | func (r *RestfulAPI) exitManager(w rest.ResponseWriter, req *rest.Request) { 93 | r.manager.Exit() 94 | } 95 | -------------------------------------------------------------------------------- /cli/lug/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "time" 8 | 9 | "github.com/cheshir/logrustash" 10 | "github.com/davecgh/go-spew/spew" 11 | log "github.com/sirupsen/logrus" 12 | flag "github.com/spf13/pflag" 13 | 14 | "github.com/sjtug/lug/pkg/config" 15 | "github.com/sjtug/lug/pkg/exporter" 16 | "github.com/sjtug/lug/pkg/manager" 17 | ) 18 | 19 | const ( 20 | lugVersionInfo = `Lug: An extensible backend for software mirror 21 | Presented by SJTUG Version 0.12.1 22 | 23 | Visit https://github.com/sjtug/lug for latest version` 24 | configHelp = `Refer to config.example.yaml for sample config!` 25 | ) 26 | 27 | // CommandFlags stores parsed flags from command line 28 | type CommandFlags struct { 29 | configFile string 30 | version bool 31 | license bool 32 | jsonAPIAddr string 33 | exporterAddr string 34 | } 35 | 36 | // parse command line options and return CommandFlags 37 | func getFlags() (flags CommandFlags) { 38 | flag.StringVarP(&flags.configFile, "conf", "c", "config.yaml", 39 | configHelp) 40 | flag.BoolVar(&flags.license, "license", false, "Prints license of used libraries") 41 | flag.BoolVarP(&flags.version, "version", "v", false, "Prints version of lug") 42 | flag.StringVarP(&flags.jsonAPIAddr, "jsonapi", "j", "", "JSON API Address") 43 | flag.StringVarP(&flags.exporterAddr, "exporter", "e", "", "Exporter Address") 44 | flag.Parse() 45 | return 46 | } 47 | 48 | // Register Logger and set logLevel 49 | func prepareLogger(logLevel log.Level, logStashAddr string, additionalFields map[string]interface{}) { 50 | log.SetLevel(logLevel) 51 | if logStashAddr != "" { 52 | hook, err := logrustash.NewAsyncHookWithFields("tcp", logStashAddr, "lug", additionalFields) 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | hook.WaitUntilBufferFrees = true 57 | hook.ReconnectBaseDelay = time.Second 58 | hook.ReconnectDelayMultiplier = 2 59 | hook.MaxSendRetries = 10 60 | log.AddHook(hook) 61 | } 62 | } 63 | 64 | var cfg config.Config 65 | 66 | func init() { 67 | flags := getFlags() 68 | 69 | cfgViper := config.CfgViper 70 | cfgViper.BindPFlag("json_api.address", flag.Lookup("jsonapi")) 71 | cfgViper.BindPFlag("exporter_address", flag.Lookup("exporter")) 72 | 73 | if flags.version { 74 | fmt.Print(lugVersionInfo) 75 | os.Exit(0) 76 | } 77 | 78 | if flags.license { 79 | fmt.Print(licenseText) 80 | os.Exit(0) 81 | } 82 | 83 | file, err := os.Open(flags.configFile) 84 | if err != nil { 85 | log.Error(err) 86 | fmt.Print(configHelp) 87 | os.Exit(0) 88 | } 89 | defer file.Close() 90 | cfg = config.Config{} 91 | err = cfg.Parse(file) 92 | 93 | prepareLogger(cfg.LogLevel, cfg.LogStashConfig.Address, cfg.LogStashConfig.AdditionalFields) 94 | log.Info("Starting...") 95 | log.Debugln(spew.Sdump(cfg)) 96 | if err != nil { 97 | panic(err) 98 | } 99 | } 100 | 101 | func main() { 102 | m, err := manager.NewManager(&cfg) 103 | if err != nil { 104 | panic(err) 105 | } 106 | jsonapi := manager.NewRestfulAPI(m) 107 | handler := jsonapi.GetAPIHandler() 108 | go http.ListenAndServe(cfg.JsonAPIConfig.Address, handler) 109 | 110 | go exporter.Expose(cfg.ExporterAddr) 111 | m.Run() 112 | } 113 | -------------------------------------------------------------------------------- /pkg/config/config.go: -------------------------------------------------------------------------------- 1 | // Package config provides the definition of Config and a method 2 | // to parse it from a []byte 3 | package config 4 | 5 | import ( 6 | "errors" 7 | "fmt" 8 | "io" 9 | "os" 10 | "reflect" 11 | 12 | "github.com/davecgh/go-spew/spew" 13 | log "github.com/sirupsen/logrus" 14 | "github.com/spf13/viper" 15 | ) 16 | 17 | // RepoConfig stores config of each repo in a map 18 | type RepoConfig map[string]interface{} 19 | 20 | type JsonAPIConfig struct { 21 | // The address that lug listens for JSON API 22 | Address string 23 | } 24 | 25 | type LogStashConfig struct { 26 | Address string 27 | AdditionalFields map[string]interface{} `mapstructure:"additional_fields"` 28 | } 29 | 30 | // Config stores all configuration of lug 31 | type Config struct { 32 | // Interval between pollings in manager 33 | Interval int 34 | // LogLevel: 0-5 is acceptable 35 | LogLevel log.Level 36 | // ConcurrentLimit: how many worker can run at the same time 37 | ConcurrentLimit int `mapstructure:"concurrent_limit"` 38 | // LogStashConfig represents configurations for logstash 39 | LogStashConfig LogStashConfig `mapstructure:"logstash"` 40 | // ExporterAddr is the address to expose metrics, :8080 for default 41 | ExporterAddr string `mapstructure:"exporter_address"` 42 | // JsonAPIConfig specifies configuration of JSON restful API 43 | JsonAPIConfig JsonAPIConfig `mapstructure:"json_api"` 44 | // Worker sync checkpoint path 45 | Checkpoint string `mapstructure:"checkpoint"` 46 | // Config for each repo is represented as an array of RepoConfig. Nested structure is disallowed 47 | Repos []RepoConfig 48 | // A dummy section that will not be used in our program. 49 | Dummy interface{} `mapstructure:"dummy"` 50 | } 51 | 52 | // CfgViper is the instance of config 53 | var CfgViper *viper.Viper 54 | 55 | func init() { 56 | CfgViper = viper.New() 57 | CfgViper.SetDefault("loglevel", 4) 58 | CfgViper.SetDefault("json_api.address", ":7001") 59 | CfgViper.SetDefault("exporter_address", ":8080") 60 | CfgViper.SetDefault("concurrent_limit", 5) 61 | } 62 | 63 | // Parse creates config from a reader 64 | func (c *Config) Parse(in io.Reader) (err error) { 65 | CfgViper.SetConfigType("yaml") 66 | err = CfgViper.ReadConfig(in) 67 | if err != nil { 68 | return err 69 | } 70 | err = CfgViper.UnmarshalExact(&c) 71 | if err == nil { 72 | if c.Interval < 0 { 73 | return errors.New("Interval can't be negative") 74 | } 75 | if c.LogLevel < 0 || c.LogLevel > 5 { 76 | return errors.New("loglevel must be 0-5") 77 | } 78 | if c.ConcurrentLimit <= 0 { 79 | return errors.New("concurrent limit must be positive") 80 | } 81 | } 82 | for _, repo := range c.Repos { 83 | var removeKeys []string 84 | for k, v := range repo { 85 | t := reflect.TypeOf(v) 86 | if t == nil { 87 | continue 88 | } 89 | kind := t.Kind() 90 | var invalidKinds = map[reflect.Kind]bool{ 91 | reflect.Array: true, 92 | reflect.Map: true, 93 | reflect.Slice: true, 94 | reflect.Struct: true, 95 | reflect.Interface: true, 96 | } 97 | if _, ok := invalidKinds[kind]; ok { 98 | removeKeys = append(removeKeys, k) 99 | _, err := fmt.Fprintln(os.Stderr, "nested property(e.g. arrays/maps) in Repos ignored: "+spew.Sdump(v)) 100 | if err != nil { 101 | return err 102 | } 103 | } 104 | } 105 | for _, k := range removeKeys { 106 | delete(repo, k) 107 | } 108 | } 109 | return err 110 | } 111 | -------------------------------------------------------------------------------- /pkg/worker/shell_script_executor.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "os" 9 | "os/exec" 10 | "strings" 11 | 12 | "github.com/davecgh/go-spew/spew" 13 | "github.com/sirupsen/logrus" 14 | "github.com/sjtug/lug/pkg/config" 15 | "mvdan.cc/sh/v3/shell" 16 | ) 17 | 18 | // shellScriptExecutor implements executor interface 19 | type shellScriptExecutor struct { 20 | cfg config.RepoConfig 21 | } 22 | 23 | func newShellScriptExecutor(cfg config.RepoConfig) *shellScriptExecutor { 24 | return &shellScriptExecutor{ 25 | cfg: cfg, 26 | } 27 | } 28 | 29 | func convertMapToEnvVars(m map[string]interface{}) (map[string]string, error) { 30 | result := map[string]string{} 31 | for k, v := range m { 32 | switch v.(type) { 33 | case nil: 34 | // skip 35 | case bool: 36 | if v.(bool) { 37 | result["LUG_"+k] = "1" 38 | } 39 | case int, uint, float32, float64, string: 40 | result["LUG_"+k] = fmt.Sprint(v) 41 | default: 42 | return nil, errors.New("invalid type:" + spew.Sdump(v)) 43 | } 44 | } 45 | marshal, err := json.Marshal(m) 46 | if err != nil { 47 | return nil, err 48 | } 49 | result["LUG_config_json"] = string(marshal) 50 | return result, nil 51 | } 52 | 53 | func getOsEnvsAsMap() (result map[string]string) { 54 | envs := os.Environ() 55 | result = map[string]string{} 56 | for _, e := range envs { 57 | pair := strings.Split(e, "=") 58 | key := pair[0] 59 | val := pair[1] 60 | result[key] = val 61 | } 62 | return 63 | } 64 | 65 | // RunSync launches the worker 66 | func (w *shellScriptExecutor) RunOnce(logger *logrus.Entry, utilities []utility) (execResult, error) { 67 | script, ok := w.cfg["script"] 68 | if !ok { 69 | return execResult{"", ""}, errors.New("script not found in config") 70 | } 71 | 72 | // Split the command string into fields, respecting shell quoting rules 73 | fields, err := shell.Fields(script.(string), func(name string) string { 74 | return getOsEnvsAsMap()[name] 75 | }) 76 | if err != nil { 77 | return execResult{"", ""}, fmt.Errorf("failed to parse command: %w", err) 78 | } 79 | 80 | if len(fields) == 0 { 81 | return execResult{"", ""}, errors.New("empty command") 82 | } 83 | 84 | logger.Debug("Invoking command:", fields[0], "with args:", fields[1:]) 85 | cmd := exec.Command(fields[0], fields[1:]...) 86 | 87 | // Forwarding config items to shell script as environmental variables 88 | // Adds a LUG_ prefix to their key 89 | env := os.Environ() 90 | envvars, err := convertMapToEnvVars(w.cfg) 91 | if err != nil { 92 | return execResult{"", ""}, errors.New(fmt.Sprint("cannot convert w.cfg to env vars: ", err)) 93 | } 94 | for k, v := range envvars { 95 | env = append(env, fmt.Sprintf("%s=%s", k, v)) 96 | } 97 | cmd.Env = env 98 | 99 | for _, utility := range utilities { 100 | logger.WithField("event", "exec_prehook").Debug("Executing prehook of ", utility) 101 | if err := utility.preHook(); err != nil { 102 | logger.Error("Failed to execute preHook:", err) 103 | } 104 | } 105 | 106 | var bufErr, bufOut bytes.Buffer 107 | cmd.Stdout = &bufOut 108 | cmd.Stderr = &bufErr 109 | 110 | err = cmd.Start() 111 | 112 | for _, utility := range utilities { 113 | logger.WithField("event", "exec_posthook").Debug("Executing postHook of ", utility) 114 | if err := utility.postHook(); err != nil { 115 | logger.Error("Failed to execute postHook:", err) 116 | } 117 | } 118 | if err != nil { 119 | return execResult{"", ""}, errors.New("execution cannot start") 120 | } 121 | err = cmd.Wait() 122 | if err != nil { 123 | return execResult{bufOut.String(), bufErr.String()}, errors.New("execution failed") 124 | } 125 | return execResult{bufOut.String(), bufErr.String()}, nil 126 | } 127 | -------------------------------------------------------------------------------- /pkg/config/config_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestParseConfig(t *testing.T) { 11 | const testStr = `interval: 25 12 | loglevel: 5 # 1 - 5 13 | concurrent_limit: 6 14 | repos: 15 | - type: shell_script 16 | script: rsync -av rsync://rsync.chiark.greenend.org.uk/ftp/users/sgtatham/putty-website-mirror/ /tmp/putty 17 | name: putty 18 | path: /mnt/putty 19 | ` 20 | c := Config{} 21 | err := c.Parse(strings.NewReader(testStr)) 22 | 23 | asrt := assert.New(t) 24 | asrt.Nil(err) 25 | asrt.Equal(25, c.Interval) 26 | asrt.Equal(5, int(c.LogLevel)) 27 | asrt.Equal(1, len(c.Repos)) 28 | asrt.Equal(6, c.ConcurrentLimit) 29 | asrt.EqualValues("shell_script", c.Repos[0]["type"]) 30 | asrt.EqualValues("rsync -av rsync://rsync.chiark.greenend.org.uk/ftp/users/sgtatham/putty-website-mirror/ /tmp/putty", c.Repos[0]["script"]) 31 | asrt.EqualValues("/mnt/putty", c.Repos[0]["path"]) 32 | } 33 | 34 | func TestParseRepo(t *testing.T) { 35 | const testStr = `interval: 25 36 | loglevel: 5 37 | repos: 38 | - type: shell_script 39 | number: 2 40 | float: 2.5 41 | nullValue: null 42 | str: string 43 | boolean: false 44 | ` 45 | c := Config{} 46 | err := c.Parse(strings.NewReader(testStr)) 47 | 48 | asrt := assert.New(t) 49 | asrt.Nil(err) 50 | asrt.Equal(1, len(c.Repos)) 51 | asrt.EqualValues(2, c.Repos[0]["number"]) 52 | asrt.EqualValues(2.5, c.Repos[0]["float"]) 53 | asrt.EqualValues(nil, c.Repos[0]["nullValue"]) 54 | asrt.EqualValues("string", c.Repos[0]["str"]) 55 | asrt.EqualValues(false, c.Repos[0]["boolean"]) 56 | } 57 | 58 | func TestParseYamlAnchor(t *testing.T) { 59 | const testStr = `interval: 25 60 | loglevel: 5 61 | dummy: 62 | common1: &common1 63 | interval: 3600 64 | common2: &common2 65 | retry: 5 66 | repos: 67 | - type: shell_script 68 | <<: *common1 69 | str: string 70 | retry: 3 71 | - type: shell_script 72 | <<: [*common1, *common2] 73 | ` 74 | c := Config{} 75 | err := c.Parse(strings.NewReader(testStr)) 76 | asrt := assert.New(t) 77 | asrt.NoError(err) 78 | asrt.Equal(2, len(c.Repos)) 79 | asrt.EqualValues("shell_script", c.Repos[0]["type"]) 80 | asrt.EqualValues("string", c.Repos[0]["str"]) 81 | asrt.EqualValues(3600, c.Repos[0]["interval"]) 82 | asrt.EqualValues("shell_script", c.Repos[0]["type"]) 83 | asrt.EqualValues(3600, c.Repos[1]["interval"]) 84 | asrt.EqualValues(5, c.Repos[1]["retry"]) 85 | } 86 | 87 | func TestWrongManagerConfig(t *testing.T) { 88 | var testStr = `interval: -1 89 | loglevel: 5 # 1 - 5 90 | repos: 91 | - type: shell_script 92 | script: rsync -av rsync://rsync.chiark.greenend.org.uk/ftp/users/sgtatham/putty-website-mirror/ /tmp/putty 93 | name: putty 94 | path: /mnt/putty 95 | ` 96 | c := Config{} 97 | var err error 98 | err = c.Parse(strings.NewReader(testStr)) 99 | 100 | asrt := assert.New(t) 101 | asrt.Equal("Interval can't be negative", err.Error()) 102 | 103 | testStr = `interval: 25 104 | loglevel: 6 105 | repos: 106 | - type: shell_script 107 | script: rsync -av rsync://rsync.chiark.greenend.org.uk/ftp/users/sgtatham/putty-website-mirror/ /tmp/putty 108 | name: putty 109 | path: /mnt/putty 110 | ` 111 | c = Config{} 112 | err = c.Parse(strings.NewReader(testStr)) 113 | 114 | asrt.Equal("loglevel must be 0-5", err.Error()) 115 | 116 | testStr = `interval: 25 117 | loglevel: 4 118 | concurrent_limit: 0 119 | repos: 120 | - type: shell_script 121 | script: rsync -av rsync://rsync.chiark.greenend.org.uk/ftp/users/sgtatham/putty-website-mirror/ /tmp/putty 122 | name: putty 123 | path: /mnt/putty 124 | ` 125 | c = Config{} 126 | err = c.Parse(strings.NewReader(testStr)) 127 | 128 | asrt.Equal("concurrent limit must be positive", err.Error()) 129 | } 130 | -------------------------------------------------------------------------------- /pkg/exporter/exporter.go: -------------------------------------------------------------------------------- 1 | // Package exporter provides definition of exporter 2 | package exporter 3 | 4 | import ( 5 | "net/http" 6 | "sync" 7 | "time" 8 | 9 | "github.com/prometheus/client_golang/prometheus" 10 | "github.com/prometheus/client_golang/prometheus/promhttp" 11 | log "github.com/sirupsen/logrus" 12 | 13 | "github.com/sjtug/lug/pkg/helper" 14 | ) 15 | 16 | // Exporter exports lug metrics to Prometheus. All operations are thread-safe 17 | type Exporter struct { 18 | successCounter *prometheus.CounterVec 19 | failCounter *prometheus.CounterVec 20 | diskUsage *prometheus.GaugeVec 21 | // stores worker_name -> last time that updates its disk usage 22 | diskUsageLastUpdateTime map[string]time.Time 23 | // guard the exporter 24 | mutex sync.Mutex 25 | } 26 | 27 | var instance *Exporter 28 | 29 | // newExporter creates a new exporter 30 | func newExporter() *Exporter { 31 | newExporter := Exporter{ 32 | successCounter: prometheus.NewCounterVec( 33 | prometheus.CounterOpts{ 34 | Name: "success_sync", 35 | Help: "How many successful synchronizations processed, partitioned by workers.", 36 | }, 37 | []string{"worker"}, 38 | ), 39 | failCounter: prometheus.NewCounterVec( 40 | prometheus.CounterOpts{ 41 | Name: "fail_sync", 42 | Help: "How many failed synchronizations processed, partitioned by workers.", 43 | }, 44 | []string{"worker"}, 45 | ), 46 | diskUsage: prometheus.NewGaugeVec( 47 | prometheus.GaugeOpts{ 48 | Namespace: "lug", 49 | Subsystem: "storage", 50 | Name: "disk_usage", 51 | Help: "Disk usage in bytes, partitioned by workers.", 52 | }, 53 | []string{"worker"}, 54 | ), 55 | diskUsageLastUpdateTime: map[string]time.Time{}, 56 | } 57 | prometheus.MustRegister(newExporter.successCounter) 58 | prometheus.MustRegister(newExporter.failCounter) 59 | prometheus.MustRegister(newExporter.diskUsage) 60 | log.Info("Exporter initialized") 61 | return &newExporter 62 | } 63 | 64 | // GetInstance gets the exporter 65 | func GetInstance() *Exporter { 66 | if instance == nil { 67 | instance = newExporter() 68 | } 69 | return instance 70 | } 71 | 72 | // Expose the registered metrics via HTTP. 73 | func Expose(addr string) { 74 | GetInstance() // ensure init 75 | http.Handle("/metrics", promhttp.Handler()) 76 | log.Info("Metrics exposed at " + addr + "/metrics") 77 | log.Fatal(http.ListenAndServe(addr, nil)) 78 | } 79 | 80 | // SyncSuccess will report a successful synchronization 81 | func (e *Exporter) SyncSuccess(worker string) { 82 | e.mutex.Lock() 83 | defer e.mutex.Unlock() 84 | e.successCounter.With(prometheus.Labels{"worker": worker}).Inc() 85 | e.failCounter.With(prometheus.Labels{"worker": worker}).Add(0) 86 | } 87 | 88 | // SyncFail will report a failed synchronization 89 | func (e *Exporter) SyncFail(worker string) { 90 | e.mutex.Lock() 91 | defer e.mutex.Unlock() 92 | e.failCounter.With(prometheus.Labels{"worker": worker}).Inc() 93 | e.successCounter.With(prometheus.Labels{"worker": worker}).Add(0) 94 | } 95 | 96 | // need at least 1min to rescan disk 97 | const updateDiskUsageThrottle time.Duration = time.Minute 98 | 99 | // UpdateDiskUsage will update the disk usage of a directory. 100 | // This call is asynchronous at rate-limited per worker 101 | func (e *Exporter) UpdateDiskUsage(worker string, path string) { 102 | e.mutex.Lock() 103 | defer e.mutex.Unlock() 104 | lastUpdateTime, found := e.diskUsageLastUpdateTime[worker] 105 | logger := log.WithFields(log.Fields{ 106 | "worker": worker, 107 | "path": path, 108 | }) 109 | logger.WithField("event", "update_disk_usage").Info("Invoke UpdateDiskUsage") 110 | if !found || time.Now().Sub(lastUpdateTime) > updateDiskUsageThrottle { 111 | logger.Debug("background update_disk_usage launched") 112 | // first, we set it to infinity (2037-01-01) 113 | // Note that we cannot use a larger value due to Y2038 problem on *nix 114 | e.diskUsageLastUpdateTime[worker] = time.Date( 115 | 2037, 1, 1, 0, 0, 0, 0, time.Local) 116 | // then, we perform the operation in background 117 | go func() { 118 | size, err := helper.DiskUsage(path) 119 | // the above step is time-consuming, so acquire the lock after it completes 120 | e.mutex.Lock() 121 | defer e.mutex.Unlock() 122 | if err == nil { 123 | e.diskUsage.With(prometheus.Labels{"worker": worker}).Set(float64(size)) 124 | } 125 | // when it finishes, we set it to actual finishing time 126 | e.diskUsageLastUpdateTime[worker] = time.Now() 127 | logger.WithField( 128 | "event", "update_disk_usage_complete").WithField("size", size).Info("Disk usage updated") 129 | }() 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /pkg/worker/executor_invoke_worker.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "errors" 5 | "github.com/davecgh/go-spew/spew" 6 | log "github.com/sirupsen/logrus" 7 | "github.com/sjtug/lug/pkg/config" 8 | "github.com/sjtug/lug/pkg/exporter" 9 | "github.com/sjtug/lug/pkg/helper" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | type executorInvokeWorker struct { 15 | executor executor 16 | idle bool 17 | result bool 18 | retry int 19 | retry_interval time.Duration 20 | lastFinished time.Time 21 | stdout *helper.MaxLengthStringSliceAdaptor 22 | stderr *helper.MaxLengthStringSliceAdaptor 23 | cfg config.RepoConfig 24 | name string 25 | signal chan int 26 | logger *log.Entry 27 | rwmutex sync.RWMutex 28 | } 29 | 30 | // creates a new executorInvokeWorker, which encapsules an executor 31 | // into a Worker and provides functinalities like auto-retry and state 32 | // management 33 | func NewExecutorInvokeWorker(exector executor, status Status, 34 | cfg config.RepoConfig, 35 | signal chan int) (*executorInvokeWorker, error) { 36 | name, ok := cfg["name"].(string) 37 | if !ok { 38 | return nil, errors.New("No name in config") 39 | } 40 | w := &executorInvokeWorker{ 41 | idle: status.Idle, 42 | result: status.Result, 43 | retry: 3, 44 | retry_interval: 3 * time.Second, 45 | lastFinished: status.LastFinished, 46 | stdout: helper.NewMaxLengthSlice(status.Stdout, 20), 47 | stderr: helper.NewMaxLengthSlice(status.Stderr, 20), 48 | cfg: cfg, 49 | signal: signal, 50 | name: name, 51 | logger: log.WithField("worker", name), 52 | executor: exector, 53 | } 54 | if retry_generic, ok := cfg["retry"]; ok { 55 | if retry, ok := retry_generic.(int); ok { 56 | w.retry = retry 57 | } else { 58 | return nil, errors.New("retry should be an integer when present") 59 | } 60 | } 61 | 62 | if retry_interval_generic, ok := cfg["retry_interval"]; ok { 63 | if retry_interval, ok := retry_interval_generic.(int); ok { 64 | w.retry_interval = time.Duration(retry_interval) * time.Second 65 | } else { 66 | return nil, errors.New("retry_interval should be an integer when present") 67 | } 68 | } 69 | w.logger.Info(spew.Sprint(w)) 70 | return w, nil 71 | } 72 | 73 | func (eiw *executorInvokeWorker) TriggerSync() { 74 | eiw.signal <- 1 75 | } 76 | 77 | func (eiw *executorInvokeWorker) GetStatus() Status { 78 | eiw.rwmutex.RLock() 79 | defer eiw.rwmutex.RUnlock() 80 | return Status{ 81 | Idle: eiw.idle, 82 | Result: eiw.result, 83 | LastFinished: eiw.lastFinished, 84 | Stdout: eiw.stdout.GetAll(), 85 | Stderr: eiw.stderr.GetAll(), 86 | } 87 | } 88 | 89 | func (eiw *executorInvokeWorker) GetConfig() config.RepoConfig { 90 | eiw.rwmutex.RLock() 91 | defer eiw.rwmutex.RUnlock() 92 | return eiw.cfg 93 | } 94 | 95 | func (w *executorInvokeWorker) RunSync() { 96 | for { 97 | w.logger.WithField("event", "start_wait_signal").Debug("start waiting for signal") 98 | func() { 99 | w.rwmutex.Lock() 100 | defer w.rwmutex.Unlock() 101 | w.idle = true 102 | }() 103 | <-w.signal 104 | w.logger.WithField("event", "signal_received").Debug("finished waiting for signal") 105 | func() { 106 | w.rwmutex.Lock() 107 | defer w.rwmutex.Unlock() 108 | w.idle = false 109 | }() 110 | w.logger.WithField("event", "start_execution").Info("start execution") 111 | retry_limit := w.retry 112 | var result execResult 113 | var err error 114 | for retry_cnt := 1; retry_cnt <= retry_limit; retry_cnt++ { 115 | w.logger.WithField("event", "invoke_executor").WithField( 116 | "try_cnt", retry_cnt).Debugf("Invoke executor for the %v time", retry_cnt) 117 | utilities := []utility{newRlimit(w)} 118 | result, err = w.executor.RunOnce(w.logger, utilities) 119 | if err == nil { 120 | break 121 | } 122 | w.logger.WithField("event", "invoke_executor_fail").WithField( 123 | "try_cnt", retry_cnt).Infof( 124 | "Failed on the %v-th executor. Error: %v", retry_cnt, err.Error()) 125 | w.logger.Debug("Stderr: ", result.Stderr) 126 | time.Sleep(w.retry_interval) 127 | } 128 | if err != nil { 129 | w.logger.WithField("event", "execution_fail").Error(err.Error()) 130 | exporter.GetInstance().SyncFail(w.name) 131 | func() { 132 | w.rwmutex.Lock() 133 | defer w.rwmutex.Unlock() 134 | w.result = false 135 | w.stdout.Put(result.Stdout) 136 | w.stderr.Put(result.Stderr) 137 | w.logger.Infof("Stderr: %s", result.Stderr) 138 | w.logger.Debugf("Stdout: %s", result.Stdout) 139 | w.idle = true 140 | }() 141 | continue 142 | } 143 | 144 | exporter.GetInstance().SyncSuccess(w.name) 145 | w.logger.WithField("event", "execution_succeed").Info("succeed") 146 | w.logger.Infof("Stderr: %s", result.Stderr) 147 | func() { 148 | w.rwmutex.Lock() 149 | defer w.rwmutex.Unlock() 150 | w.stderr.Put(result.Stderr) 151 | w.logger.Debugf("Stdout: %s", result.Stdout) 152 | w.stdout.Put(result.Stdout) 153 | w.result = true 154 | w.lastFinished = time.Now() 155 | }() 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /pkg/worker/worker_test.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "io" 5 | "os/exec" 6 | "strings" 7 | "testing" 8 | "time" 9 | 10 | "github.com/davecgh/go-spew/spew" 11 | "github.com/spf13/viper" 12 | "github.com/stretchr/testify/assert" 13 | 14 | "errors" 15 | "sync/atomic" 16 | 17 | "github.com/sirupsen/logrus" 18 | "github.com/sjtug/lug/pkg/config" 19 | ) 20 | 21 | func TestNewExternalWorker(t *testing.T) { 22 | asrt := assert.New(t) 23 | c := config.RepoConfig{ 24 | "blahblah": "foobar", 25 | "type": "external", 26 | } 27 | _, err := NewWorker(c, time.Now(), true) 28 | // worker with no name is not allowed 29 | asrt.NotNil(err) 30 | 31 | c["name"] = "test_external" 32 | w, err := NewWorker(c, time.Now(), true) 33 | // config with name and dummy kv pairs should be allowed 34 | asrt.Nil(err) 35 | 36 | status := w.GetStatus() 37 | asrt.True(status.Result) 38 | asrt.True(status.Idle) 39 | asrt.NotNil(status.Stderr) 40 | asrt.NotNil(status.Stdout) 41 | } 42 | 43 | func TestNewShellScriptWorker(t *testing.T) { 44 | var c config.RepoConfig = make(map[string]interface{}) 45 | c["type"] = "shell_script" 46 | c["name"] = "shell" 47 | c["script"] = "script" 48 | 49 | asrt := assert.New(t) 50 | 51 | w, _ := NewWorker(c, time.Now(), true) 52 | 53 | asrt.Equal(true, w.GetStatus().Result) 54 | asrt.Equal("shell_script", w.GetConfig()["type"]) 55 | asrt.Equal("shell", w.GetConfig()["name"]) 56 | asrt.Equal("script", w.GetConfig()["script"]) 57 | 58 | } 59 | 60 | func TestShellScriptWorkerEnvVarsConvert(t *testing.T) { 61 | type TestCase struct { 62 | Str string 63 | Expected map[string]string 64 | ExpectedJSON string 65 | } 66 | testCases := []TestCase{ 67 | { 68 | Str: ` 69 | env1: 2 70 | env2: true 71 | env3: false 72 | env4: null 73 | env5: /tmp/bbc`, 74 | Expected: map[string]string{ 75 | "LUG_env1": "2", 76 | "LUG_env2": "1", 77 | "LUG_env5": "/tmp/bbc", 78 | }, 79 | ExpectedJSON: `{"env1": 2, "env2": true, "env3": false, "env5": "/tmp/bbc"}`, 80 | }, 81 | } 82 | asrt := assert.New(t) 83 | for _, testcase := range testCases { 84 | cfgViper := viper.New() 85 | cfgViper.SetConfigType("yaml") 86 | asrt.Nil(cfgViper.ReadConfig(strings.NewReader(testcase.Str))) 87 | actual_interfaces := map[string]interface{}{} 88 | asrt.Nil(cfgViper.Unmarshal(&actual_interfaces)) 89 | actual, err := convertMapToEnvVars(actual_interfaces) 90 | asrt.Nil(err, spew.Sdump(actual_interfaces)+"\n"+spew.Sdump(cfgViper.AllSettings())) 91 | asrt.Contains(actual, "LUG_config_json") 92 | actual_json := actual["LUG_config_json"] 93 | delete(actual, "LUG_config_json") 94 | asrt.Equal(testcase.Expected, actual) 95 | asrt.JSONEq(testcase.ExpectedJSON, actual_json) 96 | } 97 | } 98 | 99 | type dummyExecutor struct { 100 | RunCnt int32 101 | } 102 | 103 | func (d *dummyExecutor) RunOnce(logger *logrus.Entry, utilities []utility) (execResult, error) { 104 | atomic.AddInt32(&d.RunCnt, 1) 105 | return execResult{"", ""}, errors.New("dummy error") 106 | } 107 | 108 | func TestExecutorInvokeWorker(t *testing.T) { 109 | asrt := assert.New(t) 110 | d := &dummyExecutor{} 111 | cfg := config.RepoConfig{ 112 | "interval": 100, 113 | "retry": 2, 114 | "retry_interval": 1, 115 | "name": "dummy", 116 | } 117 | logrus.SetLevel(logrus.DebugLevel) 118 | control := make(chan int, 1) 119 | w, err := NewExecutorInvokeWorker(d, Status{ 120 | Idle: true, 121 | Result: true, 122 | LastFinished: time.Now().AddDate(-1, -1, -1), 123 | }, cfg, control) 124 | asrt.Nil(err) 125 | go w.RunSync() 126 | w.TriggerSync() 127 | time.Sleep(time.Millisecond * 100) 128 | // should be retrying... 129 | status1 := w.GetStatus() 130 | asrt.False(status1.Idle) 131 | asrt.Equal(1, int(atomic.LoadInt32(&d.RunCnt))) 132 | time.Sleep(time.Second * 2) 133 | // should abort.. 134 | status2 := w.GetStatus() 135 | asrt.True(status2.Idle) 136 | asrt.False(status2.Result) 137 | asrt.Equal(2, int(atomic.LoadInt32(&d.RunCnt))) 138 | } 139 | 140 | type limitReader struct { 141 | cnt int 142 | limit int 143 | } 144 | 145 | func newLimitReader(limit int) *limitReader { 146 | return &limitReader{ 147 | cnt: 0, 148 | limit: limit, 149 | } 150 | } 151 | func (i *limitReader) Read(p []byte) (int, error) { 152 | if i.cnt > i.limit { 153 | return 0, io.EOF 154 | } 155 | i.cnt += len(p) 156 | for i := 0; i < len(p); i++ { 157 | p[i] = 5 // shouldn't use zero here, because sometimes pages filled with zero are not allocated 158 | } 159 | return len(p), nil 160 | } 161 | 162 | func TestUtilityRlimit(t *testing.T) { 163 | asrt := assert.New(t) 164 | external_worker, ok := NewExternalWorker(config.RepoConfig{ 165 | "name": "test_worker", 166 | "rlimit_mem": "10M", 167 | }) 168 | asrt.Nil(ok) 169 | 170 | rlimitUtility := newRlimit(external_worker) 171 | 172 | cmd := exec.Command("rev") 173 | cmd.Stdin = newLimitReader(20000000) // > 10M = 10485760 174 | rlimitUtility.preHook() 175 | err1 := cmd.Start() 176 | rlimitUtility.postHook() 177 | var err2 error 178 | if err1 == nil { 179 | err2 = cmd.Wait() 180 | } 181 | asrt.True(err1 != nil || err2 != nil) 182 | } 183 | 184 | func TestShellScriptWorkerArgParse(t *testing.T) { 185 | c := map[string]interface{}{ 186 | "type": "shell_script", 187 | "name": "shell", 188 | "script": "wc -l /proc/stat", 189 | } 190 | w, err := NewWorker(c, time.Now(), true) 191 | 192 | asrt := assert.New(t) 193 | asrt.Nil(err) 194 | 195 | go w.RunSync() 196 | // workarounds 197 | time.Sleep(time.Millisecond * 500) 198 | w.TriggerSync() 199 | time.Sleep(time.Millisecond * 500) 200 | for !w.GetStatus().Idle { 201 | time.Sleep(time.Millisecond * 500) 202 | } 203 | asrt.True(w.GetStatus().Idle) 204 | asrt.True(w.GetStatus().Result) 205 | } 206 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/ant0ine/go-json-rest v3.3.2+incompatible h1:nBixrkLFiDNAW0hauKDLc8yJI6XfrQumWvytE1Hk14E= 2 | github.com/ant0ine/go-json-rest v3.3.2+incompatible/go.mod h1:q6aCt0GfU6LhpBsnZ/2U+mwe+0XB5WStbmwyoPfc+sk= 3 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 4 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 5 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 6 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 7 | github.com/cheshir/logrustash v0.0.0-20230213210745-aca6961b250d h1:d/UzZmpXS1dZvb90oSdCT8BnbGlbzo6+9JM44zJyzyc= 8 | github.com/cheshir/logrustash v0.0.0-20230213210745-aca6961b250d/go.mod h1:J+idqV/m19ccuMARuOeEJ9KeZS0Vdrwqv3gNx195CBg= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 13 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 14 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 15 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 16 | github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= 17 | github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 18 | github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 19 | github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 20 | github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= 21 | github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 22 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 23 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 24 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 25 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 26 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 27 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 28 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 29 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 30 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 31 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 32 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 33 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 34 | github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= 35 | github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 36 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 37 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 38 | github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= 39 | github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= 40 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= 41 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= 42 | github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= 43 | github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= 44 | github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= 45 | github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= 46 | github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 47 | github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 48 | github.com/sagikazarmark/locafero v0.8.0 h1:mXaMVw7IqxNBxfv3LdWt9MDmcWDQ1fagDH918lOdVaQ= 49 | github.com/sagikazarmark/locafero v0.8.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= 50 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 51 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 52 | github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= 53 | github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= 54 | github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= 55 | github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= 56 | github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= 57 | github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 58 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= 59 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 60 | github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY= 61 | github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= 62 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 63 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 64 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 65 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 66 | github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= 67 | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 68 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 69 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 70 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 71 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= 72 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 73 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= 74 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 75 | google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= 76 | google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 77 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 78 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 79 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 80 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 81 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 82 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 83 | mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw= 84 | mvdan.cc/sh/v3 v3.11.0/go.mod h1:LRM+1NjoYCzuq/WZ6y44x14YNAI0NK7FLPeQSaFagGg= 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /pkg/manager/manager.go: -------------------------------------------------------------------------------- 1 | // Package manager provides definition of manager 2 | package manager 3 | 4 | import ( 5 | "encoding/json" 6 | "fmt" 7 | "github.com/davecgh/go-spew/spew" 8 | "io" 9 | "os" 10 | "time" 11 | 12 | "github.com/sirupsen/logrus" 13 | 14 | "github.com/sjtug/lug/pkg/config" 15 | "github.com/sjtug/lug/pkg/worker" 16 | ) 17 | 18 | const ( 19 | // SigStart is a signal sent to control channel of manager which starts sync of all container 20 | SigStart = iota 21 | // SigStop is a signal sent to control channel of manager which stops sync of all container 22 | SigStop 23 | // SigExit is a signal sent to control channel of manager which exits manager run loop 24 | SigExit 25 | // ExitFinish is a signal from finish channel of manager indicating exit finished 26 | ExitFinish 27 | // StopFinish is a signal from finish channel of manager indicating stopping job finished 28 | StopFinish 29 | // StartFinish is a signal from finish channel of manager indicating starting job finished 30 | StartFinish 31 | ) 32 | 33 | // Manager holds worker instances 34 | type Manager struct { 35 | config *config.Config 36 | workers []worker.Worker 37 | workersLastInvokeTime map[string]time.Time 38 | controlChan chan int 39 | finishChan chan int 40 | running bool 41 | // storing index of worker to launch 42 | pendingQueue []int 43 | logger *logrus.Entry 44 | } 45 | 46 | // Status holds the status of a manager and its workers 47 | // WorkerStatus: key = worker's name, value = worker's status 48 | type Status struct { 49 | Running bool 50 | WorkerStatus map[string]worker.Status 51 | } 52 | 53 | type WorkerCheckPoint struct { 54 | LastInvokeTime time.Time `json:"last_invoke_time"` 55 | LastFinished *time.Time `json:"last_finished,omitempty"` 56 | Result *bool `json:"result,omitempty"` 57 | } 58 | 59 | type CheckPoint struct { 60 | WorkerInfo map[string]WorkerCheckPoint `json:"worker_info"` 61 | } 62 | 63 | // fromCheckpoint laods last invoke time from json 64 | func fromCheckpoint(checkpointFile string) (*CheckPoint, error) { 65 | jsonFile, err := os.Open(checkpointFile) 66 | if err != nil { 67 | return nil, err 68 | } 69 | defer func() { _ = jsonFile.Close() }() 70 | 71 | data, err := io.ReadAll(jsonFile) 72 | if err != nil { 73 | return nil, err 74 | } 75 | 76 | var checkpoint CheckPoint 77 | 78 | err = json.Unmarshal(data, &checkpoint) 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | return &checkpoint, nil 84 | } 85 | 86 | func workerFromCheckpoint(repoConfig config.RepoConfig, checkpoint *CheckPoint, name string, lastInvokeTime time.Time) (worker.Worker, error) { 87 | if checkpoint == nil { 88 | return worker.NewWorker(repoConfig, lastInvokeTime, true) 89 | } 90 | info, ok := checkpoint.WorkerInfo[name] 91 | if !ok { 92 | return worker.NewWorker(repoConfig, lastInvokeTime, true) 93 | } 94 | 95 | result := true 96 | if info.Result != nil { 97 | result = *info.Result 98 | } 99 | lastFinished := lastInvokeTime 100 | if info.LastFinished != nil { 101 | lastFinished = *info.LastFinished 102 | } 103 | return worker.NewWorker(repoConfig, lastFinished, result) 104 | } 105 | 106 | // NewManager creates a new manager with attached workers from config 107 | func NewManager(config *config.Config) (*Manager, error) { 108 | logger := logrus.WithField("manager", "") 109 | checkpoint, err := fromCheckpoint(config.Checkpoint) 110 | workersLastInvokeTime := make(map[string]time.Time) 111 | if err != nil { 112 | logger.Info("failed to parse checkpoint file") 113 | } else { 114 | for name, info := range checkpoint.WorkerInfo { 115 | workersLastInvokeTime[name] = info.LastInvokeTime 116 | } 117 | } 118 | newManager := Manager{ 119 | config: config, 120 | workers: []worker.Worker{}, 121 | workersLastInvokeTime: workersLastInvokeTime, 122 | controlChan: make(chan int), 123 | finishChan: make(chan int), 124 | running: true, 125 | logger: logger, 126 | } 127 | for _, repoConfig := range config.Repos { 128 | if disabled, ok := repoConfig["disabled"].(bool); ok && disabled { 129 | continue 130 | } 131 | name, _ := repoConfig["name"].(string) 132 | if _, ok := newManager.workersLastInvokeTime[name]; !ok { 133 | newManager.workersLastInvokeTime[name] = time.Now().AddDate(-1, 0, 0) 134 | } 135 | w, err := workerFromCheckpoint(repoConfig, checkpoint, name, newManager.workersLastInvokeTime[name]) 136 | if err != nil { 137 | return nil, err 138 | } 139 | newManager.workers = append(newManager.workers, w) 140 | } 141 | return &newManager, nil 142 | } 143 | 144 | func (m *Manager) checkpoint() error { 145 | ckptObj := &CheckPoint{WorkerInfo: make(map[string]WorkerCheckPoint)} 146 | for _, w := range m.workers { 147 | name := w.GetConfig()["name"].(string) 148 | status := w.GetStatus() 149 | lastInvokeTime, ok := m.workersLastInvokeTime[name] 150 | if !ok { 151 | lastInvokeTime = time.Now().AddDate(-1, 0, 0) 152 | } 153 | 154 | ckptObj.WorkerInfo[name] = WorkerCheckPoint{ 155 | LastInvokeTime: lastInvokeTime, 156 | Result: &status.Result, 157 | LastFinished: &status.LastFinished, 158 | } 159 | } 160 | 161 | file, err := json.MarshalIndent(ckptObj, "", " ") 162 | if err != nil { 163 | return err 164 | } 165 | ckpt := fmt.Sprintf("%s.tmp", m.config.Checkpoint) 166 | err = os.WriteFile(ckpt, file, 0644) 167 | if err != nil { 168 | return err 169 | } 170 | err = os.Rename(ckpt, m.config.Checkpoint) 171 | if err != nil { 172 | return err 173 | } 174 | return nil 175 | } 176 | 177 | func (m *Manager) isAlreadyInPendingQueue(workerIdx int) bool { 178 | for _, wk := range m.pendingQueue { 179 | if wk == workerIdx { 180 | return true 181 | } 182 | } 183 | return false 184 | } 185 | 186 | func (m *Manager) launchWorkerFromPendingQueue(max_allowed int) { 187 | if max_allowed <= 0 { 188 | return 189 | } 190 | var new_idx int 191 | if max_allowed > len(m.pendingQueue) { 192 | new_idx = len(m.pendingQueue) 193 | } else { 194 | new_idx = max_allowed 195 | } 196 | m.logger.WithFields(logrus.Fields{ 197 | "event": "launch_worker_from_pending_queue", 198 | "max_allowed": max_allowed, 199 | "new_idx": new_idx, 200 | "pending_queue": spew.Sprint(m.pendingQueue), 201 | }).Debug("launch worker from pending queue") 202 | to_launch := m.pendingQueue[:new_idx] 203 | m.pendingQueue = m.pendingQueue[new_idx:] 204 | 205 | for _, w_idx := range to_launch { 206 | w := m.workers[w_idx] 207 | wConfig := w.GetConfig() 208 | m.logger.WithFields(logrus.Fields{ 209 | "event": "trigger_sync", 210 | "target_worker_name": wConfig["name"], 211 | }).Infof("trigger sync for worker %s from pendingQueue", wConfig["name"]) 212 | m.workersLastInvokeTime[wConfig["name"].(string)] = time.Now() 213 | w.TriggerSync() 214 | } 215 | } 216 | 217 | // Run will block current routine 218 | func (m *Manager) Run() { 219 | m.logger.Debugf("%p", m) 220 | c := time.Tick(time.Duration(m.config.Interval) * time.Second) 221 | for _, w := range m.workers { 222 | m.logger.WithFields(logrus.Fields{ 223 | "event": "call_runsync", 224 | "target_worker": w.GetConfig()["name"], 225 | }).Debugf("Calling RunSync() to w %s", w.GetConfig()["name"]) 226 | go w.RunSync() 227 | } 228 | err := m.checkpoint() 229 | if err != nil { 230 | m.logger.WithFields(logrus.Fields{ 231 | "event": "checkpoint_failed", 232 | "error": err, 233 | }).Error("Failed to checkpoint") 234 | } 235 | for { 236 | // wait until config.Interval seconds has elapsed 237 | select { 238 | case <-c: 239 | if m.running { 240 | m.logger.WithField("event", "poll_start").Info("Start polling workers") 241 | running_worker_cnt := 0 242 | shouldCheckpoint := false 243 | for i, w := range m.workers { 244 | wStatus := w.GetStatus() 245 | m.logger.WithFields(logrus.Fields{ 246 | "event": "worker_status", 247 | "target_worker_idx": i, 248 | "target_worker_idle": wStatus.Idle, 249 | "target_worker_result": wStatus.Result, 250 | "target_worker_last_finished": wStatus.LastFinished, 251 | }) 252 | if !wStatus.Idle { 253 | running_worker_cnt++ 254 | continue 255 | } 256 | wConfig := w.GetConfig() 257 | elapsed := time.Since(m.workersLastInvokeTime[wConfig["name"].(string)]) 258 | sec2sync, ok := wConfig["interval"].(int) 259 | if !ok { 260 | sec2sync = 31536000 // if "interval" is not specified, then worker will launch once a year 261 | } 262 | if !m.isAlreadyInPendingQueue(i) && elapsed > time.Duration(sec2sync)*time.Second { 263 | m.logger.WithFields(logrus.Fields{ 264 | "event": "trigger_pending", 265 | "target_worker_name": wConfig["name"], 266 | "target_worker_interval": sec2sync, 267 | }).Infof("Interval of w %s (%d sec) elapsed, send it to pendingQueue", wConfig["name"], sec2sync) 268 | m.pendingQueue = append(m.pendingQueue, i) 269 | shouldCheckpoint = true 270 | } 271 | } 272 | m.launchWorkerFromPendingQueue(m.config.ConcurrentLimit - running_worker_cnt) 273 | m.logger.WithField("event", "poll_end").Info("Stop polling workers") 274 | 275 | // Here we do not checkpoint very concisely (e.g. every time after a successful sync). 276 | // We just want to minimize re-sync after restarting lug. 277 | if shouldCheckpoint { 278 | err := m.checkpoint() 279 | if err != nil { 280 | m.logger.WithFields(logrus.Fields{ 281 | "event": "checkpoint_failed", 282 | "error": err, 283 | }).Error("Failed to checkpoint") 284 | } 285 | } 286 | } 287 | case sig, ok := <-m.controlChan: 288 | if ok { 289 | switch sig { 290 | default: 291 | m.logger.WithField("event", "unrecognized_control_signal"). 292 | Warningf("Unrecognized Control Signal: %d", sig) 293 | case SigStart: 294 | m.running = true 295 | m.finishChan <- StartFinish 296 | case SigStop: 297 | m.running = false 298 | m.finishChan <- StopFinish 299 | case SigExit: 300 | m.logger.WithField("event", "exit_control_signal").Info("Exiting...") 301 | goto END_OF_FINISH 302 | } 303 | } else { 304 | m.logger.WithField("event", "control_channel_closed").Fatal("Control channel is closed!") 305 | } 306 | } 307 | } 308 | END_OF_FINISH: 309 | m.logger.WithField("event", "send_exit_finish").Debug("Sending ExitFinish...") 310 | m.finishChan <- ExitFinish 311 | m.logger.WithField("event", "senf_exit_finish_end").Debug("Finished sending ExitFinish...") 312 | } 313 | 314 | func (m *Manager) expectChanVal(ch chan int, expected int) { 315 | exitMsg, ok := <-ch 316 | if ok { 317 | switch exitMsg { 318 | default: 319 | m.logger.WithFields(logrus.Fields{ 320 | "event": "unexpected_control_message", 321 | "expected_msg": expected, 322 | "received_msg": exitMsg, 323 | }).Fatalf("Unrecognized Msg: %d, expected %d", exitMsg, expected) 324 | case expected: 325 | m.logger.WithFields(logrus.Fields{ 326 | "event": "finish_receive_control_message", 327 | "expected_msg": expected, 328 | "received_msg": expected, 329 | }).Infof("Finished reading %d", expected) 330 | } 331 | } else { 332 | m.logger.WithField("event", "control_channel_closed").Fatalf("Channel has been closed, expected %d", expected) 333 | } 334 | } 335 | 336 | // Start polling, block until finish(may take several seconds) 337 | func (m *Manager) Start() { 338 | m.controlChan <- SigStart 339 | m.expectChanVal(m.finishChan, StartFinish) 340 | } 341 | 342 | // Stop polling, block until finish(may take several seconds) 343 | func (m *Manager) Stop() { 344 | m.controlChan <- SigStop 345 | m.expectChanVal(m.finishChan, StopFinish) 346 | } 347 | 348 | // Exit polling, block until finish(may take several seconds) 349 | func (m *Manager) Exit() { 350 | m.Stop() 351 | m.controlChan <- SigExit 352 | m.expectChanVal(m.finishChan, ExitFinish) 353 | } 354 | 355 | // GetStatus gets status of Manager 356 | func (m *Manager) GetStatus() *Status { 357 | status := Status{ 358 | Running: m.running, 359 | WorkerStatus: make(map[string]worker.Status), 360 | } 361 | for _, w := range m.workers { 362 | wConfig := w.GetConfig() 363 | wStatus := w.GetStatus() 364 | if hidden, ok := wConfig["hidden"].(bool); !(ok && hidden) { 365 | status.WorkerStatus[wConfig["name"].(string)] = wStatus 366 | } 367 | } 368 | return &status 369 | } 370 | -------------------------------------------------------------------------------- /cli/lug/license.go: -------------------------------------------------------------------------------- 1 | package main 2 | /* Generated by script scripts/gen_license.sh */ 3 | const licenseText = ` ==> ./vendor/gopkg.in/yaml.v3/LICENSE <== 4 | 5 | This project is covered by two different licenses: MIT and Apache. 6 | 7 | #### MIT License #### 8 | 9 | The following files were ported to Go from C files of libyaml, and thus 10 | are still covered by their original MIT license, with the additional 11 | copyright staring in 2011 when the project was ported over: 12 | 13 | apic.go emitterc.go parserc.go readerc.go scannerc.go 14 | writerc.go yamlh.go yamlprivateh.go 15 | 16 | Copyright (c) 2006-2010 Kirill Simonov 17 | Copyright (c) 2006-2011 Kirill Simonov 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of 20 | this software and associated documentation files (the "Software"), to deal in 21 | the Software without restriction, including without limitation the rights to 22 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 23 | of the Software, and to permit persons to whom the Software is furnished to do 24 | so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in all 27 | copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. 36 | 37 | ### Apache License ### 38 | 39 | All the remaining project files are covered by the Apache license: 40 | 41 | Copyright (c) 2011-2019 Canonical Ltd 42 | 43 | Licensed under the Apache License, Version 2.0 (the "License"); 44 | you may not use this file except in compliance with the License. 45 | You may obtain a copy of the License at 46 | 47 | http://www.apache.org/licenses/LICENSE-2.0 48 | 49 | Unless required by applicable law or agreed to in writing, software 50 | distributed under the License is distributed on an "AS IS" BASIS, 51 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 52 | See the License for the specific language governing permissions and 53 | limitations under the License. 54 | 55 | ==> ./vendor/google.golang.org/protobuf/LICENSE <== 56 | Copyright (c) 2018 The Go Authors. All rights reserved. 57 | 58 | Redistribution and use in source and binary forms, with or without 59 | modification, are permitted provided that the following conditions are 60 | met: 61 | 62 | * Redistributions of source code must retain the above copyright 63 | notice, this list of conditions and the following disclaimer. 64 | * Redistributions in binary form must reproduce the above 65 | copyright notice, this list of conditions and the following disclaimer 66 | in the documentation and/or other materials provided with the 67 | distribution. 68 | * Neither the name of Google Inc. nor the names of its 69 | contributors may be used to endorse or promote products derived from 70 | this software without specific prior written permission. 71 | 72 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 73 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 74 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 75 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 76 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 77 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 78 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 79 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 80 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 81 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 82 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 83 | 84 | ==> ./vendor/mvdan.cc/sh/v3/LICENSE <== 85 | Copyright (c) 2016, Daniel Martí. All rights reserved. 86 | 87 | Redistribution and use in source and binary forms, with or without 88 | modification, are permitted provided that the following conditions are 89 | met: 90 | 91 | * Redistributions of source code must retain the above copyright 92 | notice, this list of conditions and the following disclaimer. 93 | * Redistributions in binary form must reproduce the above 94 | copyright notice, this list of conditions and the following disclaimer 95 | in the documentation and/or other materials provided with the 96 | distribution. 97 | * Neither the name of the copyright holder nor the names of its 98 | contributors may be used to endorse or promote products derived from 99 | this software without specific prior written permission. 100 | 101 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 102 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 103 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 104 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 105 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 106 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 107 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 108 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 109 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 110 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 111 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 112 | 113 | ==> ./vendor/golang.org/x/sys/LICENSE <== 114 | Copyright 2009 The Go Authors. 115 | 116 | Redistribution and use in source and binary forms, with or without 117 | modification, are permitted provided that the following conditions are 118 | met: 119 | 120 | * Redistributions of source code must retain the above copyright 121 | notice, this list of conditions and the following disclaimer. 122 | * Redistributions in binary form must reproduce the above 123 | copyright notice, this list of conditions and the following disclaimer 124 | in the documentation and/or other materials provided with the 125 | distribution. 126 | * Neither the name of Google LLC nor the names of its 127 | contributors may be used to endorse or promote products derived from 128 | this software without specific prior written permission. 129 | 130 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 131 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 132 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 133 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 134 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 135 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 136 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 137 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 138 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 139 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 140 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 141 | 142 | ==> ./vendor/golang.org/x/text/LICENSE <== 143 | Copyright 2009 The Go Authors. 144 | 145 | Redistribution and use in source and binary forms, with or without 146 | modification, are permitted provided that the following conditions are 147 | met: 148 | 149 | * Redistributions of source code must retain the above copyright 150 | notice, this list of conditions and the following disclaimer. 151 | * Redistributions in binary form must reproduce the above 152 | copyright notice, this list of conditions and the following disclaimer 153 | in the documentation and/or other materials provided with the 154 | distribution. 155 | * Neither the name of Google LLC nor the names of its 156 | contributors may be used to endorse or promote products derived from 157 | this software without specific prior written permission. 158 | 159 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 160 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 161 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 162 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 163 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 164 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 165 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 166 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 167 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 168 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 169 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 170 | 171 | ==> ./vendor/github.com/pelletier/go-toml/v2/LICENSE <== 172 | The MIT License (MIT) 173 | 174 | go-toml v2 175 | Copyright (c) 2021 - 2023 Thomas Pelletier 176 | 177 | Permission is hereby granted, free of charge, to any person obtaining a copy 178 | of this software and associated documentation files (the "Software"), to deal 179 | in the Software without restriction, including without limitation the rights 180 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 181 | copies of the Software, and to permit persons to whom the Software is 182 | furnished to do so, subject to the following conditions: 183 | 184 | The above copyright notice and this permission notice shall be included in all 185 | copies or substantial portions of the Software. 186 | 187 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 188 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 189 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 190 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 192 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 193 | SOFTWARE. 194 | 195 | ==> ./vendor/github.com/cheshir/logrustash/LICENSE <== 196 | The MIT License (MIT) 197 | 198 | Copyright (c) 2016 Boaz Shuster 199 | 200 | Permission is hereby granted, free of charge, to any person obtaining a copy 201 | of this software and associated documentation files (the "Software"), to deal 202 | in the Software without restriction, including without limitation the rights 203 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 204 | copies of the Software, and to permit persons to whom the Software is 205 | furnished to do so, subject to the following conditions: 206 | 207 | The above copyright notice and this permission notice shall be included in 208 | all copies or substantial portions of the Software. 209 | 210 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 211 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 212 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 213 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 214 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 215 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 216 | THE SOFTWARE. 217 | ==> ./vendor/github.com/davecgh/go-spew/LICENSE <== 218 | ISC License 219 | 220 | Copyright (c) 2012-2016 Dave Collins 221 | 222 | Permission to use, copy, modify, and/or distribute this software for any 223 | purpose with or without fee is hereby granted, provided that the above 224 | copyright notice and this permission notice appear in all copies. 225 | 226 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 227 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 228 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 229 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 230 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 231 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 232 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 233 | 234 | ==> ./vendor/github.com/klauspost/compress/LICENSE <== 235 | Copyright (c) 2012 The Go Authors. All rights reserved. 236 | Copyright (c) 2019 Klaus Post. All rights reserved. 237 | 238 | Redistribution and use in source and binary forms, with or without 239 | modification, are permitted provided that the following conditions are 240 | met: 241 | 242 | * Redistributions of source code must retain the above copyright 243 | notice, this list of conditions and the following disclaimer. 244 | * Redistributions in binary form must reproduce the above 245 | copyright notice, this list of conditions and the following disclaimer 246 | in the documentation and/or other materials provided with the 247 | distribution. 248 | * Neither the name of Google Inc. nor the names of its 249 | contributors may be used to endorse or promote products derived from 250 | this software without specific prior written permission. 251 | 252 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 253 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 254 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 255 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 256 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 257 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 258 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 259 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 260 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 261 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 263 | 264 | ------------------ 265 | 266 | Files: gzhttp/* 267 | 268 | Apache License 269 | Version 2.0, January 2004 270 | http://www.apache.org/licenses/ 271 | 272 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 273 | 274 | 1. Definitions. 275 | 276 | "License" shall mean the terms and conditions for use, reproduction, 277 | and distribution as defined by Sections 1 through 9 of this document. 278 | 279 | "Licensor" shall mean the copyright owner or entity authorized by 280 | the copyright owner that is granting the License. 281 | 282 | "Legal Entity" shall mean the union of the acting entity and all 283 | other entities that control, are controlled by, or are under common 284 | control with that entity. For the purposes of this definition, 285 | "control" means (i) the power, direct or indirect, to cause the 286 | direction or management of such entity, whether by contract or 287 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 288 | outstanding shares, or (iii) beneficial ownership of such entity. 289 | 290 | "You" (or "Your") shall mean an individual or Legal Entity 291 | exercising permissions granted by this License. 292 | 293 | "Source" form shall mean the preferred form for making modifications, 294 | including but not limited to software source code, documentation 295 | source, and configuration files. 296 | 297 | "Object" form shall mean any form resulting from mechanical 298 | transformation or translation of a Source form, including but 299 | not limited to compiled object code, generated documentation, 300 | and conversions to other media types. 301 | 302 | "Work" shall mean the work of authorship, whether in Source or 303 | Object form, made available under the License, as indicated by a 304 | copyright notice that is included in or attached to the work 305 | (an example is provided in the Appendix below). 306 | 307 | "Derivative Works" shall mean any work, whether in Source or Object 308 | form, that is based on (or derived from) the Work and for which the 309 | editorial revisions, annotations, elaborations, or other modifications 310 | represent, as a whole, an original work of authorship. For the purposes 311 | of this License, Derivative Works shall not include works that remain 312 | separable from, or merely link (or bind by name) to the interfaces of, 313 | the Work and Derivative Works thereof. 314 | 315 | "Contribution" shall mean any work of authorship, including 316 | the original version of the Work and any modifications or additions 317 | to that Work or Derivative Works thereof, that is intentionally 318 | submitted to Licensor for inclusion in the Work by the copyright owner 319 | or by an individual or Legal Entity authorized to submit on behalf of 320 | the copyright owner. For the purposes of this definition, "submitted" 321 | means any form of electronic, verbal, or written communication sent 322 | to the Licensor or its representatives, including but not limited to 323 | communication on electronic mailing lists, source code control systems, 324 | and issue tracking systems that are managed by, or on behalf of, the 325 | Licensor for the purpose of discussing and improving the Work, but 326 | excluding communication that is conspicuously marked or otherwise 327 | designated in writing by the copyright owner as "Not a Contribution." 328 | 329 | "Contributor" shall mean Licensor and any individual or Legal Entity 330 | on behalf of whom a Contribution has been received by Licensor and 331 | subsequently incorporated within the Work. 332 | 333 | 2. Grant of Copyright License. Subject to the terms and conditions of 334 | this License, each Contributor hereby grants to You a perpetual, 335 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 336 | copyright license to reproduce, prepare Derivative Works of, 337 | publicly display, publicly perform, sublicense, and distribute the 338 | Work and such Derivative Works in Source or Object form. 339 | 340 | 3. Grant of Patent License. Subject to the terms and conditions of 341 | this License, each Contributor hereby grants to You a perpetual, 342 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 343 | (except as stated in this section) patent license to make, have made, 344 | use, offer to sell, sell, import, and otherwise transfer the Work, 345 | where such license applies only to those patent claims licensable 346 | by such Contributor that are necessarily infringed by their 347 | Contribution(s) alone or by combination of their Contribution(s) 348 | with the Work to which such Contribution(s) was submitted. If You 349 | institute patent litigation against any entity (including a 350 | cross-claim or counterclaim in a lawsuit) alleging that the Work 351 | or a Contribution incorporated within the Work constitutes direct 352 | or contributory patent infringement, then any patent licenses 353 | granted to You under this License for that Work shall terminate 354 | as of the date such litigation is filed. 355 | 356 | 4. Redistribution. You may reproduce and distribute copies of the 357 | Work or Derivative Works thereof in any medium, with or without 358 | modifications, and in Source or Object form, provided that You 359 | meet the following conditions: 360 | 361 | (a) You must give any other recipients of the Work or 362 | Derivative Works a copy of this License; and 363 | 364 | (b) You must cause any modified files to carry prominent notices 365 | stating that You changed the files; and 366 | 367 | (c) You must retain, in the Source form of any Derivative Works 368 | that You distribute, all copyright, patent, trademark, and 369 | attribution notices from the Source form of the Work, 370 | excluding those notices that do not pertain to any part of 371 | the Derivative Works; and 372 | 373 | (d) If the Work includes a "NOTICE" text file as part of its 374 | distribution, then any Derivative Works that You distribute must 375 | include a readable copy of the attribution notices contained 376 | within such NOTICE file, excluding those notices that do not 377 | pertain to any part of the Derivative Works, in at least one 378 | of the following places: within a NOTICE text file distributed 379 | as part of the Derivative Works; within the Source form or 380 | documentation, if provided along with the Derivative Works; or, 381 | within a display generated by the Derivative Works, if and 382 | wherever such third-party notices normally appear. The contents 383 | of the NOTICE file are for informational purposes only and 384 | do not modify the License. You may add Your own attribution 385 | notices within Derivative Works that You distribute, alongside 386 | or as an addendum to the NOTICE text from the Work, provided 387 | that such additional attribution notices cannot be construed 388 | as modifying the License. 389 | 390 | You may add Your own copyright statement to Your modifications and 391 | may provide additional or different license terms and conditions 392 | for use, reproduction, or distribution of Your modifications, or 393 | for any such Derivative Works as a whole, provided Your use, 394 | reproduction, and distribution of the Work otherwise complies with 395 | the conditions stated in this License. 396 | 397 | 5. Submission of Contributions. Unless You explicitly state otherwise, 398 | any Contribution intentionally submitted for inclusion in the Work 399 | by You to the Licensor shall be under the terms and conditions of 400 | this License, without any additional terms or conditions. 401 | Notwithstanding the above, nothing herein shall supersede or modify 402 | the terms of any separate license agreement you may have executed 403 | with Licensor regarding such Contributions. 404 | 405 | 6. Trademarks. This License does not grant permission to use the trade 406 | names, trademarks, service marks, or product names of the Licensor, 407 | except as required for reasonable and customary use in describing the 408 | origin of the Work and reproducing the content of the NOTICE file. 409 | 410 | 7. Disclaimer of Warranty. Unless required by applicable law or 411 | agreed to in writing, Licensor provides the Work (and each 412 | Contributor provides its Contributions) on an "AS IS" BASIS, 413 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 414 | implied, including, without limitation, any warranties or conditions 415 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 416 | PARTICULAR PURPOSE. You are solely responsible for determining the 417 | appropriateness of using or redistributing the Work and assume any 418 | risks associated with Your exercise of permissions under this License. 419 | 420 | 8. Limitation of Liability. In no event and under no legal theory, 421 | whether in tort (including negligence), contract, or otherwise, 422 | unless required by applicable law (such as deliberate and grossly 423 | negligent acts) or agreed to in writing, shall any Contributor be 424 | liable to You for damages, including any direct, indirect, special, 425 | incidental, or consequential damages of any character arising as a 426 | result of this License or out of the use or inability to use the 427 | Work (including but not limited to damages for loss of goodwill, 428 | work stoppage, computer failure or malfunction, or any and all 429 | other commercial damages or losses), even if such Contributor 430 | has been advised of the possibility of such damages. 431 | 432 | 9. Accepting Warranty or Additional Liability. While redistributing 433 | the Work or Derivative Works thereof, You may choose to offer, 434 | and charge a fee for, acceptance of support, warranty, indemnity, 435 | or other liability obligations and/or rights consistent with this 436 | License. However, in accepting such obligations, You may act only 437 | on Your own behalf and on Your sole responsibility, not on behalf 438 | of any other Contributor, and only if You agree to indemnify, 439 | defend, and hold each Contributor harmless for any liability 440 | incurred by, or claims asserted against, such Contributor by reason 441 | of your accepting any such warranty or additional liability. 442 | 443 | END OF TERMS AND CONDITIONS 444 | 445 | APPENDIX: How to apply the Apache License to your work. 446 | 447 | To apply the Apache License to your work, attach the following 448 | boilerplate notice, with the fields enclosed by brackets "[]" 449 | replaced with your own identifying information. (Don't include 450 | the brackets!) The text should be enclosed in the appropriate 451 | comment syntax for the file format. We also recommend that a 452 | file or class name and description of purpose be included on the 453 | same "printed page" as the copyright notice for easier 454 | identification within third-party archives. 455 | 456 | Copyright 2016-2017 The New York Times Company 457 | 458 | Licensed under the Apache License, Version 2.0 (the "License"); 459 | you may not use this file except in compliance with the License. 460 | You may obtain a copy of the License at 461 | 462 | http://www.apache.org/licenses/LICENSE-2.0 463 | 464 | Unless required by applicable law or agreed to in writing, software 465 | distributed under the License is distributed on an "AS IS" BASIS, 466 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 467 | See the License for the specific language governing permissions and 468 | limitations under the License. 469 | 470 | ------------------ 471 | 472 | Files: s2/cmd/internal/readahead/* 473 | 474 | The MIT License (MIT) 475 | 476 | Copyright (c) 2015 Klaus Post 477 | 478 | Permission is hereby granted, free of charge, to any person obtaining a copy 479 | of this software and associated documentation files (the "Software"), to deal 480 | in the Software without restriction, including without limitation the rights 481 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 482 | copies of the Software, and to permit persons to whom the Software is 483 | furnished to do so, subject to the following conditions: 484 | 485 | The above copyright notice and this permission notice shall be included in all 486 | copies or substantial portions of the Software. 487 | 488 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 489 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 490 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 491 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 492 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 493 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 494 | SOFTWARE. 495 | 496 | --------------------- 497 | Files: snappy/* 498 | Files: internal/snapref/* 499 | 500 | Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. 501 | 502 | Redistribution and use in source and binary forms, with or without 503 | modification, are permitted provided that the following conditions are 504 | met: 505 | 506 | * Redistributions of source code must retain the above copyright 507 | notice, this list of conditions and the following disclaimer. 508 | * Redistributions in binary form must reproduce the above 509 | copyright notice, this list of conditions and the following disclaimer 510 | in the documentation and/or other materials provided with the 511 | distribution. 512 | * Neither the name of Google Inc. nor the names of its 513 | contributors may be used to endorse or promote products derived from 514 | this software without specific prior written permission. 515 | 516 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 517 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 518 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 519 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 520 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 521 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 522 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 523 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 524 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 525 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 526 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 527 | 528 | ----------------- 529 | 530 | Files: s2/cmd/internal/filepathx/* 531 | 532 | Copyright 2016 The filepathx Authors 533 | 534 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 535 | 536 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 537 | 538 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 539 | 540 | ==> ./vendor/github.com/klauspost/compress/internal/snapref/LICENSE <== 541 | Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. 542 | 543 | Redistribution and use in source and binary forms, with or without 544 | modification, are permitted provided that the following conditions are 545 | met: 546 | 547 | * Redistributions of source code must retain the above copyright 548 | notice, this list of conditions and the following disclaimer. 549 | * Redistributions in binary form must reproduce the above 550 | copyright notice, this list of conditions and the following disclaimer 551 | in the documentation and/or other materials provided with the 552 | distribution. 553 | * Neither the name of Google Inc. nor the names of its 554 | contributors may be used to endorse or promote products derived from 555 | this software without specific prior written permission. 556 | 557 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 558 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 559 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 560 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 561 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 562 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 563 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 564 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 565 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 566 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 567 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 568 | 569 | ==> ./vendor/github.com/pmezard/go-difflib/LICENSE <== 570 | Copyright (c) 2013, Patrick Mezard 571 | All rights reserved. 572 | 573 | Redistribution and use in source and binary forms, with or without 574 | modification, are permitted provided that the following conditions are 575 | met: 576 | 577 | Redistributions of source code must retain the above copyright 578 | notice, this list of conditions and the following disclaimer. 579 | Redistributions in binary form must reproduce the above copyright 580 | notice, this list of conditions and the following disclaimer in the 581 | documentation and/or other materials provided with the distribution. 582 | The names of its contributors may not be used to endorse or promote 583 | products derived from this software without specific prior written 584 | permission. 585 | 586 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 587 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 588 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 589 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 590 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 591 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 592 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 593 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 594 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 595 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 596 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 597 | 598 | ==> ./vendor/github.com/fsnotify/fsnotify/LICENSE <== 599 | Copyright © 2012 The Go Authors. All rights reserved. 600 | Copyright © fsnotify Authors. All rights reserved. 601 | 602 | Redistribution and use in source and binary forms, with or without modification, 603 | are permitted provided that the following conditions are met: 604 | 605 | * Redistributions of source code must retain the above copyright notice, this 606 | list of conditions and the following disclaimer. 607 | * Redistributions in binary form must reproduce the above copyright notice, this 608 | list of conditions and the following disclaimer in the documentation and/or 609 | other materials provided with the distribution. 610 | * Neither the name of Google Inc. nor the names of its contributors may be used 611 | to endorse or promote products derived from this software without specific 612 | prior written permission. 613 | 614 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 615 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 616 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 617 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 618 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 619 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 620 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 621 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 622 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 623 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 624 | 625 | ==> ./vendor/github.com/beorn7/perks/LICENSE <== 626 | Copyright (C) 2013 Blake Mizerany 627 | 628 | Permission is hereby granted, free of charge, to any person obtaining 629 | a copy of this software and associated documentation files (the 630 | "Software"), to deal in the Software without restriction, including 631 | without limitation the rights to use, copy, modify, merge, publish, 632 | distribute, sublicense, and/or sell copies of the Software, and to 633 | permit persons to whom the Software is furnished to do so, subject to 634 | the following conditions: 635 | 636 | The above copyright notice and this permission notice shall be 637 | included in all copies or substantial portions of the Software. 638 | 639 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 640 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 641 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 642 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 643 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 644 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 645 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 646 | 647 | ==> ./vendor/github.com/stretchr/testify/LICENSE <== 648 | MIT License 649 | 650 | Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 651 | 652 | Permission is hereby granted, free of charge, to any person obtaining a copy 653 | of this software and associated documentation files (the "Software"), to deal 654 | in the Software without restriction, including without limitation the rights 655 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 656 | copies of the Software, and to permit persons to whom the Software is 657 | furnished to do so, subject to the following conditions: 658 | 659 | The above copyright notice and this permission notice shall be included in all 660 | copies or substantial portions of the Software. 661 | 662 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 663 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 664 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 665 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 666 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 667 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 668 | SOFTWARE. 669 | 670 | ==> ./vendor/github.com/go-viper/mapstructure/v2/LICENSE <== 671 | The MIT License (MIT) 672 | 673 | Copyright (c) 2013 Mitchell Hashimoto 674 | 675 | Permission is hereby granted, free of charge, to any person obtaining a copy 676 | of this software and associated documentation files (the "Software"), to deal 677 | in the Software without restriction, including without limitation the rights 678 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 679 | copies of the Software, and to permit persons to whom the Software is 680 | furnished to do so, subject to the following conditions: 681 | 682 | The above copyright notice and this permission notice shall be included in 683 | all copies or substantial portions of the Software. 684 | 685 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 686 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 687 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 688 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 689 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 690 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 691 | THE SOFTWARE. 692 | 693 | ==> ./vendor/github.com/sourcegraph/conc/LICENSE <== 694 | MIT License 695 | 696 | Copyright (c) 2023 Sourcegraph 697 | 698 | Permission is hereby granted, free of charge, to any person obtaining a copy 699 | of this software and associated documentation files (the "Software"), to deal 700 | in the Software without restriction, including without limitation the rights 701 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 702 | copies of the Software, and to permit persons to whom the Software is 703 | furnished to do so, subject to the following conditions: 704 | 705 | The above copyright notice and this permission notice shall be included in all 706 | copies or substantial portions of the Software. 707 | 708 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 709 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 710 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 711 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 712 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 713 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 714 | SOFTWARE. 715 | 716 | ==> ./vendor/github.com/sirupsen/logrus/LICENSE <== 717 | The MIT License (MIT) 718 | 719 | Copyright (c) 2014 Simon Eskildsen 720 | 721 | Permission is hereby granted, free of charge, to any person obtaining a copy 722 | of this software and associated documentation files (the "Software"), to deal 723 | in the Software without restriction, including without limitation the rights 724 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 725 | copies of the Software, and to permit persons to whom the Software is 726 | furnished to do so, subject to the following conditions: 727 | 728 | The above copyright notice and this permission notice shall be included in 729 | all copies or substantial portions of the Software. 730 | 731 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 732 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 733 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 734 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 735 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 736 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 737 | THE SOFTWARE. 738 | 739 | ==> ./vendor/github.com/spf13/cast/LICENSE <== 740 | The MIT License (MIT) 741 | 742 | Copyright (c) 2014 Steve Francia 743 | 744 | Permission is hereby granted, free of charge, to any person obtaining a copy 745 | of this software and associated documentation files (the "Software"), to deal 746 | in the Software without restriction, including without limitation the rights 747 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 748 | copies of the Software, and to permit persons to whom the Software is 749 | furnished to do so, subject to the following conditions: 750 | 751 | The above copyright notice and this permission notice shall be included in all 752 | copies or substantial portions of the Software. 753 | 754 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 755 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 756 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 757 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 758 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 759 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 760 | SOFTWARE. 761 | ==> ./vendor/github.com/spf13/viper/LICENSE <== 762 | The MIT License (MIT) 763 | 764 | Copyright (c) 2014 Steve Francia 765 | 766 | Permission is hereby granted, free of charge, to any person obtaining a copy 767 | of this software and associated documentation files (the "Software"), to deal 768 | in the Software without restriction, including without limitation the rights 769 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 770 | copies of the Software, and to permit persons to whom the Software is 771 | furnished to do so, subject to the following conditions: 772 | 773 | The above copyright notice and this permission notice shall be included in all 774 | copies or substantial portions of the Software. 775 | 776 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 777 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 778 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 779 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 780 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 781 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 782 | SOFTWARE. 783 | ==> ./vendor/github.com/spf13/pflag/LICENSE <== 784 | Copyright (c) 2012 Alex Ogier. All rights reserved. 785 | Copyright (c) 2012 The Go Authors. All rights reserved. 786 | 787 | Redistribution and use in source and binary forms, with or without 788 | modification, are permitted provided that the following conditions are 789 | met: 790 | 791 | * Redistributions of source code must retain the above copyright 792 | notice, this list of conditions and the following disclaimer. 793 | * Redistributions in binary form must reproduce the above 794 | copyright notice, this list of conditions and the following disclaimer 795 | in the documentation and/or other materials provided with the 796 | distribution. 797 | * Neither the name of Google Inc. nor the names of its 798 | contributors may be used to endorse or promote products derived from 799 | this software without specific prior written permission. 800 | 801 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 802 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 803 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 804 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 805 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 806 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 807 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 808 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 809 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 810 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 811 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 812 | 813 | ==> ./vendor/github.com/dustin/go-humanize/LICENSE <== 814 | Copyright (c) 2005-2008 Dustin Sallings 815 | 816 | Permission is hereby granted, free of charge, to any person obtaining a copy 817 | of this software and associated documentation files (the "Software"), to deal 818 | in the Software without restriction, including without limitation the rights 819 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 820 | copies of the Software, and to permit persons to whom the Software is 821 | furnished to do so, subject to the following conditions: 822 | 823 | The above copyright notice and this permission notice shall be included in 824 | all copies or substantial portions of the Software. 825 | 826 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 827 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 828 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 829 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 830 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 831 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 832 | SOFTWARE. 833 | 834 | 835 | 836 | ==> ./vendor/github.com/sagikazarmark/locafero/LICENSE <== 837 | Copyright (c) 2023 Márk Sági-Kazár 838 | 839 | Permission is hereby granted, free of charge, to any person obtaining a copy 840 | of this software and associated documentation files (the "Software"), to deal 841 | in the Software without restriction, including without limitation the rights 842 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 843 | copies of the Software, and to permit persons to whom the Software is furnished 844 | to do so, subject to the following conditions: 845 | 846 | The above copyright notice and this permission notice shall be included in all 847 | copies or substantial portions of the Software. 848 | 849 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 850 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 851 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 852 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 853 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 854 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 855 | THE SOFTWARE. 856 | 857 | ==> ./vendor/github.com/subosito/gotenv/LICENSE <== 858 | The MIT License (MIT) 859 | 860 | Copyright (c) 2013 Alif Rachmawadi 861 | 862 | Permission is hereby granted, free of charge, to any person obtaining a copy 863 | of this software and associated documentation files (the "Software"), to deal 864 | in the Software without restriction, including without limitation the rights 865 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 866 | copies of the Software, and to permit persons to whom the Software is 867 | furnished to do so, subject to the following conditions: 868 | 869 | The above copyright notice and this permission notice shall be included in 870 | all copies or substantial portions of the Software. 871 | 872 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 873 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 874 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 875 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 876 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 877 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 878 | THE SOFTWARE. 879 | 880 | ==> ./vendor/github.com/prometheus/client_golang/LICENSE <== 881 | Apache License 882 | Version 2.0, January 2004 883 | http://www.apache.org/licenses/ 884 | 885 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 886 | 887 | 1. Definitions. 888 | 889 | "License" shall mean the terms and conditions for use, reproduction, 890 | and distribution as defined by Sections 1 through 9 of this document. 891 | 892 | "Licensor" shall mean the copyright owner or entity authorized by 893 | the copyright owner that is granting the License. 894 | 895 | "Legal Entity" shall mean the union of the acting entity and all 896 | other entities that control, are controlled by, or are under common 897 | control with that entity. For the purposes of this definition, 898 | "control" means (i) the power, direct or indirect, to cause the 899 | direction or management of such entity, whether by contract or 900 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 901 | outstanding shares, or (iii) beneficial ownership of such entity. 902 | 903 | "You" (or "Your") shall mean an individual or Legal Entity 904 | exercising permissions granted by this License. 905 | 906 | "Source" form shall mean the preferred form for making modifications, 907 | including but not limited to software source code, documentation 908 | source, and configuration files. 909 | 910 | "Object" form shall mean any form resulting from mechanical 911 | transformation or translation of a Source form, including but 912 | not limited to compiled object code, generated documentation, 913 | and conversions to other media types. 914 | 915 | "Work" shall mean the work of authorship, whether in Source or 916 | Object form, made available under the License, as indicated by a 917 | copyright notice that is included in or attached to the work 918 | (an example is provided in the Appendix below). 919 | 920 | "Derivative Works" shall mean any work, whether in Source or Object 921 | form, that is based on (or derived from) the Work and for which the 922 | editorial revisions, annotations, elaborations, or other modifications 923 | represent, as a whole, an original work of authorship. For the purposes 924 | of this License, Derivative Works shall not include works that remain 925 | separable from, or merely link (or bind by name) to the interfaces of, 926 | the Work and Derivative Works thereof. 927 | 928 | "Contribution" shall mean any work of authorship, including 929 | the original version of the Work and any modifications or additions 930 | to that Work or Derivative Works thereof, that is intentionally 931 | submitted to Licensor for inclusion in the Work by the copyright owner 932 | or by an individual or Legal Entity authorized to submit on behalf of 933 | the copyright owner. For the purposes of this definition, "submitted" 934 | means any form of electronic, verbal, or written communication sent 935 | to the Licensor or its representatives, including but not limited to 936 | communication on electronic mailing lists, source code control systems, 937 | and issue tracking systems that are managed by, or on behalf of, the 938 | Licensor for the purpose of discussing and improving the Work, but 939 | excluding communication that is conspicuously marked or otherwise 940 | designated in writing by the copyright owner as "Not a Contribution." 941 | 942 | "Contributor" shall mean Licensor and any individual or Legal Entity 943 | on behalf of whom a Contribution has been received by Licensor and 944 | subsequently incorporated within the Work. 945 | 946 | 2. Grant of Copyright License. Subject to the terms and conditions of 947 | this License, each Contributor hereby grants to You a perpetual, 948 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 949 | copyright license to reproduce, prepare Derivative Works of, 950 | publicly display, publicly perform, sublicense, and distribute the 951 | Work and such Derivative Works in Source or Object form. 952 | 953 | 3. Grant of Patent License. Subject to the terms and conditions of 954 | this License, each Contributor hereby grants to You a perpetual, 955 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 956 | (except as stated in this section) patent license to make, have made, 957 | use, offer to sell, sell, import, and otherwise transfer the Work, 958 | where such license applies only to those patent claims licensable 959 | by such Contributor that are necessarily infringed by their 960 | Contribution(s) alone or by combination of their Contribution(s) 961 | with the Work to which such Contribution(s) was submitted. If You 962 | institute patent litigation against any entity (including a 963 | cross-claim or counterclaim in a lawsuit) alleging that the Work 964 | or a Contribution incorporated within the Work constitutes direct 965 | or contributory patent infringement, then any patent licenses 966 | granted to You under this License for that Work shall terminate 967 | as of the date such litigation is filed. 968 | 969 | 4. Redistribution. You may reproduce and distribute copies of the 970 | Work or Derivative Works thereof in any medium, with or without 971 | modifications, and in Source or Object form, provided that You 972 | meet the following conditions: 973 | 974 | (a) You must give any other recipients of the Work or 975 | Derivative Works a copy of this License; and 976 | 977 | (b) You must cause any modified files to carry prominent notices 978 | stating that You changed the files; and 979 | 980 | (c) You must retain, in the Source form of any Derivative Works 981 | that You distribute, all copyright, patent, trademark, and 982 | attribution notices from the Source form of the Work, 983 | excluding those notices that do not pertain to any part of 984 | the Derivative Works; and 985 | 986 | (d) If the Work includes a "NOTICE" text file as part of its 987 | distribution, then any Derivative Works that You distribute must 988 | include a readable copy of the attribution notices contained 989 | within such NOTICE file, excluding those notices that do not 990 | pertain to any part of the Derivative Works, in at least one 991 | of the following places: within a NOTICE text file distributed 992 | as part of the Derivative Works; within the Source form or 993 | documentation, if provided along with the Derivative Works; or, 994 | within a display generated by the Derivative Works, if and 995 | wherever such third-party notices normally appear. The contents 996 | of the NOTICE file are for informational purposes only and 997 | do not modify the License. You may add Your own attribution 998 | notices within Derivative Works that You distribute, alongside 999 | or as an addendum to the NOTICE text from the Work, provided 1000 | that such additional attribution notices cannot be construed 1001 | as modifying the License. 1002 | 1003 | You may add Your own copyright statement to Your modifications and 1004 | may provide additional or different license terms and conditions 1005 | for use, reproduction, or distribution of Your modifications, or 1006 | for any such Derivative Works as a whole, provided Your use, 1007 | reproduction, and distribution of the Work otherwise complies with 1008 | the conditions stated in this License. 1009 | 1010 | 5. Submission of Contributions. Unless You explicitly state otherwise, 1011 | any Contribution intentionally submitted for inclusion in the Work 1012 | by You to the Licensor shall be under the terms and conditions of 1013 | this License, without any additional terms or conditions. 1014 | Notwithstanding the above, nothing herein shall supersede or modify 1015 | the terms of any separate license agreement you may have executed 1016 | with Licensor regarding such Contributions. 1017 | 1018 | 6. Trademarks. This License does not grant permission to use the trade 1019 | names, trademarks, service marks, or product names of the Licensor, 1020 | except as required for reasonable and customary use in describing the 1021 | origin of the Work and reproducing the content of the NOTICE file. 1022 | 1023 | 7. Disclaimer of Warranty. Unless required by applicable law or 1024 | agreed to in writing, Licensor provides the Work (and each 1025 | Contributor provides its Contributions) on an "AS IS" BASIS, 1026 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1027 | implied, including, without limitation, any warranties or conditions 1028 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 1029 | PARTICULAR PURPOSE. You are solely responsible for determining the 1030 | appropriateness of using or redistributing the Work and assume any 1031 | risks associated with Your exercise of permissions under this License. 1032 | 1033 | 8. Limitation of Liability. In no event and under no legal theory, 1034 | whether in tort (including negligence), contract, or otherwise, 1035 | unless required by applicable law (such as deliberate and grossly 1036 | negligent acts) or agreed to in writing, shall any Contributor be 1037 | liable to You for damages, including any direct, indirect, special, 1038 | incidental, or consequential damages of any character arising as a 1039 | result of this License or out of the use or inability to use the 1040 | Work (including but not limited to damages for loss of goodwill, 1041 | work stoppage, computer failure or malfunction, or any and all 1042 | other commercial damages or losses), even if such Contributor 1043 | has been advised of the possibility of such damages. 1044 | 1045 | 9. Accepting Warranty or Additional Liability. While redistributing 1046 | the Work or Derivative Works thereof, You may choose to offer, 1047 | and charge a fee for, acceptance of support, warranty, indemnity, 1048 | or other liability obligations and/or rights consistent with this 1049 | License. However, in accepting such obligations, You may act only 1050 | on Your own behalf and on Your sole responsibility, not on behalf 1051 | of any other Contributor, and only if You agree to indemnify, 1052 | defend, and hold each Contributor harmless for any liability 1053 | incurred by, or claims asserted against, such Contributor by reason 1054 | of your accepting any such warranty or additional liability. 1055 | 1056 | END OF TERMS AND CONDITIONS 1057 | 1058 | APPENDIX: How to apply the Apache License to your work. 1059 | 1060 | To apply the Apache License to your work, attach the following 1061 | boilerplate notice, with the fields enclosed by brackets "[]" 1062 | replaced with your own identifying information. (Don't include 1063 | the brackets!) The text should be enclosed in the appropriate 1064 | comment syntax for the file format. We also recommend that a 1065 | file or class name and description of purpose be included on the 1066 | same "printed page" as the copyright notice for easier 1067 | identification within third-party archives. 1068 | 1069 | Copyright [yyyy] [name of copyright owner] 1070 | 1071 | Licensed under the Apache License, Version 2.0 (the "License"); 1072 | you may not use this file except in compliance with the License. 1073 | You may obtain a copy of the License at 1074 | 1075 | http://www.apache.org/licenses/LICENSE-2.0 1076 | 1077 | Unless required by applicable law or agreed to in writing, software 1078 | distributed under the License is distributed on an "AS IS" BASIS, 1079 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1080 | See the License for the specific language governing permissions and 1081 | limitations under the License. 1082 | 1083 | ==> ./vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/LICENSE <== 1084 | Copyright (c) 2013 The Go Authors. All rights reserved. 1085 | 1086 | Redistribution and use in source and binary forms, with or without 1087 | modification, are permitted provided that the following conditions are 1088 | met: 1089 | 1090 | * Redistributions of source code must retain the above copyright 1091 | notice, this list of conditions and the following disclaimer. 1092 | * Redistributions in binary form must reproduce the above 1093 | copyright notice, this list of conditions and the following disclaimer 1094 | in the documentation and/or other materials provided with the 1095 | distribution. 1096 | * Neither the name of Google Inc. nor the names of its 1097 | contributors may be used to endorse or promote products derived from 1098 | this software without specific prior written permission. 1099 | 1100 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1101 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1102 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1103 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1104 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1105 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1106 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1107 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1108 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1109 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1110 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1111 | 1112 | ==> ./vendor/github.com/prometheus/client_model/LICENSE <== 1113 | Apache License 1114 | Version 2.0, January 2004 1115 | http://www.apache.org/licenses/ 1116 | 1117 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1118 | 1119 | 1. Definitions. 1120 | 1121 | "License" shall mean the terms and conditions for use, reproduction, 1122 | and distribution as defined by Sections 1 through 9 of this document. 1123 | 1124 | "Licensor" shall mean the copyright owner or entity authorized by 1125 | the copyright owner that is granting the License. 1126 | 1127 | "Legal Entity" shall mean the union of the acting entity and all 1128 | other entities that control, are controlled by, or are under common 1129 | control with that entity. For the purposes of this definition, 1130 | "control" means (i) the power, direct or indirect, to cause the 1131 | direction or management of such entity, whether by contract or 1132 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 1133 | outstanding shares, or (iii) beneficial ownership of such entity. 1134 | 1135 | "You" (or "Your") shall mean an individual or Legal Entity 1136 | exercising permissions granted by this License. 1137 | 1138 | "Source" form shall mean the preferred form for making modifications, 1139 | including but not limited to software source code, documentation 1140 | source, and configuration files. 1141 | 1142 | "Object" form shall mean any form resulting from mechanical 1143 | transformation or translation of a Source form, including but 1144 | not limited to compiled object code, generated documentation, 1145 | and conversions to other media types. 1146 | 1147 | "Work" shall mean the work of authorship, whether in Source or 1148 | Object form, made available under the License, as indicated by a 1149 | copyright notice that is included in or attached to the work 1150 | (an example is provided in the Appendix below). 1151 | 1152 | "Derivative Works" shall mean any work, whether in Source or Object 1153 | form, that is based on (or derived from) the Work and for which the 1154 | editorial revisions, annotations, elaborations, or other modifications 1155 | represent, as a whole, an original work of authorship. For the purposes 1156 | of this License, Derivative Works shall not include works that remain 1157 | separable from, or merely link (or bind by name) to the interfaces of, 1158 | the Work and Derivative Works thereof. 1159 | 1160 | "Contribution" shall mean any work of authorship, including 1161 | the original version of the Work and any modifications or additions 1162 | to that Work or Derivative Works thereof, that is intentionally 1163 | submitted to Licensor for inclusion in the Work by the copyright owner 1164 | or by an individual or Legal Entity authorized to submit on behalf of 1165 | the copyright owner. For the purposes of this definition, "submitted" 1166 | means any form of electronic, verbal, or written communication sent 1167 | to the Licensor or its representatives, including but not limited to 1168 | communication on electronic mailing lists, source code control systems, 1169 | and issue tracking systems that are managed by, or on behalf of, the 1170 | Licensor for the purpose of discussing and improving the Work, but 1171 | excluding communication that is conspicuously marked or otherwise 1172 | designated in writing by the copyright owner as "Not a Contribution." 1173 | 1174 | "Contributor" shall mean Licensor and any individual or Legal Entity 1175 | on behalf of whom a Contribution has been received by Licensor and 1176 | subsequently incorporated within the Work. 1177 | 1178 | 2. Grant of Copyright License. Subject to the terms and conditions of 1179 | this License, each Contributor hereby grants to You a perpetual, 1180 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 1181 | copyright license to reproduce, prepare Derivative Works of, 1182 | publicly display, publicly perform, sublicense, and distribute the 1183 | Work and such Derivative Works in Source or Object form. 1184 | 1185 | 3. Grant of Patent License. Subject to the terms and conditions of 1186 | this License, each Contributor hereby grants to You a perpetual, 1187 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 1188 | (except as stated in this section) patent license to make, have made, 1189 | use, offer to sell, sell, import, and otherwise transfer the Work, 1190 | where such license applies only to those patent claims licensable 1191 | by such Contributor that are necessarily infringed by their 1192 | Contribution(s) alone or by combination of their Contribution(s) 1193 | with the Work to which such Contribution(s) was submitted. If You 1194 | institute patent litigation against any entity (including a 1195 | cross-claim or counterclaim in a lawsuit) alleging that the Work 1196 | or a Contribution incorporated within the Work constitutes direct 1197 | or contributory patent infringement, then any patent licenses 1198 | granted to You under this License for that Work shall terminate 1199 | as of the date such litigation is filed. 1200 | 1201 | 4. Redistribution. You may reproduce and distribute copies of the 1202 | Work or Derivative Works thereof in any medium, with or without 1203 | modifications, and in Source or Object form, provided that You 1204 | meet the following conditions: 1205 | 1206 | (a) You must give any other recipients of the Work or 1207 | Derivative Works a copy of this License; and 1208 | 1209 | (b) You must cause any modified files to carry prominent notices 1210 | stating that You changed the files; and 1211 | 1212 | (c) You must retain, in the Source form of any Derivative Works 1213 | that You distribute, all copyright, patent, trademark, and 1214 | attribution notices from the Source form of the Work, 1215 | excluding those notices that do not pertain to any part of 1216 | the Derivative Works; and 1217 | 1218 | (d) If the Work includes a "NOTICE" text file as part of its 1219 | distribution, then any Derivative Works that You distribute must 1220 | include a readable copy of the attribution notices contained 1221 | within such NOTICE file, excluding those notices that do not 1222 | pertain to any part of the Derivative Works, in at least one 1223 | of the following places: within a NOTICE text file distributed 1224 | as part of the Derivative Works; within the Source form or 1225 | documentation, if provided along with the Derivative Works; or, 1226 | within a display generated by the Derivative Works, if and 1227 | wherever such third-party notices normally appear. The contents 1228 | of the NOTICE file are for informational purposes only and 1229 | do not modify the License. You may add Your own attribution 1230 | notices within Derivative Works that You distribute, alongside 1231 | or as an addendum to the NOTICE text from the Work, provided 1232 | that such additional attribution notices cannot be construed 1233 | as modifying the License. 1234 | 1235 | You may add Your own copyright statement to Your modifications and 1236 | may provide additional or different license terms and conditions 1237 | for use, reproduction, or distribution of Your modifications, or 1238 | for any such Derivative Works as a whole, provided Your use, 1239 | reproduction, and distribution of the Work otherwise complies with 1240 | the conditions stated in this License. 1241 | 1242 | 5. Submission of Contributions. Unless You explicitly state otherwise, 1243 | any Contribution intentionally submitted for inclusion in the Work 1244 | by You to the Licensor shall be under the terms and conditions of 1245 | this License, without any additional terms or conditions. 1246 | Notwithstanding the above, nothing herein shall supersede or modify 1247 | the terms of any separate license agreement you may have executed 1248 | with Licensor regarding such Contributions. 1249 | 1250 | 6. Trademarks. This License does not grant permission to use the trade 1251 | names, trademarks, service marks, or product names of the Licensor, 1252 | except as required for reasonable and customary use in describing the 1253 | origin of the Work and reproducing the content of the NOTICE file. 1254 | 1255 | 7. Disclaimer of Warranty. Unless required by applicable law or 1256 | agreed to in writing, Licensor provides the Work (and each 1257 | Contributor provides its Contributions) on an "AS IS" BASIS, 1258 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1259 | implied, including, without limitation, any warranties or conditions 1260 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 1261 | PARTICULAR PURPOSE. You are solely responsible for determining the 1262 | appropriateness of using or redistributing the Work and assume any 1263 | risks associated with Your exercise of permissions under this License. 1264 | 1265 | 8. Limitation of Liability. In no event and under no legal theory, 1266 | whether in tort (including negligence), contract, or otherwise, 1267 | unless required by applicable law (such as deliberate and grossly 1268 | negligent acts) or agreed to in writing, shall any Contributor be 1269 | liable to You for damages, including any direct, indirect, special, 1270 | incidental, or consequential damages of any character arising as a 1271 | result of this License or out of the use or inability to use the 1272 | Work (including but not limited to damages for loss of goodwill, 1273 | work stoppage, computer failure or malfunction, or any and all 1274 | other commercial damages or losses), even if such Contributor 1275 | has been advised of the possibility of such damages. 1276 | 1277 | 9. Accepting Warranty or Additional Liability. While redistributing 1278 | the Work or Derivative Works thereof, You may choose to offer, 1279 | and charge a fee for, acceptance of support, warranty, indemnity, 1280 | or other liability obligations and/or rights consistent with this 1281 | License. However, in accepting such obligations, You may act only 1282 | on Your own behalf and on Your sole responsibility, not on behalf 1283 | of any other Contributor, and only if You agree to indemnify, 1284 | defend, and hold each Contributor harmless for any liability 1285 | incurred by, or claims asserted against, such Contributor by reason 1286 | of your accepting any such warranty or additional liability. 1287 | 1288 | END OF TERMS AND CONDITIONS 1289 | 1290 | APPENDIX: How to apply the Apache License to your work. 1291 | 1292 | To apply the Apache License to your work, attach the following 1293 | boilerplate notice, with the fields enclosed by brackets "[]" 1294 | replaced with your own identifying information. (Don't include 1295 | the brackets!) The text should be enclosed in the appropriate 1296 | comment syntax for the file format. We also recommend that a 1297 | file or class name and description of purpose be included on the 1298 | same "printed page" as the copyright notice for easier 1299 | identification within third-party archives. 1300 | 1301 | Copyright [yyyy] [name of copyright owner] 1302 | 1303 | Licensed under the Apache License, Version 2.0 (the "License"); 1304 | you may not use this file except in compliance with the License. 1305 | You may obtain a copy of the License at 1306 | 1307 | http://www.apache.org/licenses/LICENSE-2.0 1308 | 1309 | Unless required by applicable law or agreed to in writing, software 1310 | distributed under the License is distributed on an "AS IS" BASIS, 1311 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1312 | See the License for the specific language governing permissions and 1313 | limitations under the License. 1314 | 1315 | ==> ./vendor/github.com/prometheus/common/LICENSE <== 1316 | Apache License 1317 | Version 2.0, January 2004 1318 | http://www.apache.org/licenses/ 1319 | 1320 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1321 | 1322 | 1. Definitions. 1323 | 1324 | "License" shall mean the terms and conditions for use, reproduction, 1325 | and distribution as defined by Sections 1 through 9 of this document. 1326 | 1327 | "Licensor" shall mean the copyright owner or entity authorized by 1328 | the copyright owner that is granting the License. 1329 | 1330 | "Legal Entity" shall mean the union of the acting entity and all 1331 | other entities that control, are controlled by, or are under common 1332 | control with that entity. For the purposes of this definition, 1333 | "control" means (i) the power, direct or indirect, to cause the 1334 | direction or management of such entity, whether by contract or 1335 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 1336 | outstanding shares, or (iii) beneficial ownership of such entity. 1337 | 1338 | "You" (or "Your") shall mean an individual or Legal Entity 1339 | exercising permissions granted by this License. 1340 | 1341 | "Source" form shall mean the preferred form for making modifications, 1342 | including but not limited to software source code, documentation 1343 | source, and configuration files. 1344 | 1345 | "Object" form shall mean any form resulting from mechanical 1346 | transformation or translation of a Source form, including but 1347 | not limited to compiled object code, generated documentation, 1348 | and conversions to other media types. 1349 | 1350 | "Work" shall mean the work of authorship, whether in Source or 1351 | Object form, made available under the License, as indicated by a 1352 | copyright notice that is included in or attached to the work 1353 | (an example is provided in the Appendix below). 1354 | 1355 | "Derivative Works" shall mean any work, whether in Source or Object 1356 | form, that is based on (or derived from) the Work and for which the 1357 | editorial revisions, annotations, elaborations, or other modifications 1358 | represent, as a whole, an original work of authorship. For the purposes 1359 | of this License, Derivative Works shall not include works that remain 1360 | separable from, or merely link (or bind by name) to the interfaces of, 1361 | the Work and Derivative Works thereof. 1362 | 1363 | "Contribution" shall mean any work of authorship, including 1364 | the original version of the Work and any modifications or additions 1365 | to that Work or Derivative Works thereof, that is intentionally 1366 | submitted to Licensor for inclusion in the Work by the copyright owner 1367 | or by an individual or Legal Entity authorized to submit on behalf of 1368 | the copyright owner. For the purposes of this definition, "submitted" 1369 | means any form of electronic, verbal, or written communication sent 1370 | to the Licensor or its representatives, including but not limited to 1371 | communication on electronic mailing lists, source code control systems, 1372 | and issue tracking systems that are managed by, or on behalf of, the 1373 | Licensor for the purpose of discussing and improving the Work, but 1374 | excluding communication that is conspicuously marked or otherwise 1375 | designated in writing by the copyright owner as "Not a Contribution." 1376 | 1377 | "Contributor" shall mean Licensor and any individual or Legal Entity 1378 | on behalf of whom a Contribution has been received by Licensor and 1379 | subsequently incorporated within the Work. 1380 | 1381 | 2. Grant of Copyright License. Subject to the terms and conditions of 1382 | this License, each Contributor hereby grants to You a perpetual, 1383 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 1384 | copyright license to reproduce, prepare Derivative Works of, 1385 | publicly display, publicly perform, sublicense, and distribute the 1386 | Work and such Derivative Works in Source or Object form. 1387 | 1388 | 3. Grant of Patent License. Subject to the terms and conditions of 1389 | this License, each Contributor hereby grants to You a perpetual, 1390 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 1391 | (except as stated in this section) patent license to make, have made, 1392 | use, offer to sell, sell, import, and otherwise transfer the Work, 1393 | where such license applies only to those patent claims licensable 1394 | by such Contributor that are necessarily infringed by their 1395 | Contribution(s) alone or by combination of their Contribution(s) 1396 | with the Work to which such Contribution(s) was submitted. If You 1397 | institute patent litigation against any entity (including a 1398 | cross-claim or counterclaim in a lawsuit) alleging that the Work 1399 | or a Contribution incorporated within the Work constitutes direct 1400 | or contributory patent infringement, then any patent licenses 1401 | granted to You under this License for that Work shall terminate 1402 | as of the date such litigation is filed. 1403 | 1404 | 4. Redistribution. You may reproduce and distribute copies of the 1405 | Work or Derivative Works thereof in any medium, with or without 1406 | modifications, and in Source or Object form, provided that You 1407 | meet the following conditions: 1408 | 1409 | (a) You must give any other recipients of the Work or 1410 | Derivative Works a copy of this License; and 1411 | 1412 | (b) You must cause any modified files to carry prominent notices 1413 | stating that You changed the files; and 1414 | 1415 | (c) You must retain, in the Source form of any Derivative Works 1416 | that You distribute, all copyright, patent, trademark, and 1417 | attribution notices from the Source form of the Work, 1418 | excluding those notices that do not pertain to any part of 1419 | the Derivative Works; and 1420 | 1421 | (d) If the Work includes a "NOTICE" text file as part of its 1422 | distribution, then any Derivative Works that You distribute must 1423 | include a readable copy of the attribution notices contained 1424 | within such NOTICE file, excluding those notices that do not 1425 | pertain to any part of the Derivative Works, in at least one 1426 | of the following places: within a NOTICE text file distributed 1427 | as part of the Derivative Works; within the Source form or 1428 | documentation, if provided along with the Derivative Works; or, 1429 | within a display generated by the Derivative Works, if and 1430 | wherever such third-party notices normally appear. The contents 1431 | of the NOTICE file are for informational purposes only and 1432 | do not modify the License. You may add Your own attribution 1433 | notices within Derivative Works that You distribute, alongside 1434 | or as an addendum to the NOTICE text from the Work, provided 1435 | that such additional attribution notices cannot be construed 1436 | as modifying the License. 1437 | 1438 | You may add Your own copyright statement to Your modifications and 1439 | may provide additional or different license terms and conditions 1440 | for use, reproduction, or distribution of Your modifications, or 1441 | for any such Derivative Works as a whole, provided Your use, 1442 | reproduction, and distribution of the Work otherwise complies with 1443 | the conditions stated in this License. 1444 | 1445 | 5. Submission of Contributions. Unless You explicitly state otherwise, 1446 | any Contribution intentionally submitted for inclusion in the Work 1447 | by You to the Licensor shall be under the terms and conditions of 1448 | this License, without any additional terms or conditions. 1449 | Notwithstanding the above, nothing herein shall supersede or modify 1450 | the terms of any separate license agreement you may have executed 1451 | with Licensor regarding such Contributions. 1452 | 1453 | 6. Trademarks. This License does not grant permission to use the trade 1454 | names, trademarks, service marks, or product names of the Licensor, 1455 | except as required for reasonable and customary use in describing the 1456 | origin of the Work and reproducing the content of the NOTICE file. 1457 | 1458 | 7. Disclaimer of Warranty. Unless required by applicable law or 1459 | agreed to in writing, Licensor provides the Work (and each 1460 | Contributor provides its Contributions) on an "AS IS" BASIS, 1461 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1462 | implied, including, without limitation, any warranties or conditions 1463 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 1464 | PARTICULAR PURPOSE. You are solely responsible for determining the 1465 | appropriateness of using or redistributing the Work and assume any 1466 | risks associated with Your exercise of permissions under this License. 1467 | 1468 | 8. Limitation of Liability. In no event and under no legal theory, 1469 | whether in tort (including negligence), contract, or otherwise, 1470 | unless required by applicable law (such as deliberate and grossly 1471 | negligent acts) or agreed to in writing, shall any Contributor be 1472 | liable to You for damages, including any direct, indirect, special, 1473 | incidental, or consequential damages of any character arising as a 1474 | result of this License or out of the use or inability to use the 1475 | Work (including but not limited to damages for loss of goodwill, 1476 | work stoppage, computer failure or malfunction, or any and all 1477 | other commercial damages or losses), even if such Contributor 1478 | has been advised of the possibility of such damages. 1479 | 1480 | 9. Accepting Warranty or Additional Liability. While redistributing 1481 | the Work or Derivative Works thereof, You may choose to offer, 1482 | and charge a fee for, acceptance of support, warranty, indemnity, 1483 | or other liability obligations and/or rights consistent with this 1484 | License. However, in accepting such obligations, You may act only 1485 | on Your own behalf and on Your sole responsibility, not on behalf 1486 | of any other Contributor, and only if You agree to indemnify, 1487 | defend, and hold each Contributor harmless for any liability 1488 | incurred by, or claims asserted against, such Contributor by reason 1489 | of your accepting any such warranty or additional liability. 1490 | 1491 | END OF TERMS AND CONDITIONS 1492 | 1493 | APPENDIX: How to apply the Apache License to your work. 1494 | 1495 | To apply the Apache License to your work, attach the following 1496 | boilerplate notice, with the fields enclosed by brackets "[]" 1497 | replaced with your own identifying information. (Don't include 1498 | the brackets!) The text should be enclosed in the appropriate 1499 | comment syntax for the file format. We also recommend that a 1500 | file or class name and description of purpose be included on the 1501 | same "printed page" as the copyright notice for easier 1502 | identification within third-party archives. 1503 | 1504 | Copyright [yyyy] [name of copyright owner] 1505 | 1506 | Licensed under the Apache License, Version 2.0 (the "License"); 1507 | you may not use this file except in compliance with the License. 1508 | You may obtain a copy of the License at 1509 | 1510 | http://www.apache.org/licenses/LICENSE-2.0 1511 | 1512 | Unless required by applicable law or agreed to in writing, software 1513 | distributed under the License is distributed on an "AS IS" BASIS, 1514 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1515 | See the License for the specific language governing permissions and 1516 | limitations under the License. 1517 | 1518 | ==> ./vendor/github.com/prometheus/procfs/LICENSE <== 1519 | Apache License 1520 | Version 2.0, January 2004 1521 | http://www.apache.org/licenses/ 1522 | 1523 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1524 | 1525 | 1. Definitions. 1526 | 1527 | "License" shall mean the terms and conditions for use, reproduction, 1528 | and distribution as defined by Sections 1 through 9 of this document. 1529 | 1530 | "Licensor" shall mean the copyright owner or entity authorized by 1531 | the copyright owner that is granting the License. 1532 | 1533 | "Legal Entity" shall mean the union of the acting entity and all 1534 | other entities that control, are controlled by, or are under common 1535 | control with that entity. For the purposes of this definition, 1536 | "control" means (i) the power, direct or indirect, to cause the 1537 | direction or management of such entity, whether by contract or 1538 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 1539 | outstanding shares, or (iii) beneficial ownership of such entity. 1540 | 1541 | "You" (or "Your") shall mean an individual or Legal Entity 1542 | exercising permissions granted by this License. 1543 | 1544 | "Source" form shall mean the preferred form for making modifications, 1545 | including but not limited to software source code, documentation 1546 | source, and configuration files. 1547 | 1548 | "Object" form shall mean any form resulting from mechanical 1549 | transformation or translation of a Source form, including but 1550 | not limited to compiled object code, generated documentation, 1551 | and conversions to other media types. 1552 | 1553 | "Work" shall mean the work of authorship, whether in Source or 1554 | Object form, made available under the License, as indicated by a 1555 | copyright notice that is included in or attached to the work 1556 | (an example is provided in the Appendix below). 1557 | 1558 | "Derivative Works" shall mean any work, whether in Source or Object 1559 | form, that is based on (or derived from) the Work and for which the 1560 | editorial revisions, annotations, elaborations, or other modifications 1561 | represent, as a whole, an original work of authorship. For the purposes 1562 | of this License, Derivative Works shall not include works that remain 1563 | separable from, or merely link (or bind by name) to the interfaces of, 1564 | the Work and Derivative Works thereof. 1565 | 1566 | "Contribution" shall mean any work of authorship, including 1567 | the original version of the Work and any modifications or additions 1568 | to that Work or Derivative Works thereof, that is intentionally 1569 | submitted to Licensor for inclusion in the Work by the copyright owner 1570 | or by an individual or Legal Entity authorized to submit on behalf of 1571 | the copyright owner. For the purposes of this definition, "submitted" 1572 | means any form of electronic, verbal, or written communication sent 1573 | to the Licensor or its representatives, including but not limited to 1574 | communication on electronic mailing lists, source code control systems, 1575 | and issue tracking systems that are managed by, or on behalf of, the 1576 | Licensor for the purpose of discussing and improving the Work, but 1577 | excluding communication that is conspicuously marked or otherwise 1578 | designated in writing by the copyright owner as "Not a Contribution." 1579 | 1580 | "Contributor" shall mean Licensor and any individual or Legal Entity 1581 | on behalf of whom a Contribution has been received by Licensor and 1582 | subsequently incorporated within the Work. 1583 | 1584 | 2. Grant of Copyright License. Subject to the terms and conditions of 1585 | this License, each Contributor hereby grants to You a perpetual, 1586 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 1587 | copyright license to reproduce, prepare Derivative Works of, 1588 | publicly display, publicly perform, sublicense, and distribute the 1589 | Work and such Derivative Works in Source or Object form. 1590 | 1591 | 3. Grant of Patent License. Subject to the terms and conditions of 1592 | this License, each Contributor hereby grants to You a perpetual, 1593 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 1594 | (except as stated in this section) patent license to make, have made, 1595 | use, offer to sell, sell, import, and otherwise transfer the Work, 1596 | where such license applies only to those patent claims licensable 1597 | by such Contributor that are necessarily infringed by their 1598 | Contribution(s) alone or by combination of their Contribution(s) 1599 | with the Work to which such Contribution(s) was submitted. If You 1600 | institute patent litigation against any entity (including a 1601 | cross-claim or counterclaim in a lawsuit) alleging that the Work 1602 | or a Contribution incorporated within the Work constitutes direct 1603 | or contributory patent infringement, then any patent licenses 1604 | granted to You under this License for that Work shall terminate 1605 | as of the date such litigation is filed. 1606 | 1607 | 4. Redistribution. You may reproduce and distribute copies of the 1608 | Work or Derivative Works thereof in any medium, with or without 1609 | modifications, and in Source or Object form, provided that You 1610 | meet the following conditions: 1611 | 1612 | (a) You must give any other recipients of the Work or 1613 | Derivative Works a copy of this License; and 1614 | 1615 | (b) You must cause any modified files to carry prominent notices 1616 | stating that You changed the files; and 1617 | 1618 | (c) You must retain, in the Source form of any Derivative Works 1619 | that You distribute, all copyright, patent, trademark, and 1620 | attribution notices from the Source form of the Work, 1621 | excluding those notices that do not pertain to any part of 1622 | the Derivative Works; and 1623 | 1624 | (d) If the Work includes a "NOTICE" text file as part of its 1625 | distribution, then any Derivative Works that You distribute must 1626 | include a readable copy of the attribution notices contained 1627 | within such NOTICE file, excluding those notices that do not 1628 | pertain to any part of the Derivative Works, in at least one 1629 | of the following places: within a NOTICE text file distributed 1630 | as part of the Derivative Works; within the Source form or 1631 | documentation, if provided along with the Derivative Works; or, 1632 | within a display generated by the Derivative Works, if and 1633 | wherever such third-party notices normally appear. The contents 1634 | of the NOTICE file are for informational purposes only and 1635 | do not modify the License. You may add Your own attribution 1636 | notices within Derivative Works that You distribute, alongside 1637 | or as an addendum to the NOTICE text from the Work, provided 1638 | that such additional attribution notices cannot be construed 1639 | as modifying the License. 1640 | 1641 | You may add Your own copyright statement to Your modifications and 1642 | may provide additional or different license terms and conditions 1643 | for use, reproduction, or distribution of Your modifications, or 1644 | for any such Derivative Works as a whole, provided Your use, 1645 | reproduction, and distribution of the Work otherwise complies with 1646 | the conditions stated in this License. 1647 | 1648 | 5. Submission of Contributions. Unless You explicitly state otherwise, 1649 | any Contribution intentionally submitted for inclusion in the Work 1650 | by You to the Licensor shall be under the terms and conditions of 1651 | this License, without any additional terms or conditions. 1652 | Notwithstanding the above, nothing herein shall supersede or modify 1653 | the terms of any separate license agreement you may have executed 1654 | with Licensor regarding such Contributions. 1655 | 1656 | 6. Trademarks. This License does not grant permission to use the trade 1657 | names, trademarks, service marks, or product names of the Licensor, 1658 | except as required for reasonable and customary use in describing the 1659 | origin of the Work and reproducing the content of the NOTICE file. 1660 | 1661 | 7. Disclaimer of Warranty. Unless required by applicable law or 1662 | agreed to in writing, Licensor provides the Work (and each 1663 | Contributor provides its Contributions) on an "AS IS" BASIS, 1664 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1665 | implied, including, without limitation, any warranties or conditions 1666 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 1667 | PARTICULAR PURPOSE. You are solely responsible for determining the 1668 | appropriateness of using or redistributing the Work and assume any 1669 | risks associated with Your exercise of permissions under this License. 1670 | 1671 | 8. Limitation of Liability. In no event and under no legal theory, 1672 | whether in tort (including negligence), contract, or otherwise, 1673 | unless required by applicable law (such as deliberate and grossly 1674 | negligent acts) or agreed to in writing, shall any Contributor be 1675 | liable to You for damages, including any direct, indirect, special, 1676 | incidental, or consequential damages of any character arising as a 1677 | result of this License or out of the use or inability to use the 1678 | Work (including but not limited to damages for loss of goodwill, 1679 | work stoppage, computer failure or malfunction, or any and all 1680 | other commercial damages or losses), even if such Contributor 1681 | has been advised of the possibility of such damages. 1682 | 1683 | 9. Accepting Warranty or Additional Liability. While redistributing 1684 | the Work or Derivative Works thereof, You may choose to offer, 1685 | and charge a fee for, acceptance of support, warranty, indemnity, 1686 | or other liability obligations and/or rights consistent with this 1687 | License. However, in accepting such obligations, You may act only 1688 | on Your own behalf and on Your sole responsibility, not on behalf 1689 | of any other Contributor, and only if You agree to indemnify, 1690 | defend, and hold each Contributor harmless for any liability 1691 | incurred by, or claims asserted against, such Contributor by reason 1692 | of your accepting any such warranty or additional liability. 1693 | 1694 | END OF TERMS AND CONDITIONS 1695 | 1696 | APPENDIX: How to apply the Apache License to your work. 1697 | 1698 | To apply the Apache License to your work, attach the following 1699 | boilerplate notice, with the fields enclosed by brackets "[]" 1700 | replaced with your own identifying information. (Don't include 1701 | the brackets!) The text should be enclosed in the appropriate 1702 | comment syntax for the file format. We also recommend that a 1703 | file or class name and description of purpose be included on the 1704 | same "printed page" as the copyright notice for easier 1705 | identification within third-party archives. 1706 | 1707 | Copyright [yyyy] [name of copyright owner] 1708 | 1709 | Licensed under the Apache License, Version 2.0 (the "License"); 1710 | you may not use this file except in compliance with the License. 1711 | You may obtain a copy of the License at 1712 | 1713 | http://www.apache.org/licenses/LICENSE-2.0 1714 | 1715 | Unless required by applicable law or agreed to in writing, software 1716 | distributed under the License is distributed on an "AS IS" BASIS, 1717 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1718 | See the License for the specific language governing permissions and 1719 | limitations under the License. 1720 | 1721 | ==> ./vendor/github.com/ant0ine/go-json-rest/LICENSE <== 1722 | Copyright (c) 2013-2016 Antoine Imbert 1723 | 1724 | The MIT License 1725 | 1726 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 1727 | 1728 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1729 | 1730 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1731 | 1732 | ==> ./vendor/github.com/munnerz/goautoneg/LICENSE <== 1733 | Copyright (c) 2011, Open Knowledge Foundation Ltd. 1734 | All rights reserved. 1735 | 1736 | Redistribution and use in source and binary forms, with or without 1737 | modification, are permitted provided that the following conditions are 1738 | met: 1739 | 1740 | Redistributions of source code must retain the above copyright 1741 | notice, this list of conditions and the following disclaimer. 1742 | 1743 | Redistributions in binary form must reproduce the above copyright 1744 | notice, this list of conditions and the following disclaimer in 1745 | the documentation and/or other materials provided with the 1746 | distribution. 1747 | 1748 | Neither the name of the Open Knowledge Foundation Ltd. nor the 1749 | names of its contributors may be used to endorse or promote 1750 | products derived from this software without specific prior written 1751 | permission. 1752 | 1753 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1754 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1755 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1756 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1757 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1758 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1759 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1760 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1761 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1762 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1763 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ` 1764 | --------------------------------------------------------------------------------