├── TODO
├── features
└── cmd
│ ├── clone.feature
│ ├── init.Feature
│ ├── setVersion.feature
│ ├── plugins.feature
│ └── sync.feature
├── tests
├── fixtures
│ ├── extension_storage
│ │ ├── data
│ │ │ ├── ver
│ │ │ ├── objects
│ │ │ │ ├── 15
│ │ │ │ │ └── af5e8f18aea8397ae287ef2f0f237eca7ba410
│ │ │ │ ├── 51
│ │ │ │ │ └── ddb08f4a5453469fb93b1cdc90304d747357b7
│ │ │ │ ├── 90
│ │ │ │ │ └── 5786cba6e9271268f277226315b61c46427718
│ │ │ │ ├── 09
│ │ │ │ │ └── 0694564fb2cc20d4ee82dff29581aea6ebceb2
│ │ │ │ ├── 3e
│ │ │ │ │ └── 09dd8ca40ee4c38920ec37b53860a6335d9749
│ │ │ │ └── fd
│ │ │ │ │ └── 94de288b43ff531cadf282f9664dd70031a9cb
│ │ │ └── pack
│ │ │ │ ├── pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.ind
│ │ │ │ └── pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.pck
│ │ └── 1cv8ddb.1CD
│ ├── storage
│ │ └── 1cv8ddb.1CD
│ ├── ibWithAccess
│ │ └── 1Cv8.1CD
│ └── bigRepository
│ │ └── 1cv8ddb.1CD
├── r2gitsync.yaml
└── bdd
│ ├── run.go
│ └── suite.go
├── pkg
└── plugin
│ ├── subscription
│ ├── handlers.go
│ ├── helpers.go
│ ├── doc.go
│ ├── updatecfg.go
│ ├── dumpConfigToFiles.go
│ ├── getRepositoryAuthors.go
│ ├── commitFiles.go
│ ├── sync.go
│ ├── subscription.go
│ ├── getRepositoryHistory.go
│ ├── workdir.go
│ └── versionFile.go
│ ├── types
│ ├── doc.go
│ ├── subscriber.go
│ ├── updateCfg.go
│ ├── syncProcess.go
│ ├── syncVersion.go
│ ├── dumpConfigToFiles.go
│ ├── commitFiles.go
│ ├── getRepositoryAuthors.go
│ ├── workdir.go
│ ├── repositoryHistory.go
│ └── versionFile.go
│ ├── metadata
│ ├── types.go
│ ├── plugin.go
│ └── pkg.go
│ ├── types.go
│ ├── helpers.go
│ ├── plugin.go
│ ├── loader.go
│ ├── manager.go
│ ├── config
│ └── fileConfig.go
│ └── storage
│ └── storage.go
├── internal
├── manager
│ ├── tempExtension.cfe
│ ├── types.go
│ ├── v8Endpoint.go
│ ├── types
│ │ └── types.go
│ ├── features
│ │ ├── sync-ext.feature
│ │ └── sync.feature
│ ├── options.go
│ ├── init.go
│ ├── git.go
│ ├── manager.go
│ ├── flow.go
│ ├── sync.go
│ ├── helpers.go
│ ├── manager_test.go
│ └── tasks.go
├── plugins
│ ├── plugins.go
│ ├── load.go
│ └── limit
│ │ └── limit.go
├── commands
│ ├── commands.go
│ ├── setVersion_test.go
│ ├── cmdSetVersion.go
│ ├── cmdInit.go
│ ├── shared_test.go
│ ├── syncCmd_test.go
│ ├── syncCmd.go
│ ├── cmdPlugins.go
│ └── context_test.go
├── utils
│ └── appdata.go
└── config
│ └── config.go
├── goreleaser.bat
├── goreleaser.sh
├── .gitignore
├── .run
└── go build github.com_khorevaa_r2gitsync.run.xml
├── LICENSE
├── .github
└── workflows
│ └── releaser.yaml
├── .goreleaser.yml
├── README.md
├── go.mod
├── cmd
└── r2gitsync.go
└── go.sum
/TODO:
--------------------------------------------------------------------------------
1 | [] Что-то сделать
2 |
--------------------------------------------------------------------------------
/features/cmd/clone.feature:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/features/cmd/init.Feature:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/ver:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/handlers.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/objects/15/af5e8f18aea8397ae287ef2f0f237eca7ba410:
--------------------------------------------------------------------------------
1 | {0,0}
--------------------------------------------------------------------------------
/tests/r2gitsync.yaml:
--------------------------------------------------------------------------------
1 | debug: true
2 | tempdir: ./temp
3 | v8version: 8.3.1546
4 | plugins:
5 | limit:
--------------------------------------------------------------------------------
/internal/manager/tempExtension.cfe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/internal/manager/tempExtension.cfe
--------------------------------------------------------------------------------
/tests/fixtures/storage/1cv8ddb.1CD:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/storage/1cv8ddb.1CD
--------------------------------------------------------------------------------
/tests/fixtures/ibWithAccess/1Cv8.1CD:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/ibWithAccess/1Cv8.1CD
--------------------------------------------------------------------------------
/pkg/plugin/types/doc.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | //WriteVersionFile(v8end V8Endpoint, dir string, number int64, filename string) error
4 |
--------------------------------------------------------------------------------
/tests/fixtures/bigRepository/1cv8ddb.1CD:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/bigRepository/1cv8ddb.1CD
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/1cv8ddb.1CD:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/1cv8ddb.1CD
--------------------------------------------------------------------------------
/pkg/plugin/metadata/types.go:
--------------------------------------------------------------------------------
1 | package metadata
2 |
3 | const (
4 | PkgSymbolName = "PluginPackage"
5 | PluginSymbolName = "NewPlugin"
6 | )
7 |
--------------------------------------------------------------------------------
/pkg/plugin/types.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | type subscriber struct {
4 | handlers []interface{}
5 | }
6 |
7 | func (s subscriber) Handlers() []interface{} {
8 | return s.handlers
9 | }
10 |
--------------------------------------------------------------------------------
/goreleaser.bat:
--------------------------------------------------------------------------------
1 | docker run --rm --privileged -v %cd%:/go/src/khorevaa/r2gitsync -v /var/run/docker.sock:/var/run/docker.sock -w /go/src/khorevaa/r2gitsync goreleaser/goreleaser:latest release --snapshot --skip-publish --rm-dist
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/objects/09/0694564fb2cc20d4ee82dff29581aea6ebceb2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/data/objects/09/0694564fb2cc20d4ee82dff29581aea6ebceb2
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/objects/3e/09dd8ca40ee4c38920ec37b53860a6335d9749:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/data/objects/3e/09dd8ca40ee4c38920ec37b53860a6335d9749
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/objects/51/ddb08f4a5453469fb93b1cdc90304d747357b7:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/data/objects/51/ddb08f4a5453469fb93b1cdc90304d747357b7
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/objects/90/5786cba6e9271268f277226315b61c46427718:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/data/objects/90/5786cba6e9271268f277226315b61c46427718
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/objects/fd/94de288b43ff531cadf282f9664dd70031a9cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/data/objects/fd/94de288b43ff531cadf282f9664dd70031a9cb
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.ind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.ind
--------------------------------------------------------------------------------
/tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.pck:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khorevaa/r2gitsync/HEAD/tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.pck
--------------------------------------------------------------------------------
/pkg/plugin/metadata/plugin.go:
--------------------------------------------------------------------------------
1 | package metadata
2 |
3 | import (
4 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
5 | )
6 |
7 | // Plugin основной интерфейс плагинов
8 | type Plugin interface {
9 | Subscribe() Subscriber
10 | }
11 |
--------------------------------------------------------------------------------
/goreleaser.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | docker run --rm --privileged \
4 | -v $PWD:/go/src/khorevaa/r2gitsync \
5 | -v /var/run/docker.sock:/var/run/docker.sock \
6 | -w /go/src/khorevaa/r2gitsync \
7 | goreleaser/goreleaser:latest release --snapshot --skip-publish --rm-dist
--------------------------------------------------------------------------------
/internal/manager/types.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | v8 "github.com/v8platform/api"
5 | "github.com/v8platform/designer"
6 | )
7 |
8 | type V8Endpoint interface {
9 | Infobase() *v8.Infobase
10 | Repository() *designer.Repository
11 | Extention() string
12 | Options() []interface{}
13 | }
14 |
--------------------------------------------------------------------------------
/internal/plugins/plugins.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/internal/plugins/limit"
5 | "github.com/khorevaa/r2gitsync/pkg/plugin"
6 | )
7 |
8 | func init() {
9 |
10 | plugin.Register(limit.Symbol)
11 | err := LoadPlugins()
12 | if err != nil {
13 | panic(err)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/internal/commands/commands.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/pkg/plugin"
5 | "github.com/urfave/cli/v2"
6 | )
7 |
8 | var Commands = []Command{
9 |
10 | &syncCmd{},
11 | // &listCmd{},
12 |
13 | }
14 |
15 | type Command interface {
16 | Cmd(manager plugin.Manager) *cli.Command
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/plugin/types/subscriber.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | v8 "github.com/v8platform/api"
5 | "github.com/v8platform/designer"
6 | )
7 |
8 | type Subscriber interface {
9 | Handlers() []interface{}
10 | }
11 |
12 | type V8Endpoint interface {
13 | Infobase() *v8.Infobase
14 | Repository() *designer.Repository
15 | Extention() string
16 | Options() []interface{}
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 | *.cfl
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 | .idea/
14 | dist/
15 | .r2gitsync/
16 | out/
17 | .run/
18 | test_sync/
19 | # Dependency directories (remove the comment below to include it)
20 | # vendor/
21 |
--------------------------------------------------------------------------------
/pkg/plugin/types/updateCfg.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | type UpdateCfgSubscriber struct {
4 | On OnUpdateCfgFn
5 | Before BeforeUpdateCfgFn
6 | After AfterUpdateCfgFn
7 | }
8 |
9 | type (
10 | BeforeUpdateCfgFn func(v8end V8Endpoint, workdir string, version int) error
11 | OnUpdateCfgFn func(v8end V8Endpoint, workdir string, version int, stdHandler *bool) error
12 | AfterUpdateCfgFn BeforeUpdateCfgFn
13 | )
14 |
--------------------------------------------------------------------------------
/pkg/plugin/types/syncProcess.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | //StartSyncProcess(v8end V8Endpoint, dir string)
4 | //FinishSyncProcess(v8end V8Endpoint, dir string)
5 |
6 | type (
7 | SyncProcessSubscriber struct {
8 | Start StartSyncProcessFn
9 | Finish FinishSyncProcessFn
10 | }
11 |
12 | StartSyncProcessFn func(v8end V8Endpoint, workdir string)
13 | FinishSyncProcessFn func(v8end V8Endpoint, workdir string, err *error)
14 | )
15 |
--------------------------------------------------------------------------------
/pkg/plugin/helpers.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | func BuildVersion(version, commit string) string {
8 | var result = version
9 | if commit != "" {
10 | result = fmt.Sprintf("%s+%s", result, commit)
11 | }
12 | return result
13 | }
14 |
15 | func Contains(arr []string, str string) bool {
16 | for _, a := range arr {
17 | if a == str {
18 | return true
19 | }
20 | }
21 | return false
22 | }
23 |
--------------------------------------------------------------------------------
/internal/plugins/load.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 |
7 | "github.com/khorevaa/r2gitsync/internal/utils"
8 | "github.com/khorevaa/r2gitsync/pkg/plugin"
9 | )
10 |
11 | func LoadPlugins() error {
12 |
13 | appDataDir := utils.GetAppDataDir("r2gitsync")
14 | pluginsDir := filepath.Join(appDataDir, "plugins")
15 |
16 | if _, err := os.Stat(pluginsDir); err != nil {
17 | return nil
18 | }
19 |
20 | err := plugin.LoadPlugins(pluginsDir)
21 |
22 | return err
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/plugin/types/syncVersion.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | //StartSyncVersion(v8end V8Endpoint, workdir string, tempdir string, number int64) error
4 | //FinishSyncVersion(v8end V8Endpoint, workdir string, tempdir string, number int64, err *error)
5 |
6 | type (
7 | SyncVersionSubscriber struct {
8 | Start StartSyncVersionFn
9 | Finish FinishSyncVersionFn
10 | }
11 |
12 | StartSyncVersionFn func(v8end V8Endpoint, workdir string, tempdir string, number int)
13 | FinishSyncVersionFn func(v8end V8Endpoint, workdir string, tempdir string, number int, err *error)
14 | )
15 |
--------------------------------------------------------------------------------
/tests/bdd/run.go:
--------------------------------------------------------------------------------
1 | package bdd
2 |
3 | import "github.com/cucumber/godog"
4 |
5 | type Option func(suite *Suite)
6 |
7 | func Run(features []string,
8 | initSuite func(context *godog.TestSuiteContext),
9 | InitScenario func(context *godog.ScenarioContext),
10 | opts ...Option) error {
11 |
12 | suite := newSuite()
13 | suite.Paths = features
14 | suite.TestSuiteInitializer = append(suite.TestSuiteInitializer, initSuite)
15 | suite.ScenarioInitializer = append(suite.ScenarioInitializer, InitScenario)
16 |
17 | for _, opt := range opts {
18 | opt(suite)
19 | }
20 |
21 | return suite.Run()
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/plugin/types/dumpConfigToFiles.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | //DumpConfigToFiles(v8end V8Endpoint, update bool, dir string, dir2 string, number int) error
4 |
5 | type DumpConfigToFilesSubscriber struct {
6 | On OnDumpConfigFn
7 | Before BeforeDumpConfigFn
8 | After AfterDumpConfigFn
9 | }
10 |
11 | type (
12 | BeforeDumpConfigFn func(v8end V8Endpoint, workdir string, temp string, number int, update *bool) error
13 | OnDumpConfigFn func(v8end V8Endpoint, workdir string, temp string, number int, update *bool, stdHandler *bool) error
14 | AfterDumpConfigFn func(v8end V8Endpoint, workdir string, temp string, number int, update bool) error
15 | )
16 |
--------------------------------------------------------------------------------
/internal/manager/v8Endpoint.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | v8 "github.com/v8platform/api"
5 | "github.com/v8platform/designer"
6 | )
7 |
8 | type v8Endpoint struct {
9 | infobase *v8.Infobase
10 | repository *designer.Repository
11 | options []interface{}
12 |
13 | extention string
14 | }
15 |
16 | func (end *v8Endpoint) Infobase() *v8.Infobase {
17 |
18 | return end.infobase
19 |
20 | }
21 |
22 | func (end *v8Endpoint) Repository() *designer.Repository {
23 |
24 | return end.repository
25 | }
26 |
27 | func (end *v8Endpoint) Options() []interface{} {
28 |
29 | return end.options
30 |
31 | }
32 |
33 | func (end *v8Endpoint) Extention() string {
34 | return end.extention
35 | }
36 |
--------------------------------------------------------------------------------
/internal/manager/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | v8 "github.com/v8platform/api"
5 | "github.com/v8platform/designer"
6 | "time"
7 | )
8 |
9 | type V8Endpoint interface {
10 | Infobase() *v8.Infobase
11 | Repository() *designer.Repository
12 | Extention() string
13 | Options() []interface{}
14 | }
15 |
16 | type RepositoryAuthor interface {
17 | Name() string
18 | Email() string
19 | Desc() string
20 | }
21 |
22 | type RepositoryAuthorsList map[string]RepositoryAuthor
23 |
24 | type RepositoryVersionsList []RepositoryVersion
25 |
26 | type RepositoryVersion interface {
27 | Version() string
28 | Author() string
29 | Date() time.Time
30 | Comment() string
31 | Number() int
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/plugin/types/commitFiles.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/internal/manager/types"
5 | "time"
6 | )
7 |
8 | //CommitFiles(v8end V8Endpoint, dir string, author RepositoryAuthor, when time.Time, comment string) error
9 |
10 | type CommitFilesSubscriber struct {
11 | Before BeforeCommitFilesFn
12 | On OnCommitFilesFn
13 | After AfterCommitFilesFn
14 | }
15 | type (
16 | BeforeCommitFilesFn func(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when time.Time, comment string) error
17 | OnCommitFilesFn func(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when *time.Time, comment *string, stdHandler *bool) error
18 | AfterCommitFilesFn BeforeCommitFilesFn
19 | )
20 |
--------------------------------------------------------------------------------
/pkg/plugin/types/getRepositoryAuthors.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/internal/manager/types"
5 | )
6 |
7 | //GetRepositoryAuthors(v8end V8Endpoint, dir string, filenme string) (map[string]RepositoryAuthor, error)
8 |
9 | type GetRepositoryAuthorsSubscriber struct {
10 | Before BeforeGetRepositoryAuthorsFn
11 | On OnGetRepositoryAuthorsFn
12 | After AfterGetRepositoryAuthorsFn
13 | }
14 | type (
15 | BeforeGetRepositoryAuthorsFn func(v8end V8Endpoint, workdir string, filename string) error
16 | OnGetRepositoryAuthorsFn func(v8end V8Endpoint, workdir string, filename string, stdHandler *bool) (map[string]types.RepositoryAuthor, error)
17 | AfterGetRepositoryAuthorsFn func(v8end V8Endpoint, workdir string, authors *types.RepositoryAuthorsList) error
18 | )
19 |
--------------------------------------------------------------------------------
/.run/go build github.com_khorevaa_r2gitsync.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/pkg/plugin/types/workdir.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | //ClearWorkDir(v8end V8Endpoint, dir string, tempDir string) error
4 | //MoveToWorkDir(v8end V8Endpoint, dir string, tempDir string) error
5 |
6 | type ClearWorkdirSubscriber struct {
7 | Before BeforeClearWorkdirFn
8 | On OnClearWorkdirFn
9 | After AfterClearWorkdirFn
10 | }
11 |
12 | type (
13 | BeforeClearWorkdirFn func(v8end V8Endpoint, workdir string, temp string) error
14 | OnClearWorkdirFn func(v8end V8Endpoint, workdir string, temp string, stdHandler *bool) error
15 | AfterClearWorkdirFn BeforeClearWorkdirFn
16 | )
17 |
18 | type MoveToWorkdirSubscriber struct {
19 | Before BeforeMoveToWorkdirFn
20 | On OnMoveToWorkdirFn
21 | After AfterMoveToWorkdirFn
22 | }
23 |
24 | type (
25 | BeforeMoveToWorkdirFn BeforeClearWorkdirFn
26 | OnMoveToWorkdirFn OnClearWorkdirFn
27 | AfterMoveToWorkdirFn BeforeClearWorkdirFn
28 | )
29 |
--------------------------------------------------------------------------------
/pkg/plugin/types/repositoryHistory.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/internal/manager/types"
5 | )
6 |
7 | type GetRepositoryHistorySubscriber struct {
8 | On OnGetRepositoryHistoryFn
9 | Before BeforeGetRepositoryHistoryFn
10 | After AfterGetRepositoryHistoryFn
11 | }
12 |
13 | type ConfigureRepositoryVersionsSubscriber struct {
14 | On OnConfigureRepositoryVersionsFn
15 | }
16 |
17 | type OnConfigureRepositoryVersionsFn func(v8end V8Endpoint, versions *types.RepositoryVersionsList, NCurrent, NNext, NMax *int) error
18 |
19 | type (
20 | BeforeGetRepositoryHistoryFn func(v8end V8Endpoint, dir string, NBegin int) error
21 | OnGetRepositoryHistoryFn func(v8end V8Endpoint, dir string, NBegin int, stdHandler *bool) ([]types.RepositoryVersion, error)
22 | AfterGetRepositoryHistoryFn func(v8end V8Endpoint, dir string, NBegin int, rv *types.RepositoryVersionsList) error
23 | )
24 |
--------------------------------------------------------------------------------
/pkg/plugin/types/versionFile.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | //WriteVersionFile(v8end V8Endpoint, dir string, number int, filename string) error
4 |
5 | type WriteVersionFileSubscriber struct {
6 | Before BeforeWriteVersionFileFn
7 | On OnWriteVersionFileFn
8 | After AfterWriteVersionFileFn
9 | }
10 | type (
11 | BeforeWriteVersionFileFn func(v8end V8Endpoint, workdir string, number int, filename string) error
12 | OnWriteVersionFileFn func(v8end V8Endpoint, workdir string, number int, filename string, stdHandler *bool) error
13 | AfterWriteVersionFileFn BeforeWriteVersionFileFn
14 | )
15 |
16 | type ReadVersionFileSubscriber struct {
17 | Before BeforeReadVersionFileFn
18 | On OnReadVersionFileFn
19 | After AfterReadVersionFileFn
20 | }
21 | type (
22 | BeforeReadVersionFileFn func(v8end V8Endpoint, workdir string, filename string) error
23 | OnReadVersionFileFn func(v8end V8Endpoint, workdir string, filename string, stdHandler *bool) (int, error)
24 | AfterReadVersionFileFn func(v8end V8Endpoint, workdir string, filename string, number *int) error
25 | )
26 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/helpers.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
5 | )
6 |
7 | type SubscribeHandler interface {
8 | Count() int
9 | }
10 |
11 | func NewSubscribeManager() *SubscribeManager {
12 | return &SubscribeManager{
13 |
14 | UpdateCfg: &updateCfgHandler{},
15 | DumpConfigToFiles: &dumpConfigToFilesHandler{},
16 | GetRepositoryHistory: &getRepositoryHistoryHandler{},
17 | GetRepositoryAuthors: &getRepositoryAuthorsHandler{},
18 | ConfigureRepositoryVersions: &configureRepositoryVersionsHandler{},
19 | SyncProcess: &syncProcessHandler{},
20 | SyncVersion: &syncversionHandler{},
21 | ClearWorkdir: &clearWorkdirHandler{},
22 | MoveToWorkdir: &moveToWorkdirHandler{},
23 | CommitFiles: &commitFilesHandler{},
24 | ReadVersionFile: &readVersionFileHandler{},
25 | WriteVersionFile: &writeVersionFileHandler{},
26 | }
27 | }
28 |
29 | type Plugin interface {
30 | Subscribe() Subscriber
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Aleksey Khorev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/internal/manager/features/sync-ext.feature:
--------------------------------------------------------------------------------
1 | # language: ru
2 | @ext
3 | Функциональность: Синхронизация хранилища расширения конфигурации 1С и гит (команды sync)
4 | Как Пользователь
5 | Я хочу выполнять автоматическую синхронизацию конфигурации из хранилища расширения
6 | Чтобы автоматизировать свою работы с хранилищем с git
7 |
8 | Контекст: Тестовый контекст синхронизации
9 | Когда Я создаю временный каталог и сохраняю его в переменной "КаталогХранилища1С"
10 | И я скопировал каталог "./tests/fixtures/extension_storage" в каталог из переменной "КаталогХранилища1С"
11 | И Я создаю временный каталог и сохраняю его в переменной "ПутьКаталогаИсходников"
12 | И Я инициализирую репозиторий в каталоге из переменной "ПутьКаталогаИсходников"
13 | И Я создаю тестовой файл AUTHORS
14 | И Я записываю "0" в файл VERSION
15 |
16 | Сценарий: Синхронизация хранилища расширения с git-репозиторием
17 | Допустим Я устанавливаю авторизацию в хранилище пользователя "Администратор" с паролем ""
18 | И Я устанавливаю версию платформы "8.3"
19 | Когда Я выполняю выполняют синхронизацию для расширения "test"
20 | Тогда Файл VERSION содержит 4
21 |
--------------------------------------------------------------------------------
/internal/manager/options.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/pkg/plugin/subscription"
5 | "github.com/v8platform/api"
6 | )
7 |
8 | type Option func(*Options)
9 |
10 | type Options struct {
11 | TempDir string
12 | DisableIncrement bool
13 |
14 | MinVersion int
15 | MaxVersion int
16 | LimitVersions int
17 | InfobaseConnect string
18 | InfobaseUser string
19 | InfobasePassword string
20 | DomainEmail string
21 |
22 | opts []interface{}
23 | V8Path string
24 | V8version string
25 |
26 | Plugins *subscription.SubscribeManager
27 |
28 | LicTryCount int
29 | }
30 |
31 | func (o *Options) Infobase() (*v8.Infobase, error) {
32 |
33 | return v8.ParseConnectionString(o.InfobaseConnect)
34 |
35 | }
36 |
37 | func (o *Options) Options() []interface{} {
38 |
39 | if len(o.opts) == 0 {
40 | o.opts = []interface{}{
41 | v8.WithPath(o.V8Path),
42 | v8.WithVersion(o.V8version),
43 | v8.WithCommonValues("/DisableStartupDialogs", "/DisableStartupMessages"),
44 | v8.WithCredentials(o.InfobaseUser, o.InfobasePassword),
45 | }
46 | }
47 |
48 | return o.opts
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/internal/utils/appdata.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "github.com/mitchellh/go-homedir"
6 | "os"
7 | "path/filepath"
8 | "runtime"
9 | )
10 |
11 | func GetAppDataDir(appName string) string {
12 | homeDir, err := homedir.Dir()
13 |
14 | dotName := fmt.Sprintf(".%s", appName)
15 | if err != nil {
16 | return dotName
17 | }
18 |
19 | switch runtime.GOOS {
20 | case "windows":
21 | appData := os.Getenv("LOCALAPPDATA")
22 | if appData == "" {
23 | appData = os.Getenv("APPDATA")
24 | }
25 |
26 | if appData != "" {
27 | return filepath.Join(appData, appName)
28 | }
29 | case "darwin":
30 | if homeDir != "" {
31 | return filepath.Join(homeDir, "Library", "Application Support", appName)
32 | }
33 | case "linux":
34 | xdgDataHome := os.Getenv("XDG_DATA_HOME")
35 |
36 | if xdgDataHome == "" {
37 | if homeDir == "" {
38 | return filepath.Join(homeDir, dotName)
39 | }
40 |
41 | xdgDataHome = filepath.Join(homeDir, ".local", "share")
42 | }
43 |
44 | return filepath.Join(xdgDataHome, appName)
45 | default:
46 | if homeDir != "" {
47 | return filepath.Join(homeDir, dotName)
48 | }
49 | }
50 |
51 | return dotName
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/plugin/plugin.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | import (
4 | "github.com/elastic/go-ucfg"
5 | "github.com/khorevaa/r2gitsync/pkg/plugin/metadata"
6 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
7 | "github.com/urfave/cli/v2"
8 | "sync"
9 | )
10 |
11 | // plugins список загруженных плагинов
12 | var plugins = map[string]Symbol{}
13 |
14 | // muPlugins для избежания дедлоков
15 | var muPlugins = &sync.Mutex{}
16 |
17 | type Symbol struct {
18 | Name string
19 | Version string
20 | Desc string
21 | New func(cfg *ucfg.Config) (Plugin, error)
22 | Modules []string
23 | Flags []cli.Flag
24 | }
25 |
26 | type Plugin interface {
27 | metadata.Plugin
28 | }
29 |
30 | // Register registers a global plugins
31 | func Register(symbols ...Symbol) {
32 | muPlugins.Lock()
33 | defer muPlugins.Unlock()
34 | for _, pl := range symbols {
35 | plugins[pl.Name] = pl
36 | }
37 | }
38 |
39 | func Subscription(handlers ...interface{}) Subscriber {
40 |
41 | return subscriber{
42 | handlers: handlers,
43 | }
44 | }
45 |
46 | func LoadPlugins(dir string) error {
47 |
48 | loader := NewPluginsLoader(dir)
49 |
50 | err := loader.LoadPlugins(false)
51 |
52 | if err != nil {
53 | return err
54 | }
55 |
56 | Register(loader.Plugins()...)
57 |
58 | return nil
59 | }
60 |
--------------------------------------------------------------------------------
/internal/manager/init.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import _ "embed"
4 |
5 | //go:embed tempExtension.cfe
6 | var tempExtension []byte
7 |
8 | func (r *SyncRepository) initWorkdir(opts *Options) (err error) {
9 |
10 | // if !opts.ForceInit {
11 | // // TODO Проверить папку и ругнуться если там что-то есть
12 | // // TODO При принудительной инициализации - очистить целевой каталог от лишего
13 | // }
14 | //
15 | // err = r.init(opts)
16 | // if err != nil {
17 | // return err
18 | // }
19 | //
20 | // r.log.Infow("Start init repository data",
21 | // zap.String("name", r.Name),
22 | // zap.String("path", r.Repository.Path),
23 | // )
24 | //
25 | // r.log.Infow("Using infobase for init repository data",
26 | // zap.String("path", opts.infobase.ConnectionString()))
27 | //
28 | // err = r.GetRepositoryAuthors()
29 | //
30 | // if err != nil {
31 | // return err
32 | // }
33 | //
34 | // err = r.GetRepositoryHistory()
35 | // if err != nil {
36 | // return err
37 | // }
38 | //
39 | // // TODO Сделать обход версии получение всех пользователей хранилища
40 | // // TODO Сделать запись файла AUTHORS
41 | // // TODO В плагины добавить поддержку записи файла AUTHORS
42 | //
43 | // err = r.WriteVersionFile(0)
44 | //
45 | // if err != nil {
46 | // return err
47 | // }
48 |
49 | return
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/.github/workflows/releaser.yaml:
--------------------------------------------------------------------------------
1 | name: goreleaser
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 | jobs:
8 | goreleaser:
9 | runs-on: ubuntu-latest
10 | steps:
11 | -
12 | name: Checkout
13 | uses: actions/checkout@v2
14 | with:
15 | fetch-depth: 0
16 | -
17 | name: Set up Go
18 | uses: actions/setup-go@v2
19 | with:
20 | go-version: 1.16
21 | -
22 | name: Docker Login
23 | if: success() && startsWith(github.ref, 'refs/tags/v')
24 | env:
25 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
26 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
27 | GITHUB_TOKEN: ${{ secrets.GH_PAT }}
28 | run: |
29 | echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin
30 | echo "${GITHUB_TOKEN}" | docker login ghcr.io --username $GITHUB_ACTOR --password-stdin
31 | -
32 | name: Run GoReleaser
33 | uses: goreleaser/goreleaser-action@v2
34 | with:
35 | version: latest
36 | args: release --rm-dist
37 | env:
38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39 | -
40 | name: Clear
41 | if: always() && startsWith(github.ref, 'refs/tags/v')
42 | run: |
43 | rm -f ${HOME}/.docker/config.json
--------------------------------------------------------------------------------
/internal/manager/features/sync.feature:
--------------------------------------------------------------------------------
1 | # language: ru
2 |
3 | Функциональность: Синхронизация хранилища конфигурации 1С и гит (команды sync)
4 | Как Пользователь
5 | Я хочу выполнять автоматическую синхронизацию конфигурации из хранилища
6 | Чтобы автоматизировать свою работы с хранилищем с git
7 |
8 | Контекст: Тестовый контекст синхронизации
9 | Когда Я создаю временный каталог и сохраняю его в переменной "КаталогХранилища1С"
10 | И я скопировал каталог "./tests/fixtures/storage" в каталог из переменной "КаталогХранилища1С"
11 | И Я создаю временный каталог и сохраняю его в переменной "ПутьКаталогаИсходников"
12 | И Я инициализирую репозиторий в каталоге из переменной "ПутьКаталогаИсходников"
13 | И Я создаю тестовой файл AUTHORS
14 | И Я записываю "0" в файл VERSION
15 |
16 | Сценарий: Простая синхронизация хранилища с git-репозиторием
17 | Допустим Я устанавливаю авторизацию в хранилище пользователя "Администратор" с паролем ""
18 | И Я устанавливаю версию платформы "8.3"
19 | Когда Я выполняю выполняют синхронизацию
20 | Тогда Файл VERSION содержит 2
21 |
22 | Сценарий: Cинхронизация c большим хранилищам 1С
23 | Допустим Я устанавливаю авторизацию в хранилище пользователя "Администратор" с паролем ""
24 | И я скопировал каталог "./tests/fixtures/bigRepository" в каталог из переменной "КаталогХранилища1С"
25 | И Я устанавливаю версию платформы "8.3"
26 | Когда Я выполняю выполняют синхронизацию
27 | Тогда Файл VERSION содержит 10
--------------------------------------------------------------------------------
/internal/commands/setVersion_test.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | //
4 | // import (
5 | // "github.com/cucumber/godog"
6 | // "github.com/khorevaa/r2gitsync/tests/bdd"
7 | // "github.com/stretchr/testify/require"
8 | // "github.com/stretchr/testify/suite"
9 | // "testing"
10 | // )
11 | //
12 | // type cmdSetVersionTestSuite struct {
13 | // suite.Suite
14 | // BaseSuite
15 | // }
16 | //
17 | // func TestCmdSetVersionTestSuite(t *testing.T) {
18 | // suite.Run(t, new(cmdSetVersionTestSuite))
19 | // }
20 | //
21 | // func (s *cmdSetVersionTestSuite) r() *require.Assertions {
22 | // return s.Require()
23 | // }
24 | //
25 | // func (s *cmdSetVersionTestSuite) TestFeatures() {
26 | //
27 | // err := bdd.Run([]string{
28 | // "features/setVersion.feature",
29 | // },
30 | // s.InitializeCmdSyncTestSuite,
31 | // s.InitializeCmdSyncScenario)
32 | //
33 | // s.r().NoError(err)
34 | //
35 | // }
36 | //
37 | // type cmdSetVersionContext struct {
38 | // *Context
39 | // app *AppTestSuite
40 | // }
41 | //
42 | // func (s *cmdSetVersionTestSuite) InitializeCmdSyncScenario(ctx *godog.ScenarioContext) {
43 | //
44 | // sharedCtx := SharedContext(ctx)
45 | //
46 | // _ = &cmdSetVersionContext{
47 | // Context: sharedCtx,
48 | // app: SharedAppSteps(sharedCtx, ctx),
49 | // }
50 | // // ctx.Step(`^Я инициализирую новое приложение$`, step.InitNewApp)
51 | // // ctx.Step(`^я скопировал каталог "([^"]*)" в каталог из переменной "([^"]*)"$`, step.CopyDirToDirFromContext )
52 | //
53 | // }
54 |
--------------------------------------------------------------------------------
/pkg/plugin/metadata/pkg.go:
--------------------------------------------------------------------------------
1 | package metadata
2 |
3 | //
4 | // type PkgMetadata struct {
5 | // name string
6 | // version string
7 | // plugins []PluginSymbol
8 | // file string
9 | // hash crypto.Hash
10 | //
11 | // check func() error
12 | // }
13 | //
14 | // type PkgSymbol interface {
15 | // Name() string
16 | // Version() string
17 | // Plugins() []PluginSymbol
18 | // }
19 | //
20 | // func (m *PkgMetadata) Checker(fn func() error) {
21 | //
22 | // m.check = fn
23 | //
24 | // }
25 | //
26 | // func (m PkgMetadata) Check() error {
27 | //
28 | // if m.check != nil {
29 | // return m.check()
30 | // }
31 | // return nil
32 | // }
33 | //
34 | // func (m PkgMetadata) File() string {
35 | //
36 | // return m.file
37 | // }
38 | //
39 | // func (m PkgMetadata) LoadFile() (pm.Symbol, error) {
40 | //
41 | // var pSymbol pm.Symbol
42 | //
43 | // pluginFile, err := pm.Open(m.file)
44 | // if err != nil {
45 | // return pSymbol, err
46 | // }
47 | //
48 | // pSymbol, err = pluginFile.Lookup(PkgSymbolName)
49 | //
50 | // if err == nil {
51 | // return pSymbol, nil
52 | // }
53 | //
54 | // pSymbol, err = pluginFile.Lookup(PluginSymbolName)
55 | //
56 | // return pSymbol, err
57 | // }
58 | //
59 | // func NewPkgMetadata(file string, sym PkgSymbol) PkgMetadata {
60 | //
61 | // return PkgMetadata{
62 | // name: sym.Name(),
63 | // version: sym.Version(),
64 | // plugins: sym.Plugins(),
65 | // file: file,
66 | // hash: 0,
67 | // check: nil,
68 | // }
69 | //
70 | // }
71 |
--------------------------------------------------------------------------------
/tests/bdd/suite.go:
--------------------------------------------------------------------------------
1 | package bdd
2 |
3 | import (
4 | "errors"
5 | "github.com/cucumber/godog"
6 | "github.com/khorevaa/r2gitsync/pkg/context"
7 | )
8 |
9 | type Suite struct {
10 | Paths []string
11 | Format string
12 | Strict bool
13 | Concurrency int
14 | TestSuiteInitializer []func(context *godog.TestSuiteContext)
15 | ScenarioInitializer []func(context *godog.ScenarioContext)
16 |
17 | context.Context
18 | }
19 |
20 | func (s *Suite) InitializeTestSuite(context *godog.TestSuiteContext) {
21 |
22 | for _, fn := range s.TestSuiteInitializer {
23 | fn(context)
24 | }
25 |
26 | }
27 |
28 | func (s *Suite) InitializeScenario(context *godog.ScenarioContext) {
29 |
30 | for _, fn := range s.ScenarioInitializer {
31 | fn(context)
32 | }
33 |
34 | }
35 |
36 | func (s *Suite) Run() error {
37 |
38 | opts := godog.Options{
39 | Format: s.Format,
40 | Paths: s.Paths,
41 | //ShowStepDefinitions: true,
42 | //StopOnFailure: true,
43 | Strict: s.Strict,
44 | Concurrency: s.Concurrency,
45 | }
46 |
47 | // godog v0.10.0 (latest)
48 | status := godog.TestSuite{
49 | Name: "godogs",
50 | TestSuiteInitializer: s.InitializeTestSuite,
51 | ScenarioInitializer: s.InitializeScenario,
52 | Options: &opts,
53 | }.Run()
54 |
55 | if status > 0 {
56 |
57 | return errors.New("test suite is fail")
58 | }
59 |
60 | return nil
61 | }
62 |
63 | func newSuite() *Suite {
64 |
65 | return &Suite{
66 | Format: "pretty",
67 | Strict: true,
68 | Concurrency: 1,
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/internal/commands/cmdSetVersion.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | //
4 | // import (
5 | // cli "github.com/jawher/mow.cli"
6 | // "github.com/khorevaa/r2gitsync/internal/app"
7 | // flags2 "github.com/khorevaa/r2gitsync/internal/app/flags"
8 | // manager2 "github.com/khorevaa/r2gitsync/internal/manager"
9 | // "github.com/khorevaa/r2gitsync/pkg/plugin"
10 | // "github.com/khorevaa/r2gitsync/pkg/plugin/subscription"
11 | // )
12 | //
13 | // func (app *app.Application) cmdSetVersion(cmd *cli.Cmd) {
14 | //
15 | // var (
16 | // doCommit bool
17 | // setVersion int
18 | // workdir string
19 | // )
20 | //
21 | // flags2.BoolOpt("c commit", false, "закоммитить изменения в git").
22 | // Ptr(&doCommit).
23 | // Apply(cmd, app.ctx)
24 | // flags2.IntArg("VERSION", 0, "Номер версии для записи в файл.").
25 | // Ptr(&setVersion).
26 | // Apply(cmd, app.ctx)
27 | // app.WorkdirArg.Ptr(&workdir).Apply(cmd, app.ctx)
28 | //
29 | // cmd.Spec = "[OPTIONS] VERSION [WORKDIR]"
30 | //
31 | // var sm *subscription.SubscribeManager
32 | //
33 | // cmd.Before = func() {
34 | // var err error
35 | // sm, err = plugin.Subscribe("set-version", app.ctx)
36 | //
37 | // if err != nil {
38 | // app.failOnErr(err)
39 | // }
40 | //
41 | // }
42 | //
43 | // cmd.Action = func() {
44 | //
45 | // err := manager2.DoTask(manager2.WriteVersionFile{Workdir: workdir,
46 | // Filename: manager2.VERSION_FILE, Version: setVersion}, sm)
47 | //
48 | // app.failOnErr(err)
49 | //
50 | // if doCommit {
51 | // err = manager2.CommitVersionFile(workdir)
52 | // app.failOnErr(err)
53 | // }
54 | //
55 | // }
56 | // }
57 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/doc.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | //
4 | //type Subscriber struct {
5 | //
6 | // UpdateCfg UpdateCfgSubscriber
7 | // Handlers []interface{}
8 | //
9 | //}
10 | //
11 | //func WithUpdateCfg(u UpdateCfgSubscriber) func(s *Subscriber) {
12 | //
13 | // return func(s *Subscriber) {
14 | // s.UpdateCfg = u
15 | // }
16 | //}
17 | //
18 | //func NSubscriber(handlers... interface{}) Subscriber {
19 | //
20 | // s := Subscriber{
21 | // Handlers: handlers,
22 | // }
23 | // //s.options(opts...)
24 | //
25 | // return s
26 | //
27 | //}
28 | //
29 | //
30 | //func NewSubscriber(opts... func(s *Subscriber)) Subscriber {
31 | //
32 | // s := Subscriber{}
33 | // s.options(opts...)
34 | //
35 | // return s
36 | //
37 | //}
38 | //
39 | //func (s *Subscriber) options(opts... func(s *Subscriber)) {
40 | //
41 | // for _, opt := range opts {
42 | // opt(s)
43 | // }
44 | //
45 | //}
46 | //
47 | //func (s Subscriber) Empty() bool {
48 | //
49 | // return s.UpdateCfg.Empty()
50 | //
51 | //}
52 | //
53 | //type UpdateCfgSubscriber struct {
54 | // On OnUpdateCfgFn
55 | // Start BeforeUpdateCfgFn
56 | // Finish AfterUpdateCfgFn
57 | //}
58 | //
59 | //func (s UpdateCfgSubscriber) Empty() bool {
60 | // return s.On == nil &&
61 | // s.Finish == nil &&
62 | // s.Start == nil
63 | //}
64 | //
65 | //func (s UpdateCfgSubscriber) OnFn(fn OnUpdateCfgFn) UpdateCfgSubscriber {
66 | // s.On = fn
67 | // return s
68 | //}
69 | //
70 | //func (s UpdateCfgSubscriber) BeforeFn(fn BeforeUpdateCfgFn) UpdateCfgSubscriber {
71 | // s.Start = fn
72 | // return s
73 | //}
74 | //
75 | //func (s UpdateCfgSubscriber) AfterFn(fn AfterUpdateCfgFn) UpdateCfgSubscriber {
76 | // s.Finish = fn
77 | // return s
78 | //}
79 |
--------------------------------------------------------------------------------
/pkg/plugin/loader.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "os"
7 | "path/filepath"
8 | "regexp"
9 |
10 | pm "plugin"
11 | )
12 |
13 | const SymbolName = "NewPlugin"
14 |
15 | type PluginsLoader struct {
16 | plugins []Symbol
17 | dir string
18 | loaded bool
19 | }
20 |
21 | func (pl *PluginsLoader) Plugins() []Symbol {
22 | return pl.plugins
23 | }
24 |
25 | func NewPluginsLoader(dir string) *PluginsLoader {
26 |
27 | pl := &PluginsLoader{
28 | dir: dir,
29 | }
30 |
31 | return pl
32 | }
33 |
34 | func (pl *PluginsLoader) LoadPlugins(force bool) error {
35 |
36 | if pl.loaded && !force {
37 | return nil
38 | }
39 |
40 | if _, err := os.Stat(pl.dir); err != nil {
41 | return err
42 | }
43 |
44 | plugins, err := listFiles(pl.dir, `*.so`)
45 | if err != nil {
46 | return err
47 | }
48 |
49 | for _, cmdPlugin := range plugins {
50 | pluginFile, err := pm.Open(filepath.Join(pl.dir, cmdPlugin.Name()))
51 | if err != nil {
52 | fmt.Printf("failed to open pluginFile %s: %v\n", cmdPlugin.Name(), err)
53 | continue
54 | }
55 | pluginSymbol, err := pluginFile.Lookup(SymbolName)
56 | if err != nil {
57 | fmt.Printf("pluginFile %s does not export symbol \"%s\"\n",
58 | cmdPlugin.Name(), SymbolName)
59 | continue
60 | }
61 | pl.plugins = append(pl.plugins, pluginSymbol.(Symbol))
62 |
63 | }
64 |
65 | pl.loaded = true
66 |
67 | return nil
68 | }
69 |
70 | func listFiles(dir, pattern string) ([]os.FileInfo, error) {
71 | files, err := ioutil.ReadDir(dir)
72 | if err != nil {
73 | return nil, err
74 | }
75 |
76 | var filteredFiles []os.FileInfo
77 | for _, file := range files {
78 | if file.IsDir() {
79 | continue
80 | }
81 | matched, err := regexp.MatchString(pattern, file.Name())
82 | if err != nil {
83 | return nil, err
84 | }
85 | if matched {
86 | filteredFiles = append(filteredFiles, file)
87 | }
88 | }
89 | return filteredFiles, nil
90 | }
91 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/updatecfg.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
5 | )
6 |
7 | var _ UpdateCfgHandler = (*updateCfgHandler)(nil)
8 |
9 | type UpdateCfgHandler interface {
10 | SubscribeHandler
11 | Subscribe(sub UpdateCfgSubscriber)
12 | Before(v8end V8Endpoint, workdir string, number int) error
13 | On(v8end V8Endpoint, workdir string, number int, standartHandler *bool) error
14 | After(v8end V8Endpoint, workdir string, number int) error
15 |
16 | BeforeFn(v8end V8Endpoint, workdir string, number int) func() error
17 | }
18 |
19 | type updateCfgHandler struct {
20 | before []BeforeUpdateCfgFn
21 | on []OnUpdateCfgFn
22 | after []AfterUpdateCfgFn
23 | }
24 |
25 | func (h *updateCfgHandler) Count() int {
26 | return len(h.on) + len(h.after) + len(h.before)
27 | }
28 |
29 | func (h *updateCfgHandler) BeforeFn(v8end V8Endpoint, workdir string, number int) func() error {
30 | return func() error {
31 | return h.Before(v8end, workdir, number)
32 | }
33 | }
34 |
35 | func (h *updateCfgHandler) Subscribe(sub UpdateCfgSubscriber) {
36 |
37 | if sub.Before != nil {
38 | h.before = append(h.before, sub.Before)
39 | }
40 |
41 | if sub.On != nil {
42 | h.on = append(h.on, sub.On)
43 | }
44 |
45 | if sub.After != nil {
46 | h.after = append(h.after, sub.After)
47 | }
48 | }
49 |
50 | func (h *updateCfgHandler) Before(v8end V8Endpoint, workdir string, version int) error {
51 |
52 | for _, fn := range h.before {
53 |
54 | err := fn(v8end, workdir, version)
55 |
56 | if err != nil {
57 | return err
58 | }
59 | }
60 |
61 | return nil
62 | }
63 |
64 | func (h *updateCfgHandler) On(v8end V8Endpoint, workdir string, version int, stdHandler *bool) error {
65 |
66 | for _, fn := range h.on {
67 |
68 | err := fn(v8end, workdir, version, stdHandler)
69 |
70 | if err != nil {
71 | return err
72 | }
73 | }
74 |
75 | return nil
76 | }
77 |
78 | func (h *updateCfgHandler) After(v8end V8Endpoint, workdir string, version int) error {
79 |
80 | for _, fn := range h.after {
81 |
82 | err := fn(v8end, workdir, version)
83 |
84 | if err != nil {
85 | return err
86 | }
87 | }
88 |
89 | return nil
90 | }
91 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/dumpConfigToFiles.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
5 | )
6 |
7 | var _ DumpConfigToFilesHandler = (*dumpConfigToFilesHandler)(nil)
8 |
9 | type dumpConfigToFilesHandler struct {
10 | before []BeforeDumpConfigFn
11 | on []OnDumpConfigFn
12 | after []AfterDumpConfigFn
13 | }
14 |
15 | func (h *dumpConfigToFilesHandler) Count() int {
16 | return len(h.on) + len(h.after) + len(h.before)
17 | }
18 |
19 | func (h *dumpConfigToFilesHandler) Subscribe(sub DumpConfigToFilesSubscriber) {
20 |
21 | if sub.Before != nil {
22 | h.before = append(h.before, sub.Before)
23 | }
24 |
25 | if sub.On != nil {
26 | h.on = append(h.on, sub.On)
27 | }
28 |
29 | if sub.After != nil {
30 | h.after = append(h.after, sub.After)
31 | }
32 | }
33 |
34 | type DumpConfigToFilesHandler interface {
35 | SubscribeHandler
36 |
37 | Subscribe(sub DumpConfigToFilesSubscriber)
38 | Before(v8end V8Endpoint, workdir string, temp string, number int, update *bool) error
39 | On(v8end V8Endpoint, workdir string, temp string, number int, update *bool, stdHandler *bool) error
40 | After(v8end V8Endpoint, workdir string, temp string, number int, update bool) error
41 | }
42 |
43 | func (h *dumpConfigToFilesHandler) Before(v8end V8Endpoint, workdir string, temp string, version int, update *bool) error {
44 |
45 | for _, fn := range h.before {
46 |
47 | err := fn(v8end, workdir, temp, version, update)
48 |
49 | if err != nil {
50 | return err
51 | }
52 | }
53 |
54 | return nil
55 | }
56 |
57 | func (h *dumpConfigToFilesHandler) On(v8end V8Endpoint, workdir string, temp string, version int, update *bool, stdHandler *bool) error {
58 |
59 | for _, fn := range h.on {
60 |
61 | err := fn(v8end, workdir, temp, version, update, stdHandler)
62 |
63 | if err != nil {
64 | return err
65 | }
66 | }
67 |
68 | return nil
69 | }
70 |
71 | func (h *dumpConfigToFilesHandler) After(v8end V8Endpoint, workdir string, temp string, version int, update bool) error {
72 |
73 | for _, fn := range h.after {
74 |
75 | err := fn(v8end, workdir, temp, version, update)
76 |
77 | if err != nil {
78 | return err
79 | }
80 | }
81 |
82 | return nil
83 | }
84 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/getRepositoryAuthors.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/internal/manager/types"
5 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
6 | )
7 |
8 | var _ GetRepositoryAuthorsHandler = (*getRepositoryAuthorsHandler)(nil)
9 |
10 | type GetRepositoryAuthorsHandler interface {
11 | SubscribeHandler
12 | Subscribe(sub GetRepositoryAuthorsSubscriber)
13 |
14 | Before(v8end V8Endpoint, workdir string, filename string) error
15 | On(v8end V8Endpoint, workdir string, filename string, stdHandler *bool) (map[string]types.RepositoryAuthor, error)
16 | After(v8end V8Endpoint, workdir string, authors *types.RepositoryAuthorsList) error
17 | }
18 |
19 | type getRepositoryAuthorsHandler struct {
20 | before []BeforeGetRepositoryAuthorsFn
21 | on []OnGetRepositoryAuthorsFn
22 | after []AfterGetRepositoryAuthorsFn
23 | }
24 |
25 | func (h *getRepositoryAuthorsHandler) Count() int {
26 | return len(h.on) + len(h.after) + len(h.before)
27 | }
28 |
29 | func (h *getRepositoryAuthorsHandler) Subscribe(sub GetRepositoryAuthorsSubscriber) {
30 |
31 | if sub.Before != nil {
32 | h.before = append(h.before, sub.Before)
33 | }
34 |
35 | if sub.On != nil {
36 | h.on = append(h.on, sub.On)
37 | }
38 |
39 | if sub.After != nil {
40 | h.after = append(h.after, sub.After)
41 | }
42 | }
43 |
44 | func (h *getRepositoryAuthorsHandler) Before(v8end V8Endpoint, workdir string, filename string) error {
45 |
46 | for _, fn := range h.before {
47 |
48 | err := fn(v8end, workdir, filename)
49 |
50 | if err != nil {
51 | return err
52 | }
53 | }
54 |
55 | return nil
56 | }
57 |
58 | func (h *getRepositoryAuthorsHandler) On(v8end V8Endpoint, workdir string, filename string, stdHandler *bool) (map[string]types.RepositoryAuthor, error) {
59 |
60 | for _, fn := range h.on {
61 |
62 | rv, err := fn(v8end, workdir, filename, stdHandler)
63 |
64 | if err != nil {
65 | return rv, err
66 | }
67 | }
68 |
69 | return map[string]types.RepositoryAuthor{}, nil
70 | }
71 |
72 | func (h *getRepositoryAuthorsHandler) After(v8end V8Endpoint, workdir string, authors *types.RepositoryAuthorsList) error {
73 |
74 | for _, fn := range h.after {
75 |
76 | err := fn(v8end, workdir, authors)
77 |
78 | if err != nil {
79 | return err
80 | }
81 | }
82 |
83 | return nil
84 | }
85 |
--------------------------------------------------------------------------------
/pkg/plugin/manager.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | import (
4 | "github.com/duke-git/lancet/slice"
5 | "github.com/elastic/go-ucfg"
6 | "github.com/khorevaa/logos"
7 | "github.com/khorevaa/r2gitsync/pkg/plugin/subscription"
8 | "github.com/urfave/cli/v2"
9 | )
10 |
11 | var log = logos.New("github.com/khorevaa/r2gitsync/pkg/plugin")
12 |
13 | type manager struct {
14 | plugins map[string]Symbol
15 | pluginsConfig map[string]*ucfg.Config
16 | }
17 |
18 | type Manager interface {
19 | Flags(module string) []cli.Flag
20 | Subscriber(module string) (*subscription.SubscribeManager, error)
21 | }
22 |
23 | func NewPluginManager(cfg map[string]*ucfg.Config) Manager {
24 | m := &manager{
25 | plugins: map[string]Symbol{},
26 | pluginsConfig: map[string]*ucfg.Config{},
27 | }
28 | for name, config := range cfg {
29 | if symbol, ok := plugins[name]; ok {
30 | m.plugins[name] = symbol
31 | m.pluginsConfig[name] = config
32 | }
33 | }
34 |
35 | return m
36 | }
37 |
38 | func (m *manager) Flags(module string) []cli.Flag {
39 | var flags []cli.Flag
40 | log.Info("Получаю дополните флаги",
41 | logos.String("module", module))
42 |
43 | for _, symbol := range m.plugins {
44 | if !slice.Contain(symbol.Modules, module) {
45 | continue
46 | }
47 |
48 | flags = append(flags, symbol.Flags...)
49 | }
50 | log.Info("Получены дополнительные флаги",
51 | logos.String("module", module),
52 | logos.Int("количество", len(flags)))
53 |
54 | return flags
55 | }
56 |
57 | func (m *manager) Subscriber(module string) (*subscription.SubscribeManager, error) {
58 |
59 | log.Info("Получаю подписчиков",
60 | logos.String("module", module),
61 | logos.String("method", "Subscriber"))
62 |
63 | sm := subscription.NewSubscribeManager()
64 |
65 | var pList []string
66 |
67 | for _, symbol := range m.plugins {
68 | if !slice.Contain(symbol.Modules, module) {
69 | continue
70 | }
71 | cfg := m.pluginsConfig[symbol.Name]
72 | pl, err := symbol.New(cfg)
73 | if err != nil {
74 | return nil, err
75 | }
76 |
77 | sm.Subscribe(pl.Subscribe())
78 | pList = append(pList, symbol.Name)
79 | }
80 |
81 | log.Info("Получено подписчиков",
82 | logos.String("module", module),
83 | logos.Any("плагины", pList),
84 | logos.Int("количество", sm.Count()),
85 | logos.String("method", "Subscriber"))
86 |
87 | return sm, nil
88 | }
89 |
--------------------------------------------------------------------------------
/features/cmd/setVersion.feature:
--------------------------------------------------------------------------------
1 | # language: ru
2 |
3 | Функционал: Установка версии в файл версий (команды set-version)
4 | Как Пользователь
5 | Я хочу выполнять автоматическую установку последней синхронизированной версии с хранилищем 1С
6 | Чтобы автоматизировать свою работы с хранилищем с git
7 |
8 | Контекст: Тестовый контекст set-version
9 | Когда Я создаю временный каталог и сохраняю его в переменной "ПутьКаталогаИсходников"
10 | И Я инициализирую репозиторий в каталоге из переменной "ПутьКаталогаИсходников"
11 | И Я создаю тестовой файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" с текстом:
12 | """
13 |
14 | 0
15 | """
16 | И Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
17 |
18 | Сценарий: Установка версии без коммита
19 | Допустим Я добавляю параметр "--debug"
20 | И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
21 | И Я добавляю параметр "set-version"
22 | И Я добавляю параметр "10"
23 | И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
24 | Когда Я выполняю приложение
25 | Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "10"
26 |
27 | Сценарий: Установка версии с коммитом
28 | Допустим Я добавляю параметр "--debug"
29 | И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
30 | И Я добавляю параметр "set-version"
31 | И Я добавляю параметр "-c"
32 | И Я добавляю параметр "5"
33 | И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
34 | Когда Я выполняю приложение
35 | Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "5"
36 |
37 | Сценарий: Установка версии с использованием переменных окружения
38 | Допустим Я добавляю параметр "--debug"
39 | И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
40 | И Я добавляю параметр "set-version"
41 | И Я добавляю параметр "1"
42 | И Я устанавливаю переменную окружения "GITSYNC_WORKDIR" из переменной "ПутьКаталогаИсходников"
43 | Когда Я выполняю приложение
44 | Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "1"
45 | И Я очищаю значение переменных окружения
46 | |GITSYNC_WORKDIR|
--------------------------------------------------------------------------------
/pkg/plugin/subscription/commitFiles.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/khorevaa/r2gitsync/internal/manager/types"
7 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
8 | )
9 |
10 | var _ CommitFilesHandler = (*commitFilesHandler)(nil)
11 |
12 | type CommitFilesHandler interface {
13 | SubscribeHandler
14 |
15 | Subscribe(sub CommitFilesSubscriber)
16 |
17 | Before(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when time.Time, comment string) error
18 | On(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when *time.Time, comment *string, stdHandler *bool) error
19 | After(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when time.Time, comment string) error
20 | }
21 |
22 | type commitFilesHandler struct {
23 | before []BeforeCommitFilesFn
24 | on []OnCommitFilesFn
25 | after []AfterCommitFilesFn
26 | }
27 |
28 | func (h *commitFilesHandler) Count() int {
29 | return len(h.on) + len(h.after) + len(h.before)
30 | }
31 |
32 | func (h *commitFilesHandler) Subscribe(sub CommitFilesSubscriber) {
33 |
34 | if sub.Before != nil {
35 | h.before = append(h.before, sub.Before)
36 | }
37 |
38 | if sub.On != nil {
39 | h.on = append(h.on, sub.On)
40 | }
41 |
42 | if sub.After != nil {
43 | h.after = append(h.after, sub.After)
44 | }
45 | }
46 |
47 | func (h *commitFilesHandler) Before(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when time.Time, comment string) error {
48 |
49 | for _, fn := range h.before {
50 |
51 | err := fn(v8end, workdir, author, when, comment)
52 |
53 | if err != nil {
54 | return err
55 | }
56 | }
57 |
58 | return nil
59 | }
60 |
61 | func (h *commitFilesHandler) On(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when *time.Time, comment *string, stdHandler *bool) error {
62 |
63 | for _, fn := range h.on {
64 |
65 | err := fn(v8end, workdir, author, when, comment, stdHandler)
66 |
67 | if err != nil {
68 | return err
69 | }
70 | }
71 |
72 | return nil
73 | }
74 |
75 | func (h *commitFilesHandler) After(v8end V8Endpoint, workdir string, author types.RepositoryAuthor, when time.Time, comment string) error {
76 |
77 | for _, fn := range h.after {
78 |
79 | err := fn(v8end, workdir, author, when, comment)
80 |
81 | if err != nil {
82 | return err
83 | }
84 | }
85 |
86 | return nil
87 | }
88 |
--------------------------------------------------------------------------------
/internal/manager/git.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | "github.com/go-git/go-git/v5"
5 | "github.com/go-git/go-git/v5/plumbing/object"
6 | "github.com/khorevaa/r2gitsync/internal/manager/types"
7 | "path/filepath"
8 | "time"
9 | )
10 |
11 | const (
12 | VERSION_FILE = "VERSION"
13 | AUTHORS_FILE = "AUTHORS"
14 | )
15 |
16 | func CommitVersionFile(workdir string) error {
17 |
18 | r, err := git.PlainOpen(workdir)
19 |
20 | if err != nil {
21 | return err
22 | }
23 |
24 | filename := filepath.Join(workdir, VERSION_FILE)
25 |
26 | w, err := r.Worktree()
27 |
28 | if err != nil {
29 | return err
30 | }
31 |
32 | w.Add(filename)
33 | c, err := w.Commit("Изменена версия в файле VERSION", &git.CommitOptions{})
34 |
35 | if err != nil {
36 | return err
37 | }
38 |
39 | _, err = r.CommitObject(c)
40 |
41 | return err
42 | }
43 |
44 | func commitFile(filename string, msg string, opts *git.CommitOptions) error {
45 |
46 | dir := filepath.Dir(filename)
47 |
48 | r, err := git.PlainOpen(dir)
49 |
50 | if err != nil {
51 | return err
52 | }
53 |
54 | //filename := filepath.Join(workdir, VERSION_FILE)
55 |
56 | w, err := r.Worktree()
57 |
58 | if err != nil {
59 | return err
60 | }
61 |
62 | if opts == nil {
63 | opts = &git.CommitOptions{}
64 | }
65 |
66 | w.Add(filename)
67 | c, err := w.Commit(msg, opts)
68 |
69 | if err != nil {
70 | return err
71 | }
72 |
73 | _, err = r.CommitObject(c)
74 |
75 | return err
76 | }
77 |
78 | func commitFiles(dir string, author types.RepositoryAuthor, when time.Time, comment string) error {
79 |
80 | g, err := git.PlainOpen(dir)
81 |
82 | if err != nil {
83 | return err
84 | }
85 |
86 | w, err := g.Worktree()
87 |
88 | if err != nil {
89 | return err
90 | }
91 |
92 | err = w.RemoveGlob(".")
93 |
94 | if err != nil {
95 | return err
96 | }
97 |
98 | //pattern := "**/!(*.git)*.*"
99 | err = w.AddGlob(".")
100 |
101 | if err != nil {
102 | return err
103 | }
104 |
105 | c, err := w.Commit(comment, &git.CommitOptions{
106 | All: true,
107 | Author: &object.Signature{
108 | Name: author.Name(),
109 | Email: author.Email(),
110 | When: when,
111 | },
112 | })
113 |
114 | if err != nil {
115 | return err
116 | }
117 |
118 | _, err = g.CommitObject(c)
119 |
120 | return err
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/sync.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
5 | )
6 |
7 | type SyncProcessHandler interface {
8 | SubscribeHandler
9 | Subscribe(sub SyncProcessSubscriber)
10 |
11 | Start(v8end V8Endpoint, dir string)
12 | Finish(v8end V8Endpoint, dir string, err *error)
13 | }
14 |
15 | var _ SyncProcessHandler = (*syncProcessHandler)(nil)
16 |
17 | type syncProcessHandler struct {
18 | start []StartSyncProcessFn
19 | finish []FinishSyncProcessFn
20 | }
21 |
22 | func (h *syncProcessHandler) Count() int {
23 | return len(h.start) + len(h.finish)
24 | }
25 |
26 | func (h *syncProcessHandler) Subscribe(sub SyncProcessSubscriber) {
27 |
28 | if sub.Start != nil {
29 | h.start = append(h.start, sub.Start)
30 | }
31 |
32 | if sub.Finish != nil {
33 | h.finish = append(h.finish, sub.Finish)
34 | }
35 | }
36 |
37 | func (h *syncProcessHandler) Start(v8end V8Endpoint, dir string) {
38 |
39 | for _, fn := range h.start {
40 |
41 | fn(v8end, dir)
42 | }
43 | }
44 |
45 | func (h *syncProcessHandler) Finish(v8end V8Endpoint, dir string, err *error) {
46 |
47 | for _, fn := range h.finish {
48 |
49 | fn(v8end, dir, err)
50 | }
51 |
52 | }
53 |
54 | type SyncVersionHandler interface {
55 | SubscribeHandler
56 | Subscribe(sub SyncVersionSubscriber)
57 |
58 | Start(v8end V8Endpoint, dir, temp string, number int)
59 | Finish(v8end V8Endpoint, dir, temp string, number int, err *error)
60 | }
61 |
62 | var _ SyncVersionHandler = (*syncversionHandler)(nil)
63 |
64 | type syncversionHandler struct {
65 | start []StartSyncVersionFn
66 | finish []FinishSyncVersionFn
67 | }
68 |
69 | func (h *syncversionHandler) Count() int {
70 | return len(h.start) + len(h.finish)
71 | }
72 |
73 | func (h *syncversionHandler) Subscribe(sub SyncVersionSubscriber) {
74 |
75 | if sub.Start != nil {
76 | h.start = append(h.start, sub.Start)
77 | }
78 |
79 | if sub.Finish != nil {
80 | h.finish = append(h.finish, sub.Finish)
81 | }
82 | }
83 |
84 | func (h *syncversionHandler) Start(v8end V8Endpoint, dir, temp string, number int) {
85 |
86 | for _, fn := range h.start {
87 |
88 | fn(v8end, dir, temp, number)
89 | }
90 | }
91 |
92 | func (h *syncversionHandler) Finish(v8end V8Endpoint, dir, temp string, number int, err *error) {
93 |
94 | for _, fn := range h.finish {
95 |
96 | fn(v8end, dir, temp, number, err)
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/internal/commands/cmdInit.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | //
4 | // import (
5 | // cli "github.com/jawher/mow.cli"
6 | // "github.com/khorevaa/r2gitsync/internal/app"
7 | // flags2 "github.com/khorevaa/r2gitsync/internal/app/flags"
8 | // "github.com/khorevaa/r2gitsync/internal/log"
9 | // manager2 "github.com/khorevaa/r2gitsync/internal/manager"
10 | // "github.com/khorevaa/r2gitsync/pkg/plugin"
11 | // )
12 | //
13 | // func (app *app.Application) cmdInit(cmd *cli.Cmd) {
14 | //
15 | // var force bool
16 | //
17 | // cmd.LongDesc = `Инициализация структуры нового хранилища git. Подготовка к синхронизации`
18 | //
19 | // repo := manager2.SyncRepository{}
20 | //
21 | // flags2.StringOpt("storage-author u", "Администратор", "пользователь хранилища 1C конфигурации").
22 | // Env("R2GITSYNC_STORAGE_USER GITSYNC_STORAGE_USER").
23 | // Ptr(&repo.Repository.User).
24 | // Apply(cmd, app.ctx)
25 | //
26 | // flags2.StringOpt("storage-pwd p", "", "пользователь хранилища 1C конфигурации").
27 | // Env("R2GITSYNC_STORAGE_PASSWORD GITSYNC_STORAGE_PWD GITSYNC_STORAGE_PASSWORD").
28 | // Ptr(&repo.Repository.Password).
29 | // Apply(cmd, app.ctx)
30 | //
31 | // flags2.StringOpt("extension e ext", "", "имя расширения для работы с хранилищем расширения").
32 | // Env("R2GITSYNC_EXTENSION GITSYNC_EXTENSION").
33 | // Ptr(&repo.Extension).
34 | // Apply(cmd, app.ctx)
35 | //
36 | // flags2.BoolOpt("f force", false, "принудительноя инициализация, игнорирование ошибок").
37 | // Ptr(&force).
38 | // Apply(cmd, app.ctx)
39 | //
40 | // flags2.StringArg("PATH", "", "Путь к хранилищу конфигурации 1С.").
41 | // Env("R2GITSYNC_STORAGE_PATH GITSYNC_STORAGE_PATH").
42 | // Ptr(&repo.Repository.Path).
43 | // Apply(cmd, app.ctx)
44 | //
45 | // app.WorkdirArg.Ptr(&repo.Workdir).Apply(cmd, app.ctx)
46 | //
47 | // cmd.Spec = "[OPTIONS] PATH [WORKDIR]"
48 | //
49 | // var syncOptions *manager2.Options
50 | // cmd.Before = func() {
51 | //
52 | // sm, err := plugin.Subscribe("init", app.ctx)
53 | //
54 | // if err != nil {
55 | // app.failOnErr(err)
56 | // }
57 | //
58 | // logger := log.Named("cmd")
59 | // newOptions := *app.config.Options
60 | // syncOptions = &newOptions
61 | // syncOptions.Logger = logger
62 | // syncOptions.Plugins = sm
63 | // syncOptions.LicTryCount = 5
64 | //
65 | // }
66 | // cmd.Action = func() {
67 | //
68 | // err := manager2.Init(repo, *syncOptions)
69 | //
70 | // app.failOnErr(err)
71 | //
72 | // }
73 | //
74 | // plugin.RegistryFlags("init", cmd, app.ctx)
75 | //
76 | // }
77 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/subscription.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | "sync"
5 |
6 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
7 | )
8 |
9 | type SubscribeManager struct {
10 | mu sync.Mutex
11 | UpdateCfg UpdateCfgHandler
12 | DumpConfigToFiles DumpConfigToFilesHandler
13 | GetRepositoryHistory GetRepositoryHistoryHandler
14 | ConfigureRepositoryVersions ConfigureRepositoryVersionsHandler
15 | GetRepositoryAuthors GetRepositoryAuthorsHandler
16 | SyncVersion SyncVersionHandler
17 | SyncProcess SyncProcessHandler
18 | CommitFiles CommitFilesHandler
19 | ReadVersionFile ReadVersionFileHandler
20 | WriteVersionFile WriteVersionFileHandler
21 | ClearWorkdir ClearWorkdirHandler
22 | MoveToWorkdir MoveToWorkdirHandler
23 | subscribers []Plugin
24 | count int
25 | }
26 |
27 | func (sm *SubscribeManager) Count() int {
28 | return sm.UpdateCfg.Count() +
29 | sm.DumpConfigToFiles.Count() +
30 | sm.GetRepositoryHistory.Count() +
31 | sm.ConfigureRepositoryVersions.Count() +
32 | sm.GetRepositoryAuthors.Count() +
33 | sm.SyncVersion.Count() +
34 | sm.SyncProcess.Count() +
35 | sm.CommitFiles.Count() +
36 | sm.ReadVersionFile.Count() +
37 | sm.WriteVersionFile.Count() +
38 | sm.ClearWorkdir.Count() +
39 | sm.MoveToWorkdir.Count()
40 | }
41 | func (sm *SubscribeManager) Subscribe(sub Subscriber) {
42 |
43 | handlers := sub.Handlers()
44 |
45 | for _, handler := range handlers {
46 |
47 | switch h := handler.(type) {
48 | case UpdateCfgSubscriber:
49 | sm.UpdateCfg.Subscribe(h)
50 | case DumpConfigToFilesSubscriber:
51 | sm.DumpConfigToFiles.Subscribe(h)
52 | case GetRepositoryHistorySubscriber:
53 | sm.GetRepositoryHistory.Subscribe(h)
54 | case GetRepositoryAuthorsSubscriber:
55 | sm.GetRepositoryAuthors.Subscribe(h)
56 | case ConfigureRepositoryVersionsSubscriber:
57 | sm.ConfigureRepositoryVersions.Subscribe(h)
58 | case SyncVersionSubscriber:
59 | sm.SyncVersion.Subscribe(h)
60 | case SyncProcessSubscriber:
61 | sm.SyncProcess.Subscribe(h)
62 | case CommitFilesSubscriber:
63 | sm.CommitFiles.Subscribe(h)
64 | case ReadVersionFileSubscriber:
65 | sm.ReadVersionFile.Subscribe(h)
66 | case WriteVersionFileSubscriber:
67 | sm.WriteVersionFile.Subscribe(h)
68 | case ClearWorkdirSubscriber:
69 | sm.ClearWorkdir.Subscribe(h)
70 | case MoveToWorkdirSubscriber:
71 | sm.MoveToWorkdir.Subscribe(h)
72 | }
73 |
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project_name: r2gitsync
4 |
5 | env:
6 | - GO111MODULE=on
7 | # - GOPROXY=https://goproxy.io
8 | before:
9 | hooks:
10 | - go mod tidy
11 | - go get -u github.com/go-bindata/go-bindata/...
12 | - go-bindata -pkg manager -o ./manager/bindata.go -prefix bin/ ./bin
13 | builds:
14 | - env:
15 | - CGO_ENABLED=0
16 | goos:
17 | - linux
18 | - darwin
19 | - windows
20 | goarch:
21 | # - 386
22 | - amd64
23 | # - arm
24 | # - arm64
25 | dist: dist
26 |
27 | checksum:
28 | name_template: '{{ .ProjectName }}_checksums.txt'
29 | changelog:
30 | sort: asc
31 | filters:
32 | exclude:
33 | - '^docs:'
34 | - '^test:'
35 | - Merge pull request
36 | - Merge branch
37 | #dockers:
38 | # - image_templates:
39 | # - 'goreleaser/goreleaser:{{ .Tag }}-cgo'
40 | # - 'goreleaser/goreleaser:v{{ .Major }}.{{ .Minor }}-cgo'
41 | # - 'goreleaser/goreleaser:latest-cgo'
42 | # dockerfile: Dockerfile.cgo
43 | # binaries:
44 | # - goreleaser
45 | # build_flag_templates:
46 | # - "--label=org.label-schema.schema-version=1.0"
47 | # - "--label=org.label-schema.version={{.Version}}"
48 | # - "--label=org.label-schema.name={{.ProjectName}}"
49 | # extra_files:
50 | # - scripts/entrypoint.sh
51 | # - image_templates:
52 | # - 'goreleaser/goreleaser:{{ .Tag }}'
53 | # - 'goreleaser/goreleaser:v{{ .Major }}.{{ .Minor }}'
54 | # - 'goreleaser/goreleaser:latest'
55 | # dockerfile: Dockerfile
56 | # binaries:
57 | # - goreleaser
58 | # build_flag_templates:
59 | # - "--label=org.label-schema.schema-version=1.0"
60 | # - "--label=org.label-schema.version={{.Version}}"
61 | # - "--label=org.label-schema.name={{.ProjectName}}"
62 | # - "--label=com.github.actions.name={{.ProjectName}}"
63 | # - "--label=com.github.actions.description=Deliver Go binaries as fast and easily as possible"
64 | # - "--label=com.github.actions.icon=terminal"
65 | # - "--label=com.github.actions.color=blue"
66 | # - "--label=repository=http://github.com/goreleaser/goreleaser"
67 | # - "--label=homepage=http://goreleaser.com"
68 | # - "--label=maintainer=Carlos Becker "
69 | #
70 | # extra_files:
71 | # - scripts/entrypoint.sh
72 | archives:
73 | - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
74 | replacements:
75 | darwin: Darwin
76 | linux: Linux
77 | windows: Windows
78 | 386: i386
79 | amd64: x86_64
80 | format_overrides:
81 | - goos: windows
82 | format: zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # r2gitsync
2 | Sync 1C repository to git. Written on golang
3 |
4 | [](https://github.com/v8platform/oneget/releases/latest)
5 | [](/LICENSE.md)
6 | [](https://github.com/v8platform/oneget/actions?workflow=goreleaser)
7 | [](https://codecov.io/gh/v8platform/oneget)
8 | [](http://godoc.org/github.com/v8platform/oneget)
9 | [](https://saythanks.io/to/khorevaa)
10 | [](https://github.com/goreleaser)
11 | [](https://conventionalcommits.org)
12 |
13 |
14 | ## Запуск в докере
15 |
16 | ```shell
17 | docker run -v $(pwd):/tmp/dist demoncat/oneget \
18 | --user $ONEC_USERNAME \
19 | --pwd $ONEC_PASSWORD \
20 | --path /tmp/dist/ \
21 | --nicks platform83 \
22 | --version-filter 8.3.16.1876 \
23 | --distrib-filter 'deb64.tar.gz$'
24 | ```
25 |
26 | ## Настройка логов
27 |
28 | ### Через файл настройки
29 | Создать рядом с приложением файл `logos.yaml` с содержимым
30 |
31 | ```yaml
32 | appenders:
33 | console:
34 | - name: CONSOLE
35 | target: stdout
36 | encoder:
37 | console:
38 |
39 | rolling_file:
40 | - name: FILE
41 | file_name: ./logs/oneget.log
42 | max_size: 100
43 | max_age: 10
44 | encoder:
45 | json:
46 | loggers:
47 | root:
48 | level: info
49 | appender_refs:
50 | - CONSOLE
51 | logger:
52 | - name: "github.com/v8platform/oneget"
53 | appender_refs:
54 | - CONSOLE
55 | - FILE
56 | level: debug
57 |
58 | ```
59 |
60 | ### Через переменные окружения
61 | ```shell
62 | export LOGOS_CONFIG="appenders.rolling_file.0.name=FILE;
63 | appenders.rolling_file.0.file_name=./logs/oneget.log;
64 | appenders.rolling_file.0.max_size=100;
65 | appenders.rolling_file.0.encoder.json;
66 | loggers.logger.0.level=debug;
67 | loggers.logger.0.name=github.com/v8platform/oneget;
68 | loggers.logger.0.appender_refs.0=CONSOLE;
69 | loggers.logger.0.appender_refs.1=FILE;"
70 | ```
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/khorevaa/r2gitsync
2 |
3 | go 1.17
4 |
5 | require (
6 | github.com/cucumber/godog v0.10.0
7 | github.com/duke-git/lancet v1.1.8
8 | github.com/elastic/go-ucfg v0.8.3
9 | github.com/go-git/go-git/v5 v5.1.0
10 | github.com/hashicorp/go-multierror v1.1.0
11 | github.com/jawher/mow.cli v1.2.0
12 | github.com/khorevaa/logos v0.9.8
13 | github.com/lithammer/shortuuid/v3 v3.0.4
14 | github.com/mitchellh/go-homedir v1.1.0
15 | github.com/urfave/cli/v2 v2.3.0
16 | github.com/v8platform/api v0.2.2
17 | github.com/v8platform/designer v0.2.2
18 | golang.org/x/text v0.3.3
19 |
20 | )
21 |
22 | require (
23 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
24 | github.com/cucumber/gherkin-go/v11 v11.0.0 // indirect
25 | github.com/cucumber/messages-go/v10 v10.0.3 // indirect
26 | github.com/davecgh/go-spew v1.1.1 // indirect
27 | github.com/emirpasic/gods v1.12.0 // indirect
28 | github.com/go-git/gcfg v1.5.0 // indirect
29 | github.com/go-git/go-billy/v5 v5.0.0 // indirect
30 | github.com/gofrs/uuid v3.2.0+incompatible // indirect
31 | github.com/gogo/protobuf v1.3.1 // indirect
32 | github.com/google/uuid v1.1.1 // indirect
33 | github.com/hashicorp/errwrap v1.0.0 // indirect
34 | github.com/hashicorp/go-immutable-radix v1.2.0 // indirect
35 | github.com/hashicorp/go-memdb v1.2.1 // indirect
36 | github.com/hashicorp/golang-lru v0.5.4 // indirect
37 | github.com/imdario/mergo v0.3.9 // indirect
38 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
39 | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
40 | github.com/mattn/go-colorable v0.1.8 // indirect
41 | github.com/mattn/go-isatty v0.0.12 // indirect
42 | github.com/pkg/errors v0.9.1 // indirect
43 | github.com/pmezard/go-difflib v1.0.0 // indirect
44 | github.com/russross/blackfriday/v2 v2.0.1 // indirect
45 | github.com/sergi/go-diff v1.1.0 // indirect
46 | github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
47 | github.com/stretchr/testify v1.6.1 // indirect
48 | github.com/v8platform/enterprise v0.1.0 // indirect
49 | github.com/v8platform/errors v0.1.0 // indirect
50 | github.com/v8platform/find v0.0.0-20200629131701-72a40bdf1034 // indirect
51 | github.com/v8platform/marshaler v0.1.1 // indirect
52 | github.com/v8platform/runner v0.3.1 // indirect
53 | github.com/xanzy/ssh-agent v0.2.1 // indirect
54 | go.uber.org/atomic v1.6.0 // indirect
55 | go.uber.org/multierr v1.5.0 // indirect
56 | go.uber.org/zap v1.16.0 // indirect
57 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
58 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
59 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
60 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
61 | gopkg.in/warnings.v0 v0.1.2 // indirect
62 | gopkg.in/yaml.v2 v2.2.8 // indirect
63 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
64 | )
65 |
--------------------------------------------------------------------------------
/internal/commands/shared_test.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | //
4 | // import (
5 | // "errors"
6 | // "fmt"
7 | // "github.com/cucumber/godog"
8 | // "github.com/cucumber/messages-go/v10"
9 | // "github.com/khorevaa/r2gitsync/pkg/context"
10 | // "strings"
11 | // )
12 | //
13 | // func (c *AppTestSuite) RunApp() (err error) {
14 | //
15 | // defer func() {
16 | // if r := recover(); r != nil {
17 | //
18 | // switch e := r.(type) {
19 | //
20 | // case string:
21 | // err = errors.New(e)
22 | // case error:
23 | // err = e
24 | // if err != nil && strings.Contains(err.Error(), "incorrect usage") {
25 | //
26 | // err = errors.New(fmt.Sprintf("%s: %s", err.Error(), strings.Join(c.Args, " ")))
27 | // }
28 | // }
29 | //
30 | // }
31 | // }()
32 | //
33 | // err = c.Run(c.Args)
34 | //
35 | // return err
36 | // }
37 | //
38 | // func (c *AppTestSuite) RunAppWithErr(errStr *messages.PickleStepArgument_PickleDocString) (err error) {
39 | //
40 | // err = c.RunApp()
41 | // data := errStr.GetContent()
42 | // if err != nil && strings.Contains(err.Error(), data) {
43 | // return nil
44 | // }
45 | //
46 | // return errors.New("не обнаружена искомая ошибка выполнения")
47 | // }
48 | //
49 | // type AppTestSuite struct {
50 | // *Application
51 | // context.Context
52 | //
53 | // Args []string
54 | // }
55 | //
56 | // func SharedAppSteps(sharedContext context.Context, ctx *godog.ScenarioContext) *AppTestSuite {
57 | //
58 | // step := &AppTestSuite{
59 | // Application: NewApp("dev", false),
60 | // Context: sharedContext,
61 | // }
62 | //
63 | // ctx.Step(`^Я выполняю приложение$`, step.RunApp)
64 | // ctx.Step(`^Я выполняю приложение c ошибкой:$`, step.RunAppWithErr)
65 | // ctx.Step(`^Я добавляю параметр "([^"]*)" из переменной "([^"]*)"$`, step.AddArgNamedFromContext)
66 | // ctx.Step(`^Я добавляю параметр "([^"]*)"$`, step.AddArg)
67 | // ctx.Step(`^Я добавляю параметр из переменной "([^"]*)"$`, step.AddArgFromContext)
68 | // ctx.Step(`^Я добавляю параметр без равно "([^"]*)" из переменной "([^"]*)"$`, step.AddArgNamedFromContextWithOutSep)
69 | //
70 | // return step
71 | //
72 | // }
73 | //
74 | // func (c *AppTestSuite) AddArgNamedFromContext(arg, name string) error {
75 | //
76 | // value := c.String(name)
77 | //
78 | // c.Args = append(c.Args, fmt.Sprintf("%s=%s", arg, value))
79 | //
80 | // return nil
81 | // }
82 | //
83 | // func (c *AppTestSuite) AddArgNamedFromContextWithOutSep(arg, name string) error {
84 | //
85 | // value := c.String(name)
86 | //
87 | // c.Args = append(c.Args, fmt.Sprintf("%s%s", arg, value))
88 | //
89 | // return nil
90 | // }
91 | //
92 | // func (c *AppTestSuite) AddArg(arg1 string) error {
93 | //
94 | // c.Args = append(c.Args, arg1)
95 | // return nil
96 | //
97 | // }
98 | //
99 | // func (c *AppTestSuite) AddArgFromContext(name string) error {
100 | //
101 | // value := c.String(name)
102 | //
103 | // c.Args = append(c.Args, value)
104 | //
105 | // return nil
106 | // }
107 |
--------------------------------------------------------------------------------
/internal/plugins/limit/limit.go:
--------------------------------------------------------------------------------
1 | package limit
2 |
3 | import (
4 | "github.com/elastic/go-ucfg"
5 | "github.com/khorevaa/r2gitsync/internal/manager/types"
6 | "github.com/khorevaa/r2gitsync/pkg/plugin"
7 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
8 | "github.com/urfave/cli/v2"
9 | "math"
10 | )
11 |
12 | var (
13 | version = "dev"
14 | commit = ""
15 | )
16 |
17 | type Config struct {
18 | Limit *uint
19 | MinVersion *uint
20 | MaxVersion *uint
21 | }
22 |
23 | var defaultConfig = Config{}
24 | var flagsConfig = Config{}
25 |
26 | func New(cfg *ucfg.Config) (plugin.Plugin, error) {
27 |
28 | config := defaultConfig
29 |
30 | err := cfg.Unpack(&config)
31 | if err != nil {
32 | return nil, err
33 | }
34 |
35 | // TODO Сделать слияние конфигов
36 |
37 | return &Plugin{
38 | limit: config.Limit,
39 | minVersion: config.MinVersion,
40 | maxVersion: config.MaxVersion,
41 | }, nil
42 | }
43 |
44 | //goland:noinspection ALL
45 | var Symbol = plugin.Symbol{
46 | "limit",
47 | plugin.BuildVersion(version, commit),
48 | "Плагин добавляет возможность органичений при выгрузке конфигурации",
49 | New,
50 | []string{"sync"},
51 | []cli.Flag{
52 | &cli.UintFlag{
53 | Name: "limit",
54 | Usage: "выгрузить не более <Количества> версий от текущей выгруженной",
55 | EnvVars: []string{"GITSYNC_LIMIT"},
56 | Destination: flagsConfig.Limit,
57 | },
58 | &cli.UintFlag{
59 | Name: "min-version",
60 | Usage: "в<номер> минимальной версии для выгрузки",
61 | EnvVars: []string{"GITSYNC_MIN_VERSION"},
62 | Destination: flagsConfig.MinVersion,
63 | },
64 | &cli.UintFlag{
65 | Name: "maxVersion",
66 | Usage: "<номер> максимальной версии для выгрузки",
67 | EnvVars: []string{"GITSYNC_MAX_VERSION"},
68 | Destination: flagsConfig.MaxVersion,
69 | },
70 | }}
71 |
72 | type Plugin struct {
73 | limit *uint
74 | minVersion *uint
75 | maxVersion *uint
76 | }
77 |
78 | func (t *Plugin) Subscribe() Subscriber {
79 |
80 | return plugin.Subscription(
81 | ConfigureRepositoryVersionsSubscriber{
82 | On: t.ConfigureRepositoryVersions,
83 | })
84 |
85 | }
86 |
87 | func (t *Plugin) ConfigureRepositoryVersions(end V8Endpoint, versions *types.RepositoryVersionsList, Current, Next, Max *int) error {
88 |
89 | ls := *versions
90 |
91 | if len(ls) == 0 {
92 | return nil
93 | }
94 |
95 | if *t.minVersion > 0 {
96 | *Next = int(*t.minVersion)
97 | }
98 |
99 | if *t.limit > 0 {
100 |
101 | startVersion := math.Max(float64(*Next), float64(*Current))
102 |
103 | limitVersion := startVersion + float64(*t.limit) - 1 // -1, для того чтобы учесть следующую версию она всегда на 1 больше текущей
104 | *Max = int(limitVersion)
105 |
106 | }
107 |
108 | if *t.maxVersion > 0 {
109 | if *t.limit > 0 {
110 | *Max = int(math.Min(float64(*Max), float64(*t.maxVersion)))
111 | } else {
112 | *Max = int(*t.maxVersion)
113 | }
114 |
115 | }
116 |
117 | return nil
118 | }
119 |
--------------------------------------------------------------------------------
/internal/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "os"
7 | "path/filepath"
8 |
9 | "github.com/elastic/go-ucfg"
10 | "github.com/elastic/go-ucfg/yaml"
11 | )
12 |
13 | func DefaultConfig() *Config {
14 | rawConfig, err := yaml.NewConfig([]byte(defaultConfig))
15 | if err != nil {
16 | panic(err)
17 | }
18 |
19 | cfg := &Config{}
20 |
21 | if err := rawConfig.Unpack(cfg); err != nil {
22 | panic(err)
23 | }
24 |
25 | return cfg
26 | }
27 |
28 | const defaultConfig = `
29 | v8version: 8.3
30 | `
31 |
32 | type Config struct {
33 | WorkDir string `config:"workdir"`
34 | TempDir string `config:"tempdir"`
35 | V8version string `config:"v8version"`
36 | V8Path string `config:"v8path"`
37 | Storage StorageConfig `config:"storage"`
38 | Infobase *InfobaseConfig `config:"infobase"`
39 | Plugins map[string]*ucfg.Config `config:"plugins"`
40 |
41 | Debug bool `config:"debug"`
42 | }
43 |
44 | type StorageConfig struct {
45 | Path string `config:"path"`
46 | User string `config:"user"`
47 | Password string `config:"password"`
48 | }
49 |
50 | type InfobaseConfig struct {
51 | ConnectionString string `config:"connection,required"`
52 | User string `config:"user,required"`
53 | Password string `config:"password"`
54 | }
55 |
56 | func LoadConfig(config *Config, configFile string) (*Config, error) {
57 |
58 | if configFile == "" {
59 | cf, err := resolveConfigFileFromEnv()
60 | if err == nil {
61 | configFile = cf
62 | }
63 | }
64 |
65 | if configFile == "" {
66 | cf, err := resolveConfigFileFromWorkDir()
67 | if err == nil {
68 | configFile = cf
69 | }
70 | }
71 |
72 | if configFile != "" {
73 | var (
74 | err error
75 | rawConfig *ucfg.Config
76 | )
77 |
78 | if configFile, err = filepath.Abs(configFile); err != nil {
79 | return nil, err
80 | }
81 |
82 | if rawConfig, err = yaml.NewConfigWithFile(configFile); err != nil {
83 | return nil, err
84 | }
85 |
86 | cfg, err := ucfg.NewFrom(config)
87 | if err != nil {
88 | return nil, err
89 | }
90 |
91 | if err := cfg.Merge(rawConfig); err != nil {
92 | return nil, err
93 | }
94 |
95 | if err := cfg.Unpack(config); err != nil {
96 | return nil, err
97 | }
98 |
99 | return config, nil
100 | }
101 |
102 | return config, nil
103 | }
104 |
105 | func resolveConfigFileFromEnv() (string, error) {
106 | f := os.Getenv("R2GITSYNC_CONFIG_FILE")
107 | if f == "" {
108 | return "", errors.New("environment variable 'R2GITSYNC_CONFIG_FILE' is not set")
109 | }
110 | return f, nil
111 | }
112 |
113 | func resolveConfigFileFromWorkDir() (string, error) {
114 | matches1, _ := filepath.Glob("r2gitsync.yaml")
115 | matches2, _ := filepath.Glob("r2gitsync.yml")
116 | matches := append(matches1, matches2...)
117 | switch len(matches) {
118 | case 0:
119 | return "", errors.New("no config file found in work dir")
120 | case 1:
121 | return matches[0], nil
122 | default:
123 | panic(fmt.Errorf("multiple config files found %v", matches))
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/features/cmd/plugins.feature:
--------------------------------------------------------------------------------
1 | # language: ru
2 |
3 | Функционал: Синхронизация хранилища конфигурации 1С и гит (команды sync) совместно с плагинами
4 | Как Пользователь
5 | Я хочу выполнять автоматическую синхронизацию конфигурации из хранилища используя плагины
6 | Чтобы автоматизировать свою работы с хранилищем с git
7 |
8 | Контекст: Тестовый контекст
9 | Когда Я создаю временный каталог и сохраняю его в переменной "КаталогХранилища1С"
10 | И Я создаю временный каталог и сохраняю его в переменной "ПутьКаталогаИсходников"
11 | И Я инициализирую репозиторий в каталоге из переменной "ПутьКаталогаИсходников"
12 | И Я создаю тестовой файл "AUTHORS" в каталоге из переменной "ПутьКаталогаИсходников" с текстом:
13 | """
14 | Администратор=Администратор
15 | """
16 | И Я создаю тестовой файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" с текстом:
17 | """
18 |
19 | 0
20 | """
21 |
22 | Сценарий: Cинхронизация хранилища с git-репозиторием с ограничением
23 | Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
24 | И Я скопировал каталог "../tests/fixtures/bigRepository" в каталог из переменной "КаталогХранилища1С"
25 | И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
26 | И Я добавляю параметр "--debug"
27 | И Я добавляю параметр "sync"
28 | И Я добавляю параметр "--limit=2"
29 | И Я добавляю параметр "--minversion=2"
30 | И Я добавляю параметр из переменной "КаталогХранилища1С"
31 | И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
32 | Когда Я выполняю приложение
33 | Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "3"
34 |
35 | Сценарий: Cинхронизация хранилища с git-репозиторием с максимальной версией
36 | Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
37 | И Я скопировал каталог "../tests/fixtures/bigRepository" в каталог из переменной "КаталогХранилища1С"
38 | И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
39 | И Я добавляю параметр "--debug"
40 | И Я добавляю параметр "sync"
41 | И Я добавляю параметр "--maxversion=6"
42 | И Я добавляю параметр из переменной "КаталогХранилища1С"
43 | И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
44 | Когда Я выполняю приложение
45 | Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "6"
46 |
47 | Сценарий: Cинхронизация хранилища с git-репозиторием с максимальной версией и органичением
48 | Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
49 | И Я скопировал каталог "../tests/fixtures/bigRepository" в каталог из переменной "КаталогХранилища1С"
50 | И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
51 | И Я добавляю параметр "--debug"
52 | И Я добавляю параметр "sync"
53 | И Я добавляю параметр "--limit=2"
54 | И Я добавляю параметр "--maxversion=6"
55 | И Я добавляю параметр из переменной "КаталогХранилища1С"
56 | И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
57 | Когда Я выполняю приложение
58 | Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "2"
59 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/getRepositoryHistory.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/internal/manager/types"
5 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
6 | )
7 |
8 | var _ GetRepositoryHistoryHandler = (*getRepositoryHistoryHandler)(nil)
9 |
10 | type getRepositoryHistoryHandler struct {
11 | before []BeforeGetRepositoryHistoryFn
12 | on []OnGetRepositoryHistoryFn
13 | after []AfterGetRepositoryHistoryFn
14 | }
15 |
16 | func (h *getRepositoryHistoryHandler) Count() int {
17 | return len(h.on) + len(h.after) + len(h.before)
18 | }
19 |
20 | func (h *getRepositoryHistoryHandler) Subscribe(sub GetRepositoryHistorySubscriber) {
21 |
22 | if sub.Before != nil {
23 | h.before = append(h.before, sub.Before)
24 | }
25 |
26 | if sub.On != nil {
27 | h.on = append(h.on, sub.On)
28 | }
29 |
30 | if sub.After != nil {
31 | h.after = append(h.after, sub.After)
32 | }
33 | }
34 |
35 | type GetRepositoryHistoryHandler interface {
36 | SubscribeHandler
37 | Subscribe(sub GetRepositoryHistorySubscriber)
38 |
39 | Before(v8end V8Endpoint, dir string, NBegin int) error
40 | On(v8end V8Endpoint, dir string, NBegin int, stdHandler *bool) ([]types.RepositoryVersion, error)
41 | After(v8end V8Endpoint, dir string, NBegin int, rv *types.RepositoryVersionsList) error
42 |
43 | // Start(v8end V8Endpoint, workdir string, temp string, number int) error
44 | // On(v8end V8Endpoint, workdir string, temp string, number int, standartHandler *bool) error
45 | // Finish(v8end V8Endpoint, workdir string, temp string, number int) error
46 | }
47 |
48 | func (h *getRepositoryHistoryHandler) Before(v8end V8Endpoint, dir string, NBegin int) error {
49 |
50 | for _, fn := range h.before {
51 |
52 | err := fn(v8end, dir, NBegin)
53 |
54 | if err != nil {
55 | return err
56 | }
57 | }
58 |
59 | return nil
60 | }
61 |
62 | func (h *getRepositoryHistoryHandler) On(v8end V8Endpoint, dir string, NBegin int, stdHandler *bool) ([]types.RepositoryVersion, error) {
63 |
64 | for _, fn := range h.on {
65 |
66 | rv, err := fn(v8end, dir, NBegin, stdHandler)
67 |
68 | if err != nil {
69 | return rv, err
70 | }
71 | }
72 |
73 | return []types.RepositoryVersion{}, nil
74 | }
75 |
76 | func (h *getRepositoryHistoryHandler) After(v8end V8Endpoint, dir string, NBegin int, rv *types.RepositoryVersionsList) error {
77 |
78 | for _, fn := range h.after {
79 |
80 | err := fn(v8end, dir, NBegin, rv)
81 |
82 | if err != nil {
83 | return err
84 | }
85 | }
86 |
87 | return nil
88 | }
89 |
90 | var _ ConfigureRepositoryVersionsHandler = (*configureRepositoryVersionsHandler)(nil)
91 |
92 | type configureRepositoryVersionsHandler struct {
93 | on []OnConfigureRepositoryVersionsFn
94 | }
95 |
96 | func (h *configureRepositoryVersionsHandler) Count() int {
97 | return len(h.on)
98 | }
99 |
100 | func (h *configureRepositoryVersionsHandler) Subscribe(sub ConfigureRepositoryVersionsSubscriber) {
101 |
102 | if sub.On != nil {
103 | h.on = append(h.on, sub.On)
104 | }
105 |
106 | }
107 |
108 | type ConfigureRepositoryVersionsHandler interface {
109 | SubscribeHandler
110 | Subscribe(sub ConfigureRepositoryVersionsSubscriber)
111 | On(v8end V8Endpoint, versions *types.RepositoryVersionsList, NCurrent, NNext, NMax *int) error
112 | }
113 |
114 | func (h *configureRepositoryVersionsHandler) On(v8end V8Endpoint, versions *types.RepositoryVersionsList, NCurrent, NNext, NMax *int) error {
115 |
116 | for _, fn := range h.on {
117 |
118 | err := fn(v8end, versions, NCurrent, NNext, NMax)
119 |
120 | if err != nil {
121 | return err
122 | }
123 | }
124 |
125 | return nil
126 | }
127 |
--------------------------------------------------------------------------------
/cmd/r2gitsync.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/khorevaa/r2gitsync/internal/commands"
8 | "github.com/khorevaa/r2gitsync/internal/config"
9 | _ "github.com/khorevaa/r2gitsync/internal/plugins"
10 | "github.com/khorevaa/r2gitsync/pkg/plugin"
11 | "github.com/urfave/cli/v2"
12 |
13 | "os"
14 |
15 | "github.com/khorevaa/logos"
16 | )
17 |
18 | const (
19 | VerboseEnv = "GITSYNC_VERBOSE R2GITSYNC_VERBOSE"
20 | V8VersionEnv = "GITSYNC_V8_VERSION GITSYNC_V8VERSION"
21 | V8PathEnv = "GITSYNC_V8_PATH"
22 | WorkDirEnv = "R2GITSYNC_WORKDIR GITSYNC_WORKDIR"
23 | PluginsDirEnv = "GITSYNC_PLUGINS_PATH GITSYNC_PLUGINS_DIR GITSYNC_PL_DIR"
24 | )
25 |
26 | // nolint: gochecknoglobals
27 | var (
28 | version = "dev"
29 | commit = ""
30 | date = ""
31 | builtBy = ""
32 | )
33 |
34 | var log = logos.New("github.com/khorevaa/r2gitsync").Sugar()
35 |
36 | func main() {
37 |
38 | appConfig := config.DefaultConfig()
39 |
40 | manager := plugin.NewPluginManager(appConfig.Plugins)
41 |
42 | app := &cli.App{
43 | Name: "r2gitsync",
44 | Usage: "Приложение для синхронизация Хранилища 1С с git",
45 | Version: buildVersion(),
46 | Flags: setFlags(appConfig),
47 | Before: func(c *cli.Context) error {
48 | var err error
49 |
50 | if appConfig, err = config.LoadConfig(appConfig, c.String("config")); err != nil {
51 | return err
52 | }
53 |
54 | if appConfig.Debug {
55 | // TODO Не работает
56 | logos.SetLevel("github.com/khorevaa/r2gitsync", logos.DebugLevel)
57 | }
58 |
59 | manager = plugin.NewPluginManager(appConfig.Plugins)
60 | c.App.Commands = []*cli.Command{}
61 | for _, command := range commands.Commands {
62 | c.App.Commands = append(c.App.Commands, command.Cmd(manager))
63 | }
64 |
65 | return nil
66 | },
67 | }
68 |
69 | for _, command := range commands.Commands {
70 | app.Commands = append(app.Commands, command.Cmd(manager))
71 | }
72 |
73 | err := app.Run(os.Args)
74 | defer log.Sync()
75 | if err != nil {
76 | log.Fatal(err.Error())
77 | }
78 |
79 | }
80 |
81 | func buildVersion() string {
82 | var result = version
83 | if commit != "" {
84 | result = fmt.Sprintf("%s\ncommit: %s", result, commit)
85 | }
86 | if date != "" {
87 | result = fmt.Sprintf("%s\nbuilt at: %s", result, date)
88 | }
89 | if builtBy != "" {
90 | result = fmt.Sprintf("%s\nbuilt by: %s", result, builtBy)
91 | }
92 | return result
93 | }
94 |
95 | func setFlags(cfg *config.Config) []cli.Flag {
96 |
97 | return []cli.Flag{
98 | &cli.StringFlag{
99 | Name: "V8version",
100 | Value: "8.3",
101 | EnvVars: strings.Fields(V8VersionEnv),
102 | Usage: "маска версии платформы 1С (8.3, 8.3.5, 8.3.6.2299 и т.п.)",
103 | Destination: &cfg.V8version,
104 | },
105 | &cli.StringFlag{
106 | Name: "v8-path",
107 | Aliases: []string{"v8path"},
108 | EnvVars: strings.Fields(V8PathEnv),
109 | Usage: "путь к исполняемому файлу платформы 1С (Например, /opt/1C/v8.3/x86_64/1cv8)",
110 | Destination: &cfg.V8Path,
111 | },
112 | &cli.StringFlag{
113 | Name: "temp-dir",
114 | Aliases: strings.Fields("t tempdir"),
115 | EnvVars: strings.Fields("GITSYNC_TEMP GITSYNC_TEMPDIR"),
116 | Usage: "путь к каталогу временных файлов",
117 | Destination: &cfg.TempDir,
118 | },
119 |
120 | &cli.StringFlag{
121 | Name: "config",
122 | EnvVars: strings.Fields("GITSYNC_CONFIG"),
123 | Usage: "путь к файлу настройки приложения",
124 | },
125 |
126 | &cli.BoolFlag{
127 | Name: "debug",
128 | EnvVars: strings.Fields(VerboseEnv),
129 | Usage: "Режим отладки приложения",
130 | Destination: &cfg.Debug,
131 | },
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/internal/commands/syncCmd_test.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | //
4 | // import (
5 | // "github.com/cucumber/godog"
6 | // "github.com/khorevaa/r2gitsync/cmd"
7 | // "github.com/khorevaa/r2gitsync/internal/app"
8 | // "github.com/khorevaa/r2gitsync/tests/bdd"
9 | // "github.com/stretchr/testify/require"
10 | // "github.com/stretchr/testify/suite"
11 | // v8 "github.com/v8platform/api"
12 | // "github.com/v8platform/designer"
13 | // "github.com/v8platform/find"
14 | // "testing"
15 | // )
16 | //
17 | // type cmdSyncTestSuite struct {
18 | // suite.Suite
19 | // app.BaseSuite
20 | //
21 | // RepositoryPath string
22 | // WorkdirPath string
23 | // v8Version string
24 | // }
25 | //
26 | // func TestCmdSyncTestSuite(t *testing.T) {
27 | // suite.Run(t, new(cmdSyncTestSuite))
28 | // }
29 | //
30 | // func (s *cmdSyncTestSuite) r() *require.Assertions {
31 | // return s.Require()
32 | // }
33 | //
34 | // func (s *cmdSyncTestSuite) TestFeatures() {
35 | //
36 | // err := bdd.Run([]string{
37 | // "features/sync.feature",
38 | // },
39 | // s.InitializeCmdSyncTestSuite,
40 | // s.InitializeCmdSyncScenario)
41 | //
42 | // s.r().NoError(err)
43 | //
44 | // }
45 | //
46 | // type cmdSyncPluginsTestSuite struct {
47 | // suite.Suite
48 | // app.BaseSuite
49 | //
50 | // RepositoryPath string
51 | // WorkdirPath string
52 | // v8Version string
53 | // }
54 | //
55 | // func TestSyncPluginsTestSuite(t *testing.T) {
56 | // suite.Run(t, new(cmdSyncPluginsTestSuite))
57 | // }
58 | //
59 | // func (s *cmdSyncPluginsTestSuite) r() *require.Assertions {
60 | // return s.Require()
61 | // }
62 | //
63 | // func (s *cmdSyncPluginsTestSuite) TestFeatures() {
64 | //
65 | // err := bdd.Run([]string{
66 | // "features/plugins.feature",
67 | // },
68 | // s.InitializeCmdSyncTestSuite,
69 | // s.InitializeCmdSyncScenario)
70 | //
71 | // s.r().NoError(err)
72 | //
73 | // }
74 | //
75 | // type cmdSyncContext struct {
76 | // *app.Context
77 | // app *main.AppTestSuite
78 | // }
79 | //
80 | // func (s *cmdSyncContext) createTempIB(name string) error {
81 | // dir := s.Context.String(name)
82 | // return createTempIb(dir)
83 | // }
84 | //
85 | // func (s *cmdSyncContext) findAndSavev8Path(name string) error {
86 | //
87 | // path, err := find.PlatformByVersion("8.3")
88 | //
89 | // s.Context.Set(name, path)
90 | //
91 | // return err
92 | // }
93 | //
94 | // func (s *cmdSyncTestSuite) InitializeCmdSyncScenario(ctx *godog.ScenarioContext) {
95 | //
96 | // sharedCtx := app.SharedContext(ctx)
97 | //
98 | // step := &cmdSyncContext{
99 | // Context: sharedCtx,
100 | // app: main.SharedAppSteps(sharedCtx, ctx),
101 | // }
102 | // ctx.Step(`^Я создаю пустую базы в каталоге из переменной "([^"]*)"$`, step.createTempIB)
103 | // ctx.Step(`^Я ищю платформу и сохраняю в переменной "([^"]*)"$`, step.findAndSavev8Path) // ctx.Step(`^Я инициализирую новое приложение$`, step.InitNewApp)
104 | // // ctx.Step(`^я скопировал каталог "([^"]*)" в каталог из переменной "([^"]*)"$`, step.CopyDirToDirFromContext )
105 | //
106 | // }
107 | //
108 | // func (s *cmdSyncPluginsTestSuite) InitializeCmdSyncScenario(ctx *godog.ScenarioContext) {
109 | //
110 | // sharedCtx := app.SharedContext(ctx)
111 | //
112 | // step := &cmdSyncContext{
113 | // Context: sharedCtx,
114 | // app: main.SharedAppSteps(sharedCtx, ctx),
115 | // }
116 | //
117 | // step.app.Application = app.NewApp("dev", true)
118 | //
119 | // }
120 | //
121 | // func createTempIb(dir string) error {
122 | //
123 | // crOpts := designer.CreateFileInfoBaseOptions{
124 | // File: dir,
125 | // }
126 | //
127 | // ib := v8.NewFileIB(dir)
128 | //
129 | // var opts []interface{}
130 | //
131 | // err := v8.Run(ib, crOpts, opts...)
132 | //
133 | // return err
134 | //
135 | // }
136 |
--------------------------------------------------------------------------------
/internal/manager/manager.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | "fmt"
5 | "github.com/lithammer/shortuuid/v3"
6 | v8 "github.com/v8platform/api"
7 | "github.com/v8platform/designer"
8 | )
9 |
10 | func Sync(r SyncRepository, options Options) error {
11 |
12 | return r.Sync(options)
13 |
14 | }
15 |
16 | func Init(r SyncRepository, options Options) error {
17 |
18 | return r.Init(options)
19 | }
20 |
21 | type SyncRepository struct {
22 | designer.Repository
23 | Name string
24 | Workdir string
25 | }
26 |
27 | func (r *SyncRepository) Sync(options Options) error {
28 |
29 | // jobLogger := log2.Logger(log2.NullLogger)
30 | //
31 | // if options.Logger != nil {
32 | // options.Logger.Debug("use options logger")
33 | // jobLogger = options.Logger.Named("manager")
34 | // }
35 |
36 | ib, err := r.getInfobase(options)
37 | if err != nil {
38 | return err
39 | }
40 |
41 | if len(r.Name) == 0 {
42 | r.Name = shortuuid.New()
43 | }
44 |
45 | jobName := fmt.Sprintf("Sync job for repository: %s (%s)", r.Name, r.Path)
46 |
47 | job := syncJob{
48 | name: jobName,
49 | workdir: r.Workdir,
50 | tempDir: options.TempDir,
51 | repo: &r.Repository,
52 | infobase: ib,
53 | increment: !options.DisableIncrement,
54 | minVersion: options.MinVersion,
55 | maxVersion: options.MaxVersion,
56 | limitVersion: options.LimitVersions,
57 | flow: Flow{SubscribeManager: options.Plugins},
58 | options: options.Options(),
59 | // log: jobLogger,
60 | domainEmail: options.DomainEmail,
61 | skipFiles: []string{VERSION_FILE, AUTHORS_FILE, ".git"},
62 | }
63 |
64 | return job.Run()
65 |
66 | }
67 |
68 | func (r *SyncRepository) Init(options Options) error {
69 |
70 | // jobLogger := log2.Logger(log2.NullLogger)
71 | //
72 | // if options.Logger != nil {
73 | // options.Logger.Debug("use options logger")
74 | // jobLogger = options.Logger.Named("manager")
75 | // }
76 |
77 | ib, err := r.getInfobase(options)
78 | if err != nil {
79 | return err
80 | }
81 |
82 | if len(r.Name) == 0 {
83 | r.Name = shortuuid.New()
84 | }
85 |
86 | jobName := fmt.Sprintf("Init job for repository: %s (%s)", r.Name, r.Path)
87 |
88 | job := syncJob{
89 | name: jobName,
90 | workdir: r.Workdir,
91 | tempDir: options.TempDir,
92 | repo: &r.Repository,
93 | infobase: ib,
94 | increment: !options.DisableIncrement,
95 | minVersion: options.MinVersion,
96 | maxVersion: options.MaxVersion,
97 | limitVersion: options.LimitVersions,
98 | flow: Flow{SubscribeManager: options.Plugins},
99 | options: options.Options(),
100 | // log: jobLogger,
101 | domainEmail: options.DomainEmail,
102 | skipFiles: []string{VERSION_FILE, AUTHORS_FILE, ".git"},
103 | }
104 |
105 | return job.Run()
106 | }
107 |
108 | func (r *SyncRepository) getInfobase(opts Options) (*v8.Infobase, error) {
109 |
110 | if len(opts.InfobaseConnect) > 0 {
111 | return opts.Infobase()
112 | }
113 |
114 | // logger.Debug("Creating temp infobase")
115 |
116 | CreateFileInfobase := v8.CreateFileInfobase(v8.NewTempDir(opts.TempDir, "temp_ib"))
117 |
118 | ib, err := v8.CreateInfobase(CreateFileInfobase, opts.Options())
119 |
120 | if err != nil {
121 | return nil, err
122 | }
123 |
124 | if len(r.Extension) > 0 {
125 |
126 | tempExtension, err := restoreTempExtension()
127 | if err != nil {
128 | return nil, err
129 | }
130 |
131 | LoadExtensionCfg := v8.LoadExtensionCfg(tempExtension, r.Extension)
132 | err = v8.Run(ib, LoadExtensionCfg, opts.Options())
133 |
134 | if err != nil {
135 | return nil, err
136 | }
137 | // logger.Debug("Empty extension loaded into infobase")
138 | }
139 |
140 | return ib, nil
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/workdir.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
5 | )
6 |
7 | var _ ClearWorkdirHandler = (*clearWorkdirHandler)(nil)
8 |
9 | type ClearWorkdirHandler interface {
10 | SubscribeHandler
11 |
12 | Subscribe(sub ClearWorkdirSubscriber)
13 |
14 | Before(v8end V8Endpoint, workdir, temp string) error
15 | On(v8end V8Endpoint, workdir, temp string, stdHandler *bool) error
16 | After(v8end V8Endpoint, workdir, temp string) error
17 | }
18 |
19 | type clearWorkdirHandler struct {
20 | before []BeforeClearWorkdirFn
21 | on []OnClearWorkdirFn
22 | after []AfterClearWorkdirFn
23 | }
24 |
25 | func (h *clearWorkdirHandler) Count() int {
26 | return len(h.on) + len(h.after) + len(h.before)
27 | }
28 |
29 | func (h *clearWorkdirHandler) Subscribe(sub ClearWorkdirSubscriber) {
30 |
31 | if sub.Before != nil {
32 | h.before = append(h.before, sub.Before)
33 | }
34 |
35 | if sub.On != nil {
36 | h.on = append(h.on, sub.On)
37 | }
38 |
39 | if sub.After != nil {
40 | h.after = append(h.after, sub.After)
41 | }
42 | }
43 |
44 | func (h *clearWorkdirHandler) Before(v8end V8Endpoint, workdir, temp string) error {
45 |
46 | for _, fn := range h.before {
47 |
48 | err := fn(v8end, workdir, temp)
49 |
50 | if err != nil {
51 | return err
52 | }
53 | }
54 |
55 | return nil
56 | }
57 |
58 | func (h *clearWorkdirHandler) On(v8end V8Endpoint, workdir, temp string, stdHandler *bool) error {
59 |
60 | for _, fn := range h.on {
61 |
62 | err := fn(v8end, workdir, temp, stdHandler)
63 |
64 | if err != nil {
65 | return err
66 | }
67 | }
68 |
69 | return nil
70 | }
71 |
72 | func (h *clearWorkdirHandler) After(v8end V8Endpoint, workdir, temp string) error {
73 |
74 | for _, fn := range h.after {
75 |
76 | err := fn(v8end, workdir, temp)
77 |
78 | if err != nil {
79 | return err
80 | }
81 | }
82 |
83 | return nil
84 | }
85 |
86 | var _ MoveToWorkdirHandler = (*moveToWorkdirHandler)(nil)
87 |
88 | type MoveToWorkdirHandler interface {
89 | SubscribeHandler
90 |
91 | Subscribe(sub MoveToWorkdirSubscriber)
92 |
93 | Before(v8end V8Endpoint, workdir, temp string) error
94 | On(v8end V8Endpoint, workdir, temp string, stdHandler *bool) error
95 | After(v8end V8Endpoint, workdir, temp string) error
96 | }
97 |
98 | type moveToWorkdirHandler struct {
99 | before []BeforeMoveToWorkdirFn
100 | on []OnMoveToWorkdirFn
101 | after []AfterMoveToWorkdirFn
102 | }
103 |
104 | func (h *moveToWorkdirHandler) Count() int {
105 | return len(h.on) + len(h.after) + len(h.before)
106 | }
107 |
108 | func (h *moveToWorkdirHandler) Subscribe(sub MoveToWorkdirSubscriber) {
109 |
110 | if sub.Before != nil {
111 | h.before = append(h.before, sub.Before)
112 | }
113 |
114 | if sub.On != nil {
115 | h.on = append(h.on, sub.On)
116 | }
117 |
118 | if sub.After != nil {
119 | h.after = append(h.after, sub.After)
120 | }
121 | }
122 |
123 | func (h *moveToWorkdirHandler) Before(v8end V8Endpoint, workdir, temp string) error {
124 |
125 | for _, fn := range h.before {
126 |
127 | err := fn(v8end, workdir, temp)
128 |
129 | if err != nil {
130 | return err
131 | }
132 | }
133 |
134 | return nil
135 | }
136 |
137 | func (h *moveToWorkdirHandler) On(v8end V8Endpoint, workdir, temp string, stdHandler *bool) error {
138 |
139 | for _, fn := range h.on {
140 |
141 | err := fn(v8end, workdir, temp, stdHandler)
142 |
143 | if err != nil {
144 | return err
145 | }
146 | }
147 |
148 | return nil
149 | }
150 |
151 | func (h *moveToWorkdirHandler) After(v8end V8Endpoint, workdir, temp string) error {
152 |
153 | for _, fn := range h.after {
154 |
155 | err := fn(v8end, workdir, temp)
156 |
157 | if err != nil {
158 | return err
159 | }
160 | }
161 |
162 | return nil
163 | }
164 |
--------------------------------------------------------------------------------
/pkg/plugin/config/fileConfig.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 | )
9 |
10 | const (
11 | disabledPluginsFileName = "disabled-plugins"
12 | enabledPluginsFileName = "enabled-plugins"
13 | envSepKey = ","
14 | )
15 |
16 | type Config interface {
17 | Disable(name ...string)
18 | Enable(name ...string)
19 |
20 | State() map[string]bool
21 | List() (idxEnable []string, idxDisable []string)
22 |
23 | Load() error
24 | Save(saveEnable bool) error
25 | }
26 |
27 | type FilePluginsConfig struct {
28 | Dir string
29 | Filename string
30 | IdxEnable map[string]bool
31 | IdxDisable map[string]bool
32 | }
33 |
34 | func (s *FilePluginsConfig) State() (pl map[string]bool) {
35 |
36 | pl = make(map[string]bool)
37 |
38 | for name, _ := range s.IdxDisable {
39 | pl[name] = false
40 | }
41 |
42 | for name, _ := range s.IdxEnable {
43 | pl[name] = true
44 | }
45 |
46 | return
47 |
48 | }
49 |
50 | func (s *FilePluginsConfig) Disable(names ...string) {
51 |
52 | for _, name := range names {
53 |
54 | s.changeEnable(name, false)
55 |
56 | }
57 |
58 | }
59 |
60 | func (s *FilePluginsConfig) Enable(names ...string) {
61 |
62 | for _, name := range names {
63 |
64 | s.changeEnable(name, true)
65 |
66 | }
67 |
68 | }
69 |
70 | func (s *FilePluginsConfig) List() (idxEnable []string, idxDisable []string) {
71 |
72 | for name, _ := range s.IdxEnable {
73 | idxEnable = append(idxEnable, name)
74 | }
75 |
76 | for name, _ := range s.IdxDisable {
77 | idxDisable = append(idxDisable, name)
78 | }
79 |
80 | return
81 | }
82 |
83 | func (s *FilePluginsConfig) Load() error {
84 |
85 | if len(s.Dir) == 0 {
86 | return nil
87 | }
88 |
89 | s.loadPluginsState()
90 |
91 | return nil
92 | }
93 |
94 | func (s *FilePluginsConfig) Save(saveEnable bool) error {
95 |
96 | plEnable, plDisable := s.List()
97 | data := strings.Join(plDisable, "\n")
98 |
99 | file := filepath.Join(s.Dir, disabledPluginsFileName)
100 | err := ioutil.WriteFile(file, []byte(data), 0644)
101 |
102 | if saveEnable {
103 |
104 | data2 := strings.Join(plEnable, "\n")
105 |
106 | file2 := filepath.Join(s.Dir, enabledPluginsFileName)
107 | err = ioutil.WriteFile(file2, []byte(data2), 0644)
108 |
109 | }
110 |
111 | return err
112 | }
113 |
114 | func (s *FilePluginsConfig) changeEnable(name string, enable bool) {
115 |
116 | enableState := s.IdxEnable[name]
117 | disableState := s.IdxEnable[name]
118 |
119 | switch enable {
120 |
121 | case true:
122 | if enableState {
123 | delete(s.IdxEnable, name)
124 | }
125 |
126 | s.IdxDisable[name] = true
127 |
128 | case false:
129 |
130 | if disableState {
131 | delete(s.IdxDisable, name)
132 | }
133 |
134 | s.IdxEnable[name] = true
135 | }
136 |
137 | }
138 |
139 | func Exists(name string) (bool, error) {
140 | _, err := os.Stat(name)
141 | if os.IsNotExist(err) {
142 | return false, err
143 | }
144 | return true, nil
145 | }
146 |
147 | func (s *FilePluginsConfig) loadPluginsState() {
148 |
149 | fileEnable := filepath.Join(s.Dir, enabledPluginsFileName)
150 |
151 | plEnable, err := getPluginsFromFile(fileEnable)
152 |
153 | if err != nil {
154 | return
155 | }
156 |
157 | for _, name := range plEnable {
158 |
159 | s.IdxEnable[name] = true
160 | }
161 |
162 | fileDisable := filepath.Join(s.Dir, disabledPluginsFileName)
163 |
164 | plDisable, err := getPluginsFromFile(fileDisable)
165 |
166 | if err != nil {
167 | return
168 | }
169 |
170 | for _, name := range plDisable {
171 |
172 | s.IdxDisable[name] = true
173 | }
174 |
175 | }
176 |
177 | func getPluginsFromFile(file string) (pl []string, err error) {
178 |
179 | if ok, _ := Exists(file); ok {
180 | content, err2 := ioutil.ReadFile(file)
181 | if err2 != nil {
182 | return pl, err2
183 | }
184 | lines := strings.Split(string(content), "\n")
185 |
186 | for _, line := range lines {
187 | if strings.HasPrefix(strings.TrimSpace(line), "//") {
188 | continue
189 | }
190 | pl = append(pl, line)
191 | }
192 |
193 | }
194 |
195 | return
196 | }
197 |
--------------------------------------------------------------------------------
/pkg/plugin/subscription/versionFile.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | . "github.com/khorevaa/r2gitsync/pkg/plugin/types"
5 | )
6 |
7 | var _ ReadVersionFileHandler = (*readVersionFileHandler)(nil)
8 |
9 | type ReadVersionFileHandler interface {
10 | SubscribeHandler
11 |
12 | Subscribe(sub ReadVersionFileSubscriber)
13 |
14 | Before(v8end V8Endpoint, workdir, filename string) error
15 | On(v8end V8Endpoint, workdir, filename string, stdHandler *bool) (int, error)
16 | After(v8end V8Endpoint, workdir, filename string, number *int) error
17 | }
18 |
19 | type readVersionFileHandler struct {
20 | before []BeforeReadVersionFileFn
21 | on []OnReadVersionFileFn
22 | after []AfterReadVersionFileFn
23 | }
24 |
25 | func (h *readVersionFileHandler) Count() int {
26 | return len(h.on) + len(h.after) + len(h.before)
27 | }
28 |
29 | func (h *readVersionFileHandler) Subscribe(sub ReadVersionFileSubscriber) {
30 |
31 | if sub.Before != nil {
32 | h.before = append(h.before, sub.Before)
33 | }
34 |
35 | if sub.On != nil {
36 | h.on = append(h.on, sub.On)
37 | }
38 |
39 | if sub.After != nil {
40 | h.after = append(h.after, sub.After)
41 | }
42 | }
43 |
44 | func (h *readVersionFileHandler) Before(v8end V8Endpoint, workdir, filename string) error {
45 |
46 | for _, fn := range h.before {
47 |
48 | err := fn(v8end, workdir, filename)
49 |
50 | if err != nil {
51 | return err
52 | }
53 | }
54 |
55 | return nil
56 | }
57 |
58 | func (h *readVersionFileHandler) On(v8end V8Endpoint, workdir, filename string, stdHandler *bool) (int, error) {
59 |
60 | for _, fn := range h.on {
61 |
62 | n, err := fn(v8end, workdir, filename, stdHandler)
63 |
64 | if err != nil {
65 | return n, err
66 | }
67 | }
68 |
69 | return 0, nil
70 | }
71 |
72 | func (h *readVersionFileHandler) After(v8end V8Endpoint, workdir, filename string, number *int) error {
73 |
74 | for _, fn := range h.after {
75 |
76 | err := fn(v8end, workdir, filename, number)
77 |
78 | if err != nil {
79 | return err
80 | }
81 | }
82 |
83 | return nil
84 | }
85 |
86 | var _ WriteVersionFileHandler = (*writeVersionFileHandler)(nil)
87 |
88 | type WriteVersionFileHandler interface {
89 | SubscribeHandler
90 |
91 | Subscribe(sub WriteVersionFileSubscriber)
92 |
93 | Before(v8end V8Endpoint, workdir string, number int, filename string) error
94 | On(v8end V8Endpoint, workdir string, number int, filename string, stdHandler *bool) error
95 | After(v8end V8Endpoint, workdir string, number int, filename string) error
96 | }
97 |
98 | type writeVersionFileHandler struct {
99 | before []BeforeWriteVersionFileFn
100 | on []OnWriteVersionFileFn
101 | after []AfterWriteVersionFileFn
102 | }
103 |
104 | func (h *writeVersionFileHandler) Count() int {
105 | return len(h.on) + len(h.after) + len(h.before)
106 | }
107 |
108 | func (h *writeVersionFileHandler) Subscribe(sub WriteVersionFileSubscriber) {
109 |
110 | if sub.Before != nil {
111 | h.before = append(h.before, sub.Before)
112 | }
113 |
114 | if sub.On != nil {
115 | h.on = append(h.on, sub.On)
116 | }
117 |
118 | if sub.After != nil {
119 | h.after = append(h.after, sub.After)
120 | }
121 | }
122 |
123 | func (h *writeVersionFileHandler) Before(v8end V8Endpoint, workdir string, number int, filename string) error {
124 |
125 | for _, fn := range h.before {
126 |
127 | err := fn(v8end, workdir, number, filename)
128 |
129 | if err != nil {
130 | return err
131 | }
132 | }
133 |
134 | return nil
135 | }
136 |
137 | func (h *writeVersionFileHandler) On(v8end V8Endpoint, workdir string, number int, filename string, stdHandler *bool) error {
138 |
139 | for _, fn := range h.on {
140 |
141 | err := fn(v8end, workdir, number, filename, stdHandler)
142 |
143 | if err != nil {
144 | return err
145 | }
146 | }
147 |
148 | return nil
149 | }
150 |
151 | func (h *writeVersionFileHandler) After(v8end V8Endpoint, workdir string, number int, filename string) error {
152 |
153 | for _, fn := range h.after {
154 |
155 | err := fn(v8end, workdir, number, filename)
156 |
157 | if err != nil {
158 | return err
159 | }
160 | }
161 |
162 | return nil
163 | }
164 |
--------------------------------------------------------------------------------
/internal/commands/syncCmd.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/khorevaa/logos"
8 |
9 | "github.com/khorevaa/r2gitsync/pkg/plugin"
10 | "github.com/khorevaa/r2gitsync/pkg/plugin/subscription"
11 | "github.com/urfave/cli/v2"
12 | )
13 |
14 | type syncCmd struct {
15 | InfobaseConnect string
16 | InfobaseUser string
17 | InfobasePassword string
18 | StorageUser string
19 | StoragePassword string
20 | Extension string
21 |
22 | DisableIncrement bool
23 |
24 | DomainEmail string
25 | WordDir string
26 | StoragePath string
27 |
28 | sm *subscription.SubscribeManager
29 | }
30 |
31 | func (c *syncCmd) Cmd(manager plugin.Manager) *cli.Command {
32 | cmd := &cli.Command{
33 | Name: "sync",
34 | Aliases: []string{"s"},
35 | Usage: "Выполнение синхронизации Хранилища 1С с git репозиторием",
36 | ArgsUsage: "WORKDIR PATH",
37 | Flags: append(c.Flags(), manager.Flags("sync")...),
38 | Action: c.run,
39 | Before: func(ctx *cli.Context) error {
40 | if !ctx.Args().Present() {
41 | err := cli.ShowSubcommandHelp(ctx)
42 | if err != nil {
43 | return err
44 | }
45 | return fmt.Errorf("WRONG USAGE: Requires a PATH argument")
46 | }
47 |
48 | switch ctx.Args().Len() {
49 | case 1:
50 | c.StoragePath = ctx.Args().Get(0)
51 | case 2:
52 | c.WordDir = ctx.Args().Get(0)
53 | c.StoragePath = ctx.Args().Get(1)
54 | default:
55 | return fmt.Errorf("WRONG USAGE: Requires a PATH argument")
56 | }
57 |
58 | var err error
59 | if c.sm, err = manager.Subscriber("sync"); err != nil {
60 | return err
61 | }
62 |
63 | return nil
64 | },
65 | }
66 | return cmd
67 | }
68 |
69 | func (c *syncCmd) Flags() []cli.Flag {
70 | return []cli.Flag{
71 | &cli.StringFlag{
72 | Name: "ib-user",
73 | Aliases: strings.Fields("U ib-usr"),
74 | EnvVars: strings.Fields("GITSYNC_IB_USR GITSYNC_IB_USER GITSYNC_DB_USER"),
75 | Value: "Администратор",
76 | Usage: "пользователь информационной базы",
77 | // Destination: &cfg.Infobase.User,
78 | },
79 | &cli.StringFlag{
80 | Name: "ib-password",
81 | Aliases: strings.Fields("P ib-pwd"),
82 | EnvVars: strings.Fields("GITSYNC_IB_PASSWORD GITSYNC_IB_PWD GITSYNC_DB_PSW"),
83 | Usage: "пароль пользователя информационной базы",
84 | // Destination: &cfg.Infobase.Password,
85 | },
86 | &cli.StringFlag{
87 | Name: "ib-connection",
88 | Aliases: strings.Fields("C ibconnection"),
89 | EnvVars: strings.Fields("GITSYNC_IB_CONNECTION GITSYNC_IBCONNECTION"),
90 | Usage: "путь подключения к информационной базе",
91 | // Destination: &cfg.Infobase.ConnectionString,
92 | },
93 | &cli.StringFlag{
94 | Destination: &c.StorageUser,
95 | Name: "storage-user",
96 | Aliases: []string{"u"},
97 | Value: "Администратор",
98 | DefaultText: "Администратор",
99 | Usage: "пользователь хранилища 1C конфигурации",
100 | EnvVars: strings.Fields("R2GITSYNC_STORAGE_USER GITSYNC_STORAGE_USER"),
101 | },
102 | &cli.StringFlag{
103 | Destination: &c.StoragePassword,
104 | Name: "storage-pwd",
105 | Aliases: []string{"p"},
106 | Usage: "пароль пользователя хранилища 1C конфигурации",
107 | EnvVars: strings.Fields("R2GITSYNC_STORAGE_PASSWORD GITSYNC_STORAGE_PWD GITSYNC_STORAGE_PASSWORD"),
108 | },
109 | &cli.BoolFlag{
110 | Destination: &c.DisableIncrement,
111 | Name: "disable-increment",
112 | Usage: "отключает инкрементальную выгрузку",
113 | EnvVars: strings.Fields("GITSYNC_DISABLE_INCREMENT"),
114 | },
115 | &cli.StringFlag{
116 | Destination: &c.Extension,
117 | Name: "extension",
118 | Aliases: strings.Fields("e ext"),
119 | Usage: "имя расширения для работы с хранилищем расширения",
120 | EnvVars: strings.Fields("R2GITSYNC_EXTENSION GITSYNC_EXTENSION"),
121 | },
122 | }
123 | }
124 |
125 | func (c *syncCmd) run(ctx *cli.Context) error {
126 |
127 | log := logos.New("github.com/khorevaa/r2gitsync/internal/cmd/sync")
128 |
129 | log.Info("run", logos.Any("sm", c.sm.ConfigureRepositoryVersions))
130 | return nil
131 | }
132 |
--------------------------------------------------------------------------------
/internal/manager/flow.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | "github.com/khorevaa/r2gitsync/internal/manager/types"
5 | "github.com/khorevaa/r2gitsync/pkg/plugin/subscription"
6 | "time"
7 | )
8 |
9 | const ConfigDumpInfoFileName = "ConfigDumpInfo.xml"
10 |
11 | type Flow struct {
12 | SubscribeManager *subscription.SubscribeManager
13 | // Logger log.Logger
14 | }
15 |
16 | func (t Flow) StartSyncVersion(v8end types.V8Endpoint, workdir string, tempdir string, number int) {
17 | _ = t.Task(StartSyncVersion{v8end, workdir, tempdir, number})
18 | }
19 |
20 | func (t Flow) FinishSyncVersion(v8end types.V8Endpoint, workdir string, tempdir string, number int, err *error) {
21 | _ = t.Task(FinishSyncVersion{v8end, workdir, tempdir, number, err})
22 | }
23 |
24 | func (t Flow) StartSyncProcess(v8end types.V8Endpoint, dir string) {
25 | _ = t.Task(StartSyncProcess{v8end, dir})
26 | }
27 |
28 | func (t Flow) FinishSyncProcess(v8end types.V8Endpoint, dir string, err *error) {
29 | _ = t.Task(FinishSyncProcess{v8end, dir, err})
30 | }
31 |
32 | func (t Flow) DumpConfigToFiles(v8end types.V8Endpoint, dir string, temp string, number int, update bool) (bool, error) {
33 |
34 | isIncremented := new(bool)
35 |
36 | err := t.Task(DumpConfigToFiles{v8end, dir,
37 | temp, number,
38 | update, isIncremented})
39 | return *isIncremented, err
40 | }
41 |
42 | func (t Flow) ClearWorkDir(v8end types.V8Endpoint, dir string, temp string, skipFiles []string) error {
43 |
44 | return t.Task(ClearWorkdir{v8end, dir,
45 | temp, skipFiles})
46 | }
47 |
48 | func (t Flow) MoveToWorkDir(v8end types.V8Endpoint, dir string, temp string) error {
49 |
50 | return t.Task(MoveToWorkdir{v8end, dir, temp})
51 | }
52 |
53 | func (t Flow) WriteVersionFile(v8end types.V8Endpoint, dir string, number int, filename string) error {
54 |
55 | return t.Task(WriteVersionFile{v8end, dir, filename, number})
56 |
57 | }
58 |
59 | func (t Flow) ReadVersionFile(v8end types.V8Endpoint, dir string, filename string) (int, error) {
60 |
61 | number := new(int)
62 |
63 | err := t.Task(ReadVersionFile{v8end, dir,
64 | filename, number})
65 | return *number, err
66 |
67 | }
68 |
69 | func (t Flow) CommitFiles(v8end types.V8Endpoint, dir string, author types.RepositoryAuthor, when time.Time, comment string) error {
70 |
71 | return t.Task(CommitFiles{v8end, dir, author, when, comment})
72 |
73 | }
74 |
75 | func (t Flow) GetRepositoryVersions(v8end types.V8Endpoint, dir string, NBegin, NEnd int, list *types.RepositoryVersionsList) error {
76 |
77 | err := t.Task(GetRepositoryVersions{
78 | V8end: v8end,
79 | Workdir: dir,
80 | NBegin: NBegin,
81 | NEnd: NEnd,
82 | Versions: list,
83 | })
84 |
85 | return err
86 | }
87 |
88 | func (t Flow) ConfigureRepositoryVersions(v8end types.V8Endpoint, versions *types.RepositoryVersionsList, NCurrent, NNext, NMax *int) (err error) {
89 |
90 | return t.Task(ConfigureRepositoryVersions{v8end, versions,
91 | NCurrent, NNext, NMax})
92 | }
93 |
94 | func (t Flow) GetRepositoryAuthors(v8end types.V8Endpoint, dir string, filename string, authors *types.RepositoryAuthorsList) error {
95 |
96 | return t.Task(GetRepositoryAuthors{v8end, dir, filename, authors})
97 | }
98 |
99 | func (t Flow) UpdateCfg(v8end types.V8Endpoint, workDir string, number int) error {
100 |
101 | return t.Task(UpdateCfg{v8end, workDir, number})
102 | }
103 |
104 | func (f Flow) Task(task Task) error {
105 | return DoTask(task, f.SubscribeManager)
106 | }
107 |
108 | type Task interface {
109 | Action(useStdHandler bool) error
110 | Before(pm *subscription.SubscribeManager) error
111 | On(pm *subscription.SubscribeManager, useStdHandler *bool) error
112 | After(pm *subscription.SubscribeManager) error
113 | }
114 |
115 | func DoTask(t Task, subscribeManager *subscription.SubscribeManager) (err error) {
116 |
117 | stdHandler := true
118 |
119 | if subscribeManager == nil {
120 | return t.Action(true)
121 | }
122 |
123 | if err = t.Before(subscribeManager); err != nil {
124 | return err
125 | }
126 |
127 | if err = t.On(subscribeManager, &stdHandler); err != nil {
128 | return err
129 | }
130 |
131 | if stdHandler {
132 | return t.Action(stdHandler)
133 | }
134 |
135 | if err = t.After(subscribeManager); err != nil {
136 | return err
137 | }
138 |
139 | return
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/internal/commands/cmdPlugins.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | //
4 | // import (
5 | // "fmt"
6 | // cli "github.com/jawher/mow.cli"
7 | // "github.com/khorevaa/r2gitsync/internal/app"
8 | // flags2 "github.com/khorevaa/r2gitsync/internal/app/flags"
9 | // "github.com/khorevaa/r2gitsync/internal/log"
10 | // "github.com/khorevaa/r2gitsync/pkg/plugin"
11 | // "os"
12 | // "strings"
13 | // "text/tabwriter"
14 | // )
15 | // import "github.com/mgutz/ansi"
16 | //
17 | // func (app *app.Application) cmdPluginsList(cmd *cli.Cmd) {
18 | //
19 | // var showAll bool
20 | //
21 | // flags2.BoolOpt("a all", false, "показать все плагины").
22 | // Ptr(&showAll).
23 | // Apply(cmd, app.ctx)
24 | //
25 | // cmd.Action = func() {
26 | // list := plugin.Plugins()
27 | //
28 | // log.Debugw("plugins list", "list", list)
29 | //
30 | // if len(list) > 0 {
31 | //
32 | // // w := os.Stdout
33 | // stdOut := os.Stderr
34 | // w := tabwriter.NewWriter(stdOut, 10, 1, 3, ' ', 0)
35 | // defer w.Flush()
36 | // _, _ = fmt.Fprintf(stdOut, "Список плагинов:\t\n")
37 | // _, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t %s\t\n", "Состояние", "Версия", "Имя", "Модули", "Описание")
38 | // _, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t %s\t\n", "---------", "------", "----", "------", "--------")
39 | // for _, arg := range list {
40 | //
41 | // if arg.Enable || showAll {
42 | // var (
43 | // enable = ansi.Color("выкл\t", "red")
44 | // name = arg.Name()
45 | // desc = arg.Desc()
46 | // version = arg.ShortVersion()
47 | // modules = strings.Join(arg.Modules(), ",")
48 | // )
49 | //
50 | // if arg.Enable {
51 | // enable = ansi.Color("вкл\t", "green")
52 | // }
53 | //
54 | // _, _ = fmt.Fprintf(w, "%s\t %s\t %s\t %s\t%s\n", enable, version, name, modules, desc)
55 | // }
56 | // }
57 | //
58 | // }
59 | //
60 | // }
61 | // }
62 | //
63 | // func (app *app.Application) cmdPluginsEnable(cmd *cli.Cmd) {
64 | //
65 | // var (
66 | // all bool
67 | // global bool
68 | // plNames []string
69 | // )
70 | // flags2.BoolOpt("a all", false, "включить все плагины").
71 | // Ptr(&all).
72 | // Apply(cmd, app.ctx)
73 | //
74 | // flags2.BoolOpt("save", false, "сохранить включенность плагина").
75 | // Ptr(&all).
76 | // Apply(cmd, app.ctx)
77 | //
78 | // flags2.BoolOpt("g global", false, "использовать глобальное хранилище плагинов").
79 | // Ptr(&global).
80 | // Apply(cmd, app.ctx)
81 | //
82 | // flags2.StringsArg("PLUGINS", plNames, "имена плагинов").
83 | // Ptr(&plNames).
84 | // Apply(cmd, app.ctx)
85 | //
86 | // cmd.Spec = "[-g | --global] PLUGINS... | --all"
87 | //
88 | // cmd.Action = func() {
89 | //
90 | // fmt.Printf("Включаю плагины")
91 | // fmt.Printf("Список плагинов: %s \n", plNames)
92 | //
93 | // }
94 | // }
95 | //
96 | // func (app *app.Application) cmdPluginsDisable(cmd *cli.Cmd) {
97 | //
98 | // var (
99 | // all bool
100 | // global bool
101 | // plNames []string
102 | // // local bool
103 | // )
104 | //
105 | // flags2.BoolOpt("a all", false, "выключить все плагины").
106 | // Ptr(&all).
107 | // Apply(cmd, app.ctx)
108 | //
109 | // flags2.BoolOpt("g global", false, "использовать глобальное хранилище плагинов").
110 | // Ptr(&global).
111 | // Apply(cmd, app.ctx)
112 | //
113 | // flags2.StringsArg("PLUGINS", plNames, "имена плагинов").
114 | // Ptr(&plNames).
115 | // Apply(cmd, app.ctx)
116 | //
117 | // cmd.Spec = "[-g | --global] PLUGINS... | --all"
118 | //
119 | // // flags.BoolOpt("l local", true, "использовать локальное хранилище плагинов").
120 | // // Ptr(&local).
121 | // // Apply(cmd, app.ctx)
122 | //
123 | // cmd.Action = func() {
124 | //
125 | // fmt.Printf("Отключаю плагины")
126 | // fmt.Printf("Список плагинов: %s \n", plNames)
127 | //
128 | // }
129 | // }
130 | //
131 | // func (app *app.Application) cmdPluginsClear(cmd *cli.Cmd) {
132 | //
133 | // var (
134 | // all bool
135 | // global bool
136 | // plNames []string
137 | // // local bool
138 | // )
139 | //
140 | // flags2.BoolOpt("a all", false, "удалить все плагины").
141 | // Ptr(&all).
142 | // Apply(cmd, app.ctx)
143 | //
144 | // flags2.BoolOpt("g global", false, "использовать глобальное хранилище плагинов").
145 | // Ptr(&global).
146 | // Apply(cmd, app.ctx)
147 | //
148 | // flags2.StringsArg("PLUGINS", plNames, "имена плагинов").
149 | // Ptr(&plNames).
150 | // Apply(cmd, app.ctx)
151 | //
152 | // cmd.Spec = "[-g | --global] PLUGINS... | --all"
153 | //
154 | // cmd.Action = func() {
155 | //
156 | // fmt.Printf("Удаляю плагины")
157 | // fmt.Printf("Список плагинов: %s \n", plNames)
158 | //
159 | // }
160 | // }
161 | //
162 | // func (app *app.Application) cmdPluginsInstall(cmd *cli.Cmd) {
163 | //
164 | // var (
165 | // files []string
166 | // global bool
167 | // )
168 | //
169 | // flags2.BoolOpt("g global", false, "использовать глобальное хранилище плагинов").
170 | // Ptr(&global).
171 | // Apply(cmd, app.ctx)
172 | //
173 | // flags2.StringsArg("FILE", files, "Путь к файлу плагина или zip ахриву с плагинами").
174 | // Ptr(&files).
175 | // Apply(cmd, app.ctx)
176 | //
177 | // cmd.Spec = "[OPTIONS] FILE..."
178 | //
179 | // cmd.Action = func() {
180 | //
181 | // fmt.Printf("Устанавливаю новые плагины")
182 | // // fmt.Printf( "Список плагинов: %s \n", files )
183 | //
184 | // }
185 | // }
186 |
--------------------------------------------------------------------------------
/internal/manager/sync.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | "fmt"
5 | "github.com/hashicorp/go-multierror"
6 | "github.com/khorevaa/r2gitsync/internal/manager/types"
7 | v8 "github.com/v8platform/api"
8 | "github.com/v8platform/designer"
9 | "io/ioutil"
10 | "log"
11 | "os"
12 | )
13 |
14 | type syncJob struct {
15 | name string
16 | workdir string
17 | tempDir string
18 | repo *designer.Repository
19 | infobase *v8.Infobase
20 | versions types.RepositoryVersionsList
21 | authors types.RepositoryAuthorsList
22 |
23 | increment bool
24 | currentVersion int
25 | minVersion int
26 | maxVersion int
27 |
28 | flow Flow
29 | log log.Logger
30 | endpoint types.V8Endpoint
31 | domainEmail string
32 |
33 | limitVersion int
34 | options []interface{}
35 |
36 | skipFiles []string
37 | }
38 |
39 | func (j *syncJob) Run() error {
40 |
41 | return j.start()
42 |
43 | }
44 |
45 | func (j *syncJob) start() (err error) {
46 |
47 | // j.log.Infow("Start sync with repository",
48 | // zap.String("name", j.name),
49 | // zap.String("path", j.repo.Path),
50 | // )
51 | //
52 | // j.log.Infow("Using infobase for sync",
53 | // zap.String("path", j.infobase.Connect.String()))
54 | //
55 | // if j.increment {
56 | // j.log.Infow("Using increment dump config to files")
57 | // }
58 |
59 | j.endpoint = &v8Endpoint{
60 | infobase: j.infobase,
61 | repository: j.repo,
62 | options: j.options,
63 | extention: j.repo.Extension,
64 | }
65 |
66 | taskFlow := j.flow
67 |
68 | taskFlow.StartSyncProcess(j.endpoint, j.workdir)
69 | defer taskFlow.FinishSyncProcess(j.endpoint, j.workdir, &err)
70 |
71 | j.currentVersion, err = taskFlow.ReadVersionFile(j.endpoint, j.workdir, VERSION_FILE)
72 |
73 | if err != nil {
74 | return err
75 | }
76 |
77 | err = taskFlow.GetRepositoryAuthors(j.endpoint, j.workdir, AUTHORS_FILE, &j.authors)
78 |
79 | if err != nil {
80 | return err
81 | }
82 |
83 | err = taskFlow.GetRepositoryVersions(j.endpoint, j.workdir, j.currentVersion, j.maxVersion, &j.versions)
84 | if err != nil {
85 | return err
86 | }
87 |
88 | if len(j.versions) == 0 {
89 | // j.log.Warn("No versions to sync")
90 | return nil
91 | }
92 |
93 | nextVersion := j.versions[0].Number()
94 | err = taskFlow.ConfigureRepositoryVersions(j.endpoint, &j.versions, &j.currentVersion, &nextVersion, &j.maxVersion)
95 |
96 | // j.log.Infow("Sync version number",
97 | // zap.Int("currentVersion", j.currentVersion),
98 | // zap.Int("maxVersion", j.maxVersion),
99 | // zap.Int("nextVersion", nextVersion),
100 | // )
101 |
102 | if err != nil {
103 | return err
104 | }
105 |
106 | for _, rVersion := range j.versions {
107 |
108 | if j.maxVersion != 0 &&
109 | rVersion.Number() > j.maxVersion {
110 | break
111 | }
112 |
113 | if nextVersion > rVersion.Number() {
114 | continue
115 | }
116 |
117 | err = j.syncVersionFiles(rVersion)
118 |
119 | if err != nil {
120 | return err
121 | }
122 |
123 | }
124 |
125 | return nil
126 |
127 | }
128 |
129 | func (j *syncJob) syncVersionFiles(rVersion types.RepositoryVersion) (err error) {
130 |
131 | tempDir, err := ioutil.TempDir(j.tempDir, fmt.Sprintf("v%d", rVersion.Number()))
132 |
133 | if err != nil {
134 | return err
135 | }
136 |
137 | flowTask := j.flow
138 |
139 | // j.log.Infow(fmt.Sprintf("Start process sources for version %d", rVersion.Number()),
140 | // zap.Int("number", rVersion.Number()))
141 | // startTime := time.Now()
142 |
143 | flowTask.StartSyncVersion(j.endpoint, j.workdir, tempDir, rVersion.Number())
144 |
145 | defer func() {
146 |
147 | flowTask.FinishSyncVersion(j.endpoint, j.workdir, tempDir, rVersion.Number(), &err)
148 |
149 | _ = os.RemoveAll(tempDir)
150 |
151 | // j.log.Infow(fmt.Sprintf("Finished process sources for version %d", rVersion.Number()),
152 | // zap.Int("number", rVersion.Number()),
153 | // zap.Float64("duration", time.Since(startTime).Seconds()),
154 | // zap.Error(err))
155 | }()
156 |
157 | err = flowTask.UpdateCfg(j.endpoint, j.workdir, rVersion.Number())
158 |
159 | if err != nil {
160 | return err
161 | }
162 |
163 | update, err := flowTask.DumpConfigToFiles(j.endpoint, j.workdir, tempDir, rVersion.Number(), j.increment)
164 |
165 | if err != nil {
166 | return err
167 | }
168 |
169 | if !update {
170 | err = flowTask.ClearWorkDir(j.endpoint, j.workdir, tempDir, j.skipFiles)
171 |
172 | if err != nil {
173 | return err
174 | }
175 | }
176 |
177 | err = flowTask.MoveToWorkDir(j.endpoint, j.workdir, tempDir)
178 |
179 | if err != nil {
180 | return err
181 | }
182 |
183 | err = flowTask.WriteVersionFile(j.endpoint, j.workdir, rVersion.Number(), VERSION_FILE)
184 |
185 | if err != nil {
186 | return err
187 | }
188 |
189 | err = flowTask.CommitFiles(j.endpoint, j.workdir,
190 | j.getRepositoryAuthor(rVersion.Author()), rVersion.Date(), rVersion.Comment())
191 |
192 | if err != nil {
193 |
194 | errV := flowTask.WriteVersionFile(j.endpoint, j.workdir, rVersion.Number(), VERSION_FILE)
195 | if errV != nil {
196 | return multierror.Append(err, errV)
197 | }
198 | return err
199 | }
200 |
201 | j.currentVersion = rVersion.Number()
202 |
203 | return
204 |
205 | }
206 |
207 | func (j *syncJob) getRepositoryAuthor(name string) types.RepositoryAuthor {
208 |
209 | author, ok := j.authors[name]
210 |
211 | if !ok {
212 |
213 | author = NewAuthor(name, fmt.Sprintf("%s@%s", name, j.domainEmail))
214 |
215 | j.authors[name] = author
216 | }
217 |
218 | return author
219 |
220 | }
221 |
--------------------------------------------------------------------------------
/internal/manager/helpers.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "github.com/khorevaa/r2gitsync/internal/manager/types"
7 | "golang.org/x/text/encoding"
8 | "io"
9 | "io/ioutil"
10 | "os"
11 | "path/filepath"
12 | "strings"
13 | "time"
14 | )
15 |
16 | type repositoryVersion struct {
17 | version string
18 | author string
19 | date time.Time
20 | comment string
21 | number int
22 | }
23 |
24 | func (r repositoryVersion) Version() string {
25 | return r.version
26 | }
27 |
28 | func (r repositoryVersion) Author() string {
29 | return r.author
30 | }
31 |
32 | func (r repositoryVersion) Date() time.Time {
33 | return r.date
34 | }
35 |
36 | func (r repositoryVersion) Comment() string {
37 | return r.comment
38 | }
39 |
40 | func (r repositoryVersion) Number() int {
41 | return r.number
42 | }
43 |
44 | type repositoryAuthor struct {
45 | name string
46 | email string
47 | }
48 |
49 | func (a repositoryAuthor) Name() string {
50 | return a.name
51 | }
52 |
53 | func (a repositoryAuthor) Email() string {
54 | return a.email
55 | }
56 |
57 | func (a repositoryAuthor) Desc() string {
58 |
59 | return fmt.Sprintf("%s <%s> ", a.name, a.email)
60 | }
61 |
62 | func NewAuthor(name, email string) types.RepositoryAuthor {
63 |
64 | return repositoryAuthor{
65 | name: name,
66 | email: email,
67 | }
68 |
69 | }
70 |
71 | func readFile(filePath string, Decoder *encoding.Decoder) (error, *[]byte) {
72 | // dec := charmap.Windows1251.NewDecoder()
73 |
74 | if fileB, err := ioutil.ReadFile(filePath); err == nil {
75 | // Разные кодировки = разные длины символов.
76 | if Decoder != nil {
77 | newBuf := make([]byte, len(fileB)*2)
78 | Decoder.Transform(newBuf, fileB, false)
79 |
80 | return nil, &newBuf
81 | } else {
82 | return nil, &fileB
83 | }
84 | } else {
85 | return fmt.Errorf("Ошибка открытия файла %q:\n %v", filePath, err), nil
86 | }
87 | }
88 |
89 | func Exists(name string) (bool, error) {
90 | _, err := os.Stat(name)
91 | if os.IsNotExist(err) {
92 | return false, err
93 | }
94 | return true, nil
95 | }
96 | func IsNoExist(name string) (bool, error) {
97 |
98 | ok, err := Exists(name)
99 | return !ok, err
100 | }
101 |
102 | func clearDir(dir string, skipFiles ...string) error {
103 |
104 | files, err := ioutil.ReadDir(dir)
105 | if err != nil {
106 | return err
107 | }
108 | for _, f := range files {
109 |
110 | _, file := filepath.Split(f.Name())
111 |
112 | if isSkipFile(file, skipFiles) {
113 | continue
114 | }
115 |
116 | if f.IsDir() {
117 | err := clearDir(filepath.Join(dir, file), skipFiles...)
118 | if err != nil {
119 | return err
120 | }
121 | }
122 |
123 | err := os.Remove(filepath.Join(dir, file))
124 | if err != nil {
125 | return err
126 | }
127 | // fmt.Println(f.Name())
128 | }
129 |
130 | return nil
131 | }
132 |
133 | func isSkipFile(file string, skipFiles []string) bool {
134 |
135 | for _, skipFile := range skipFiles {
136 |
137 | if strings.Contains(file, skipFile) {
138 | return true
139 | }
140 |
141 | }
142 |
143 | return false
144 | }
145 |
146 | func CopyFile(src, dst string) (err error) {
147 | in, err := os.Open(src)
148 | if err != nil {
149 | return
150 | }
151 | defer in.Close()
152 |
153 | out, err := os.Create(dst)
154 | if err != nil {
155 | return
156 | }
157 | defer func() {
158 | if e := out.Close(); e != nil {
159 | err = e
160 | }
161 | }()
162 |
163 | _, err = io.Copy(out, in)
164 | if err != nil {
165 | return
166 | }
167 |
168 | err = out.Sync()
169 | if err != nil {
170 | return
171 | }
172 |
173 | si, err := os.Stat(src)
174 | if err != nil {
175 | return
176 | }
177 | err = os.Chmod(dst, si.Mode())
178 | if err != nil {
179 | return
180 | }
181 |
182 | return
183 | }
184 |
185 | // CopyDir recursively copies a directory tree, attempting to preserve permissions.
186 | // Source directory must exist,
187 | // Symlinks are ignored and skipped.
188 | func CopyDir(src string, dst string) (err error) {
189 | src = filepath.Clean(src)
190 | dst = filepath.Clean(dst)
191 |
192 | si, err := os.Stat(src)
193 | if err != nil {
194 | return err
195 | }
196 | if !si.IsDir() {
197 | return fmt.Errorf("source is not a directory")
198 | }
199 |
200 | // _, err = os.Stat(dst)
201 | // if err != nil && !os.IsNotExist(err) {
202 | // return
203 | // }
204 |
205 | if ok, _ := Exists(dst); !ok {
206 |
207 | err = os.MkdirAll(dst, si.Mode())
208 | if err != nil {
209 | return
210 | }
211 | // return fmt.Errorf("destination already exists")
212 | }
213 |
214 | entries, err := ioutil.ReadDir(src)
215 | if err != nil {
216 | return
217 | }
218 |
219 | for _, entry := range entries {
220 | srcPath := filepath.Join(src, entry.Name())
221 | dstPath := filepath.Join(dst, entry.Name())
222 |
223 | if entry.IsDir() {
224 | err = CopyDir(srcPath, dstPath)
225 | if err != nil {
226 | return
227 | }
228 | } else {
229 | // Skip symlinks.
230 | if entry.Mode()&os.ModeSymlink != 0 {
231 | continue
232 | }
233 |
234 | err = CopyFile(srcPath, dstPath)
235 | if err != nil {
236 | return
237 | }
238 | }
239 | }
240 |
241 | return
242 | }
243 |
244 | // Decode decodes a byte slice into a signature
245 | func decodeAuthor(b []byte) (string, string) {
246 | open := bytes.LastIndexByte(b, '<')
247 | closeSym := bytes.LastIndexByte(b, '>')
248 | if open == -1 || closeSym == -1 {
249 | return "", ""
250 | }
251 |
252 | if closeSym < open {
253 | return "", ""
254 | }
255 |
256 | Name := string(bytes.Trim(b[:open], " "))
257 | Email := string(b[open+1 : closeSym])
258 |
259 | return Name, Email
260 |
261 | }
262 |
263 | func restoreTempExtension() (string, error) {
264 | tempFile, err := ioutil.TempFile("", ".cfe")
265 | defer tempFile.Close()
266 | if err != nil {
267 | return "", err
268 | }
269 |
270 | _, err = tempFile.Write(tempExtension)
271 |
272 | if err != nil {
273 | return "", err
274 | }
275 | return tempFile.Name(), nil
276 | }
277 |
--------------------------------------------------------------------------------
/internal/commands/context_test.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | //
4 | // import (
5 | // "bytes"
6 | // "errors"
7 | // "fmt"
8 | // "github.com/cucumber/godog"
9 | // "github.com/cucumber/messages-go/v10"
10 | // "github.com/go-git/go-billy/v5/osfs"
11 | // "github.com/go-git/go-git/v5"
12 | // "github.com/go-git/go-git/v5/plumbing/cache"
13 | // "github.com/go-git/go-git/v5/storage/filesystem"
14 | // manager2 "github.com/khorevaa/r2gitsync/internal/manager"
15 | // "github.com/khorevaa/r2gitsync/pkg/context"
16 | // "io/ioutil"
17 | // "os"
18 | // "path/filepath"
19 | // )
20 | //
21 | // type Context struct {
22 | // context.Context
23 | // Temp string
24 | //
25 | // Args []string
26 | // }
27 | //
28 | // type BaseSuite struct {
29 | // }
30 | //
31 | // func (s *BaseSuite) InitializeCmdSyncTestSuite(_ *godog.TestSuiteContext) {
32 | //
33 | // }
34 | //
35 | // func (s *BaseSuite) InitializeCmdSyncScenario(_ *godog.ScenarioContext) {
36 | // }
37 | //
38 | // func (s *Context) createTempDirAndSaveToContext(name string) error {
39 | //
40 | // dir, _ := ioutil.TempDir(s.Temp, "1c_temp")
41 | //
42 | // s.Set(name, dir)
43 | //
44 | // return nil
45 | //
46 | // }
47 | //
48 | // func (s *Context) initGitRepoFromContext(name string) error {
49 | //
50 | // dir := s.String(name)
51 | //
52 | // fs := osfs.New(dir)
53 | // dot, _ := fs.Chroot(".git")
54 | // storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
55 | //
56 | // r, err := git.Init(storage, fs)
57 | // if err != nil {
58 | // return err
59 | // }
60 | // _, err = fs.ReadDir(".git")
61 | // if err != nil {
62 | // return err
63 | // }
64 | // _, err = r.Config()
65 | //
66 | // if err != nil {
67 | // return err
68 | // }
69 | //
70 | // return err
71 | //
72 | // }
73 | //
74 | // func (s *Context) CopyDirToDirFromContext(dir, name string) error {
75 | //
76 | // dst := s.String(name)
77 | // src := filepath.Join(pwd, dir)
78 | // err := manager2.CopyDir(src, dst)
79 | // return err
80 | //
81 | // }
82 | //
83 | // func (s *Context) createTestFile(file, name string, data *messages.PickleStepArgument_PickleDocString) error {
84 | //
85 | // dir := s.String(name)
86 | //
87 | // // data := `Администратор=Админ <Администратор@localhost>`
88 | //
89 | // filename := filepath.Join(dir, file)
90 | // err := ioutil.WriteFile(filename, []byte(data.String()), 0644)
91 | // return err
92 | //
93 | // }
94 | //
95 | // func (s *Context) createTestVersion(ver int, name string) error {
96 | //
97 | // data := fmt.Sprintf(`
98 | // %d`, ver)
99 | // dir := s.String(name)
100 | //
101 | // filename := filepath.Join(dir, manager2.VERSION_FILE)
102 | // err := ioutil.WriteFile(filename, []byte(data), 0644)
103 | // return err
104 | //
105 | // }
106 | //
107 | // func (s *Context) fileContain(file, name string, data *messages.PickleStepArgument_PickleDocString) error {
108 | //
109 | // dir := s.String(name)
110 | //
111 | // filename := filepath.Join(dir, file)
112 | //
113 | // // Open our xmlFile
114 | // xmlFile, err := os.Open(filename)
115 | // // if we os.Open returns an error then handle it
116 | // if err != nil {
117 | // return err
118 | // }
119 | //
120 | // // defer the closing of our xmlFile so that we can parse it later on
121 | // defer xmlFile.Close()
122 | //
123 | // // read our opened xmlFile as a byte array.
124 | // byteValue, _ := ioutil.ReadAll(xmlFile)
125 | //
126 | // contains := bytes.Contains(byteValue, []byte(data.String()))
127 | //
128 | // if !contains {
129 | //
130 | // return errors.New(fmt.Sprintf("файл не содержить нужной строки\n Содержание:\n %s", string(byteValue)))
131 | // }
132 | //
133 | // return nil
134 | //
135 | // }
136 | //
137 | // func (s *Context) fileContainText(file, name string, data string) error {
138 | //
139 | // dir := s.String(name)
140 | //
141 | // filename := filepath.Join(dir, file)
142 | //
143 | // // Open our xmlFile
144 | // xmlFile, err := os.Open(filename)
145 | // // if we os.Open returns an error then handle it
146 | // if err != nil {
147 | // return err
148 | // }
149 | //
150 | // // defer the closing of our xmlFile so that we can parse it later on
151 | // defer xmlFile.Close()
152 | //
153 | // // read our opened xmlFile as a byte array.
154 | // byteValue, _ := ioutil.ReadAll(xmlFile)
155 | //
156 | // contains := bytes.Contains(byteValue, []byte(data))
157 | //
158 | // if !contains {
159 | //
160 | // return errors.New(fmt.Sprintf("файл не содержить нужной строки\n Содержание:\n %s", string(byteValue)))
161 | // }
162 | //
163 | // return nil
164 | //
165 | // }
166 | //
167 | // func (s *Context) setEnvValueFromContext(env, name string) error {
168 | //
169 | // value := s.String(name)
170 | // err := os.Setenv(env, value)
171 | //
172 | // return err
173 | // }
174 | //
175 | // func (s *Context) clearEnvs(envs *messages.PickleStepArgument_PickleTable) error {
176 | // rows := envs.GetRows()
177 | //
178 | // for _, row := range rows {
179 | // envName := row.Cells[0].Value
180 | //
181 | // err := os.Unsetenv(envName)
182 | // if err != nil {
183 | // return err
184 | // }
185 | //
186 | // }
187 | //
188 | // return nil
189 | // }
190 | //
191 | // func SharedContext(ctx *godog.ScenarioContext) *Context {
192 | //
193 | // step := &Context{
194 | // Context: context.NewContext(),
195 | // }
196 | // ctx.BeforeScenario(func(sc *godog.Scenario) {
197 | // step.Temp, _ = ioutil.TempDir("", "dbb_step")
198 | // })
199 | // ctx.Step(`^Я скопировал каталог "([^"]*)" в каталог из переменной "([^"]*)"$`, step.CopyDirToDirFromContext)
200 | // ctx.Step(`^Я создаю временный каталог и сохраняю его в переменной "([^"]*)"$`, step.createTempDirAndSaveToContext)
201 | // ctx.Step(`^Я инициализирую репозиторий в каталоге из переменной "([^"]*)"$`, step.initGitRepoFromContext)
202 | // ctx.Step(`^Я создаю тестовой файл "([^"]*)" в каталоге из переменной "([^"]*)" с текстом:$`, step.createTestFile)
203 | // // ctx.Step(`^Я записываю "([^"]*)" в файл "([^"]*) в каталоге из переменной "([^"]*)"$`, step.createTestVersion)
204 | // ctx.Step(`^Файл "([^"]*)" в каталоге из переменной "([^"]*)" содержит "([^"]*)"$`, step.fileContainText)
205 | // ctx.Step(`^Файл "([^"]*)" в каталоге из переменной "([^"]*)" содержит$`, step.fileContain)
206 | // ctx.Step(`^Я устанавливаю переменную окружения "([^"]*)" из переменной "([^"]*)"$`, step.setEnvValueFromContext)
207 | // ctx.Step(`^Я очищаю значение переменных окружения$`, step.clearEnvs)
208 | // ctx.AfterScenario(func(sc *godog.Scenario, err error) {
209 | // _ = os.RemoveAll(step.Temp)
210 | // })
211 | // return step
212 | // }
213 |
--------------------------------------------------------------------------------
/features/cmd/sync.feature:
--------------------------------------------------------------------------------
1 | # language: ru
2 |
3 | Функционал: Синхронизация хранилища конфигурации 1С и гит (команды sync)
4 | Как Пользователь
5 | Я хочу выполнять автоматическую синхронизацию конфигурации из хранилища
6 | Чтобы автоматизировать свою работы с хранилищем с git
7 |
8 | Контекст: Тестовый контекст
9 | Когда Я создаю временный каталог и сохраняю его в переменной "КаталогХранилища1С"
10 | И Я создаю временный каталог и сохраняю его в переменной "ПутьКаталогаИсходников"
11 | И Я инициализирую репозиторий в каталоге из переменной "ПутьКаталогаИсходников"
12 | И Я создаю тестовой файл "AUTHORS" в каталоге из переменной "ПутьКаталогаИсходников" с текстом:
13 | """
14 | Администратор=Администратор
15 | """
16 | И Я создаю тестовой файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" с текстом:
17 | """
18 |
19 | 0
20 | """
21 |
22 | # Сценарий: Cинхронизация хранилища с git-репозиторием
23 | # Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
24 | # И Я скопировал каталог "../tests/fixtures/storage" в каталог из переменной "КаталогХранилища1С"
25 | # И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
26 | # И Я добавляю параметр "--debug"
27 | # И Я добавляю параметр "sync"
28 | # И Я добавляю параметр из переменной "КаталогХранилища1С"
29 | # И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
30 | # Когда Я выполняю приложение
31 | # Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "2"
32 | #
33 | # Сценарий: Cинхронизация хранилища расширения с git-репозиторием
34 | # Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
35 | # И Я скопировал каталог "../tests/fixtures/extension_storage" в каталог из переменной "КаталогХранилища1С"
36 | # И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
37 | # И Я добавляю параметр "--debug"
38 | # И Я добавляю параметр "sync"
39 | # И Я добавляю параметр "-e=test"
40 | # И Я добавляю параметр из переменной "КаталогХранилища1С"
41 | # И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
42 | # Когда Я выполняю приложение
43 | # Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "4"
44 | #
45 | # Сценарий: Синхронизация хранилища с git-репозиторием с ошибкой авторизации
46 | # Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
47 | # И Я скопировал каталог "../tests/fixtures/extension_storage" в каталог из переменной "КаталогХранилища1С"
48 | # И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
49 | # И Я добавляю параметр "--debug"
50 | # И Я добавляю параметр "sync"
51 | # И Я добавляю параметр "-u Админ"
52 | # И Я добавляю параметр из переменной "КаталогХранилища1С"
53 | # И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
54 | # Когда Я выполняю приложение c ошибкой:
55 | # """
56 | #Ошибка аутентификации в хранилище конфигурации!
57 | # """
58 | # Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "0"
59 |
60 | # Сценарий: Синхронизация хранилища с git-репозиторием с использованием переменных окружения
61 | # Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
62 | # И Я скопировал каталог "../tests/fixtures/extension_storage" в каталог из переменной "КаталогХранилища1С"
63 | # И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
64 | # И Я добавляю параметр "--debug"
65 | # И Я добавляю параметр "sync"
66 | # И Я добавляю параметр "-e=test"
67 | # И Я устанавливаю переменную окружения "GITSYNC_STORAGE_PATH" из переменной "КаталогХранилища1С"
68 | # И Я устанавливаю переменную окружения "GITSYNC_WORKDIR" из переменной "ПутьКаталогаИсходников"
69 | # Когда Я выполняю приложение
70 | # Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "4"
71 | # И Я очищаю значение переменных окружения
72 | # |GITSYNC_STORAGE_PATH|
73 | # |GITSYNC_WORKDIR|
74 | #
75 | # Сценарий: Проверка ошибки не установленности пути к хранилищю 1С
76 | # Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
77 | # И Я скопировал каталог "../tests/fixtures/extension_storage" в каталог из переменной "КаталогХранилища1С"
78 | # И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
79 | # И Я добавляю параметр "--debug"
80 | # И Я добавляю параметр "sync"
81 | # И Я добавляю параметр "-e=test"
82 | # И Я устанавливаю переменную окружения "GITSYNC_WORKDIR" из переменной "ПутьКаталогаИсходников"
83 | # Когда Я выполняю приложение c ошибкой:
84 | # """
85 | #путь к репозиторию должен быть установлен
86 | # """
87 | # Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "0"
88 | # И Я очищаю значение переменных окружения
89 | # |GITSYNC_WORKDIR|
90 | #
91 | # Сценарий: Синхронизация с использованием готовой базы
92 | # Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
93 | # И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
94 | # И Я скопировал каталог "../tests/fixtures/storage" в каталог из переменной "КаталогХранилища1С"
95 | # И Я создаю временный каталог и сохраняю его в переменной "ВременнаяБаза"
96 | # И Я создаю пустую базы в каталоге из переменной "ВременнаяБаза"
97 | # И Я добавляю параметр без равно "--ib-connection=/F" из переменной "ВременнаяБаза"
98 | # И Я добавляю параметр "--debug"
99 | # И Я добавляю параметр "sync"
100 | # И Я добавляю параметр из переменной "КаталогХранилища1С"
101 | # И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
102 | # Когда Я выполняю приложение
103 | # Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "2"
104 | #
105 | Сценарий: Синхронизация с использованием готовой базы и польвазотеля
106 | Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
107 | И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
108 | И Я скопировал каталог "../tests/fixtures/storage" в каталог из переменной "КаталогХранилища1С"
109 | И Я создаю временный каталог и сохраняю его в переменной "ВременнаяБаза"
110 | И Я скопировал каталог "../tests/fixtures/ibWithAccess" в каталог из переменной "ВременнаяБаза"
111 | И Я добавляю параметр без равно "--ib-connection=/F" из переменной "ВременнаяБаза"
112 | И Я добавляю параметр "--ib-user=Администратор"
113 | И Я добавляю параметр "--ib-pwd=123"
114 | И Я добавляю параметр "--debug"
115 | И Я добавляю параметр "sync"
116 | И Я добавляю параметр из переменной "КаталогХранилища1С"
117 | И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
118 | Когда Я выполняю приложение
119 | Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "2"
120 |
121 | # Сценарий: Синхронизация с использованием пути к платформе 1С
122 | # Допустим Я создаю временный каталог и сохраняю его в переменной "ВременнаяДиректория"
123 | # И Я добавляю параметр "--tempdir" из переменной "ВременнаяДиректория"
124 | # И Я скопировал каталог "../tests/fixtures/storage" в каталог из переменной "КаталогХранилища1С"
125 | # И Я ищю платформу и сохраняю в переменной "ПутьКПлатформе1С"
126 | # И Я добавляю параметр "--v8-path" из переменной "ПутьКПлатформе1С"
127 | # И Я добавляю параметр "--ib-user=Администратор"
128 | # И Я добавляю параметр "--debug"
129 | # И Я добавляю параметр "sync"
130 | # И Я добавляю параметр из переменной "КаталогХранилища1С"
131 | # И Я добавляю параметр из переменной "ПутьКаталогаИсходников"
132 | # Когда Я выполняю приложение
133 | # Тогда Файл "VERSION" в каталоге из переменной "ПутьКаталогаИсходников" содержит "2"
134 |
--------------------------------------------------------------------------------
/pkg/plugin/storage/storage.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | //
4 | // import (
5 | // "crypto"
6 | // "errors"
7 | // plugin2 "github.com/khorevaa/r2gitsync/pkg/plugin"
8 | // metadata2 "github.com/khorevaa/r2gitsync/pkg/plugin/metadata"
9 | // "github.com/recoilme/pudge"
10 | // "io/ioutil"
11 | // "os"
12 | // "path/filepath"
13 | // pm "plugin"
14 | // "regexp"
15 | // "sync"
16 | // )
17 | //
18 | // const databaseFilename = "cache"
19 | // const PkgSymbolName = "PluginPackage"
20 | //
21 | // type PluginStorage interface {
22 | //
23 | // Load() error // Загружает плагины в внутренний индекс
24 | // Reload() error // Перечитывае плагины в внутренний индекс
25 | //
26 | // Store(filename string) error
27 | // Delete(name string) error
28 | // List() ([]metadata2.PluginMetadata, error)
29 | //
30 | // Clear() error
31 | // Registry(m plugin2.Manager) error
32 | //
33 | // }
34 | //
35 | // type FilePluginStorage struct {
36 | // mu sync.Mutex
37 | // Dir string
38 | // PkgIdx map[string]metadata2.PkgMetadata
39 | // PluginsIdx map[string][]metadata2.PluginMetadata
40 | //
41 | // loaded bool
42 | // database string
43 | // }
44 | //
45 | // func NewFilePluginStorage(dir string) *FilePluginStorage {
46 | //
47 | // return &FilePluginStorage{
48 | // Dir: dir,
49 | // database: filepath.Join(dir, databaseFilename),
50 | // PkgIdx: make(map[string]metadata2.PkgMetadata),
51 | // PluginsIdx: make(map[string][]metadata2.PluginMetadata),
52 | // }
53 | // }
54 | //
55 | // func (s *FilePluginStorage) Store(filename string) error {
56 | //
57 | //
58 | // // TODO Копирование файла
59 | // // TODO Проверка файла на плагины и зашрузка их метаданных
60 | //
61 | // return nil
62 | //
63 | // }
64 | //
65 | // func (s *FilePluginStorage) Delete(name string) error {
66 | //
67 | // return nil
68 | //
69 | // }
70 | //
71 | // func (s *FilePluginStorage) Registry(mng plugin2.Manager) error {
72 | //
73 | // err := s.Load()
74 | // if err != nil {
75 | // return err
76 | // }
77 | // var pl []plugin2.Symbol
78 | //
79 | // for _, pkgMetadata := range s.PkgIdx {
80 | //
81 | // err := pkgMetadata.Check()
82 | //
83 | // if err != nil {
84 | // continue
85 | // }
86 | //
87 | // pkgPlugins, _ := loadPkgPlugins(pkgMetadata)
88 | //
89 | // pl = append(pl, pkgPlugins...)
90 | //
91 | // }
92 | //
93 | // for _, storagePlugin := pl {
94 | // _ = mng.Register(storagePlugin)
95 | // }
96 | //
97 | // return nil
98 | // }
99 | //
100 | // func (s *FilePluginStorage) openDb() (*pudge.Db, error) {
101 | //
102 | // cfg := &pudge.Config{
103 | // SyncInterval: 30,
104 | // } // every second fsync
105 | // db, err := pudge.Open(s.database, cfg)
106 | // if err != nil {
107 | // return nil, err
108 | // }
109 | //
110 | // return db, nil
111 | // }
112 | //
113 | // func (s *FilePluginStorage) List() (ls []pluginMetadata, err error) {
114 | //
115 | // err = s.Load()
116 | // if err != nil {
117 | // return ls, err
118 | // }
119 | //
120 | // for _, metadata := range s.PkgIdx {
121 | //
122 | // ls = append(ls, metadata.plugins...)
123 | //
124 | // }
125 | //
126 | // return
127 | // }
128 | //
129 | // func (s *FilePluginStorage) Reload() error {
130 | //
131 | // err := s.updatePluginsFromDir()
132 | //
133 | // return err
134 | // }
135 | //
136 | //
137 | // func (s *FilePluginStorage) Load() error {
138 | //
139 | // if s.loaded {
140 | // return nil
141 | // }
142 | //
143 | // err := s.loadData()
144 | // return err
145 | // }
146 | //
147 | // func (s *FilePluginStorage) Clear() error {
148 | //
149 | // return clearDir(s.Dir)
150 | // }
151 | //
152 | // func (s *FilePluginStorage) loadData() error {
153 | //
154 | // db, err := s.openDb()
155 | // if err != nil {
156 | // return err
157 | // }
158 | //
159 | // defer db.Close()
160 | //
161 | // keys, err := db.Keys(nil, 0, 0, true)
162 | // if err == nil {
163 | // for _, key := range keys {
164 | //
165 | // var metadata pkgMetadata
166 | // err = db.Get(key, &metadata)
167 | // if err != nil {
168 | // return err
169 | // }
170 | //
171 | // s.PkgIdx[string(key)] = metadata
172 | // }
173 | // }
174 | //
175 | // s.loaded = true
176 | //
177 | // err = s.checkPkgIdx()
178 | // if err != nil {
179 | // return err
180 | // }
181 | //
182 | // return nil
183 | //
184 | // }
185 | //
186 | // func (s *FilePluginStorage) checkPkgIdx() error {
187 | //
188 | // err := s.Load()
189 | // if err != nil {
190 | // return err
191 | // }
192 | //
193 | // for _, metadata := range s.PkgIdx {
194 | // // TODO Провека наличия и хеша файла пакета
195 | // println(metadata)
196 | // }
197 | //
198 | // return nil
199 | // }
200 | //
201 | // func (s *FilePluginStorage) savePkgIdx() error {
202 | //
203 | // db, err := s.openDb()
204 | // if err != nil {
205 | // return err
206 | // }
207 | //
208 | // defer db.Close()
209 | //
210 | // for n, k := range s.PkgIdx {
211 | //
212 | // err = db.Set(n, k)
213 | // if err != nil {
214 | // return err
215 | // }
216 | // }
217 | //
218 | // return nil
219 | // }
220 | //
221 | // func (s *FilePluginStorage) updatePluginsFromDir() error {
222 | //
223 | // if len(s.Dir) == 0 {
224 | // return nil
225 | // }
226 | // if _, err := os.Stat(s.Dir); err != nil {
227 | // return err
228 | // }
229 | //
230 | // files, err := listFiles(s.Dir, `*.so`)
231 | // if err != nil {
232 | // return err
233 | // }
234 | //
235 | // s.PkgIdx = make(map[string]pkgMetadata)
236 | //
237 | // for _, file := range files {
238 | // filename := filepath.Join(s.Dir, file.Name())
239 | //
240 | // pkg, err := loadPkgMetadata(filename)
241 | // if err != nil {
242 | // log.Error(err)
243 | // continue
244 | // }
245 | //
246 | // s.PkgIdx[pkg.name] = pkg
247 | //
248 | // }
249 | //
250 | // err = s.savePkgIdx()
251 | //
252 | // return err
253 | // }
254 | //
255 | // func loadPluginFile(filename string) (pm.Symbol, error) {
256 | //
257 | // var pSymbol pm.Symbol
258 | //
259 | // pluginFile, err := pm.Open(filename)
260 | // if err != nil {
261 | // return pSymbol, err
262 | // }
263 | //
264 | // pSymbol, err = pluginFile.Lookup(PkgSymbolName)
265 | //
266 | // if err == nil {
267 | // return pSymbol, nil
268 | // }
269 | //
270 | // pSymbol, err = pluginFile.Lookup(plugin2.SymbolName)
271 | //
272 | // return pSymbol, err
273 | //
274 | // }
275 | //
276 | // func loadPkgPlugins(filename string) (pl []plugin2.Symbol, err error) {
277 | //
278 | // pSymbol, err := loadPluginFile(filename)
279 | //
280 | // if err != nil {
281 | // return pl, err
282 | // }
283 | //
284 | // switch sym := pSymbol.(type) {
285 | //
286 | // case PkgSymbol:
287 | //
288 | // return sym.Plugins(), nil
289 | //
290 | // case plugin2.Symbol:
291 | //
292 | // pl = append(pl, sym)
293 | //
294 | // default:
295 | // return nil, errors.New("plugin is not implement ")
296 | // }
297 | //
298 | // return
299 | // }
300 | //
301 | // func loadPkgMetadata(filename string) (pkg pkgMetadata, err error) {
302 | //
303 | // pSymbol, err := loadPluginFile(filename)
304 | //
305 | // if err != nil {
306 | // return pkg, err
307 | // }
308 | //
309 | // switch sym := pSymbol.(type) {
310 | //
311 | // case PkgSymbol:
312 | //
313 | // pkg = pkgMetadata{
314 | // name: sym.Name(),
315 | // file: filename,
316 | // hash: crypto.MD5, // TODO Расчет хеша файла
317 | // }
318 | //
319 | // pkg.plugins = pkg.getPluginMetadata(sym.Plugins()...)
320 | //
321 | // case plugin2.Symbol:
322 | //
323 | // pkg = pkgMetadata{
324 | // name: sym.Name(),
325 | // file: filename,
326 | // hash: crypto.MD5, // TODO Расчет хеша файла
327 | // }
328 | // pkg.plugins = pkg.getPluginMetadata(sym)
329 | //
330 | // default:
331 | // return pkgMetadata{}, errors.New("plugin is not impliment ")
332 | // }
333 | //
334 | // return
335 | // }
336 | //
337 | // func (pkg pkgMetadata) getPluginMetadata(p...plugin2.Symbol) (pm []pluginMetadata) {
338 | //
339 | // for _, symbol := range p {
340 | // pm = append(pm, pluginMetadata{
341 | // name: symbol.Name(),
342 | // file: pkg.file,
343 | // desc: symbol.Desc(),
344 | // modules: symbol.Modules(),
345 | // ver: symbol.ShortVersion(),
346 | // pkg: pkg.name,
347 | // hash: pkg.hash,
348 | // })
349 | // }
350 | // return
351 | // }
352 | //
353 | // func clearDir(dir string) error {
354 | //
355 | // files, err := ioutil.ReadDir(dir)
356 | // if err != nil {
357 | // return err
358 | // }
359 | // for _, f := range files {
360 | //
361 | // err = os.Remove(f.Name())
362 | // if err != nil {
363 | // return err
364 | // }
365 | // //fmt.Println(f.Name())
366 | // }
367 | //
368 | // return nil
369 | // }
370 | //
371 | //
372 | // func listFiles(dir, pattern string) ([]os.FileInfo, error) {
373 | // files, err := ioutil.ReadDir(dir)
374 | // if err != nil {
375 | // return nil, err
376 | // }
377 | //
378 | // var filteredFiles []os.FileInfo
379 | // for _, file := range files {
380 | // if file.IsDir() {
381 | // continue
382 | // }
383 | // matched, err := regexp.MatchString(pattern, file.Name())
384 | // if err != nil {
385 | // return nil, err
386 | // }
387 | // if matched {
388 | // filteredFiles = append(filteredFiles, file)
389 | // }
390 | // }
391 | // return filteredFiles, nil
392 | // }
393 |
--------------------------------------------------------------------------------
/internal/manager/manager_test.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | //
4 | // import (
5 | // "encoding/xml"
6 | // "fmt"
7 | // "github.com/cucumber/godog"
8 | // "github.com/go-git/go-billy/v5/osfs"
9 | // "github.com/go-git/go-git/v5"
10 | // "github.com/go-git/go-git/v5/plumbing/cache"
11 | // "github.com/go-git/go-git/v5/storage/filesystem"
12 | // "github.com/khorevaa/r2gitsync/tests/bdd"
13 | // "github.com/stretchr/testify/require"
14 | // "github.com/stretchr/testify/suite"
15 | // v8 "github.com/v8platform/api"
16 | // "github.com/v8platform/designer"
17 | // "github.com/v8platform/designer/tests"
18 | // "io/ioutil"
19 | // "os"
20 | // "path/filepath"
21 | // "testing"
22 | // )
23 | //
24 | // var pwd, _ = os.Getwd()
25 | //
26 | // type managerTestSuite struct {
27 | // suite.Suite
28 | //
29 | // SycnRepo *SyncRepository
30 | // RepositoryPath string
31 | // WorkdirPath string
32 | // ctx map[string]string
33 | // v8Version string
34 | // }
35 | //
36 | // func TestManagerTestSuite(t *testing.T) {
37 | // suite.Run(t, new(managerTestSuite))
38 | // }
39 | //
40 | // func (s *managerTestSuite) r() *require.Assertions {
41 | // return s.Require()
42 | // }
43 | //
44 | // func (s *managerTestSuite) AfterTest(suite, testName string) {
45 | //
46 | // }
47 | // func (s *managerTestSuite) BeforeTest(suite, testName string) {
48 | //
49 | // }
50 | //
51 | // func (s *managerTestSuite) TearDownSuite() {
52 | // os.RemoveAll(s.RepositoryPath)
53 | // os.RemoveAll(s.WorkdirPath)
54 | // }
55 | //
56 | // func (s *managerTestSuite) TearDownTest() {
57 | //
58 | // }
59 | // func (s *managerTestSuite) SetupSuite() {
60 | //
61 | // s.prepare()
62 | // }
63 | //
64 | // func (s *managerTestSuite) prepare() {
65 | //
66 | // // Скопировать хранилище 1 файл
67 | // // Создать git репо
68 | // // Создать файл AUTHORS
69 | // // СОздать файл VERSION
70 | // srcRepositoryFile := filepath.Join(pwd, "..", "tests", "fixtures", "storage")
71 | //
72 | // s.preRepository(srcRepositoryFile)
73 | // s.preWorkdir()
74 | // s.preVersion()
75 | //
76 | // }
77 | //
78 | // func (s *managerTestSuite) preVersion() {
79 | //
80 | // data := fmt.Sprintf(`
81 | // %d`, 0)
82 | //
83 | // filename := filepath.Join(s.WorkdirPath, VERSION_FILE)
84 | // err := ioutil.WriteFile(filename, []byte(data), 0644)
85 | // s.r().NoError(err)
86 | //
87 | // }
88 | //
89 | // func (s *managerTestSuite) preRepository(srcRepositoryFile string) {
90 | //
91 | // s.RepositoryPath, _ = ioutil.TempDir("", "1c_repo")
92 | //
93 | // dstRepoFile := filepath.Join(s.RepositoryPath, "1cv8ddb.1CD")
94 | //
95 | // err := CopyDir(srcRepositoryFile, s.RepositoryPath)
96 | // s.r().NoError(err)
97 | // fileBaseCreated, err := Exists(dstRepoFile)
98 | // s.r().True(fileBaseCreated, "Файл базы хранилища должен быть создан")
99 | //
100 | // }
101 | //
102 | // func (s *managerTestSuite) preWorkdir() {
103 | //
104 | // s.WorkdirPath, _ = ioutil.TempDir("", "1c_git")
105 | //
106 | // fs := osfs.New(s.WorkdirPath)
107 | // dot, _ := fs.Chroot(".git")
108 | // storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
109 | //
110 | // r, err := git.Init(storage, fs)
111 | // s.r().NoError(err)
112 | //
113 | // _, err = fs.ReadDir(".git")
114 | // s.r().NoError(err)
115 | //
116 | // cfg, err := r.Config()
117 | // s.r().NoError(err)
118 | // s.r().Equal(cfg.Core.Worktree, "")
119 | //
120 | // }
121 | //
122 | // func NewTempIB() tests.TempInfobase {
123 | //
124 | // path, _ := ioutil.TempDir("", "1c_DB_")
125 | //
126 | // ib := tests.TempInfobase{
127 | // // InfoBase: InfoBase{},
128 | // File: path,
129 | // }
130 | //
131 | // return ib
132 | // }
133 | //
134 | // func (s *managerTestSuite) TestSimpleSync() {
135 | //
136 | // repo := SyncRepository{
137 | // Name: "TestRepo",
138 | // Repository: designer.Repository{
139 | // Path: s.RepositoryPath,
140 | // },
141 | // Workdir: s.WorkdirPath,
142 | // }
143 | //
144 | // logger := log.NewLogger()
145 | // logger.SetDebug()
146 | //
147 | // err := repo.Sync(Options{
148 | // MinVersion: 0,
149 | // TempDir: v8.NewTempDir("", "tests_"),
150 | // Logger: logger,
151 | // })
152 | // s.r().NoError(err)
153 | //
154 | // }
155 | //
156 | // func (s *managerTestSuite) TestSyncExtension() {
157 | //
158 | // srcRepositoryFile := filepath.Join(pwd, "..", "tests", "fixtures", "extension_storage")
159 | //
160 | // s.preRepository(srcRepositoryFile)
161 | //
162 | // repo := SyncRepository{
163 | // Name: "TestExtension",
164 | // Repository: designer.Repository{
165 | // Path: s.RepositoryPath,
166 | // Extension: "MyExtension",
167 | // },
168 | // Workdir: s.WorkdirPath,
169 | // }
170 | //
171 | // logger := log.NewLogger()
172 | // logger.SetDebug()
173 | //
174 | // err := repo.Sync(Options{
175 | // TempDir: v8.NewTempDir("", "tests_"),
176 | // Logger: logger,
177 | // })
178 | // s.r().NoError(err)
179 | //
180 | // }
181 | //
182 | // func (s *managerTestSuite) TestFeatures() {
183 | //
184 | // err := bdd.Run([]string{"features/sync.feature"},
185 | // InitializeTestSuite,
186 | // InitializeScenario)
187 | //
188 | // s.r().NoError(err)
189 | //
190 | // }
191 | //
192 | // func InitializeTestSuite(context *godog.TestSuiteContext) {
193 | //
194 | // }
195 | //
196 | // func (s *managerTestSuite) ToContext(name string, value string) {
197 | //
198 | // s.ctx[name] = value
199 | //
200 | // }
201 | //
202 | // func (s *managerTestSuite) FromContext(name string) string {
203 | //
204 | // return s.ctx[name]
205 | //
206 | // }
207 | //
208 | // func (s *managerTestSuite) createTempDirAndSaveToContext(name string) error {
209 | //
210 | // dir, _ := ioutil.TempDir("", "1c_temp")
211 | //
212 | // s.ToContext(name, dir)
213 | //
214 | // return nil
215 | //
216 | // }
217 | //
218 | // func (s *managerTestSuite) initGitRepoFromContext(name string) error {
219 | //
220 | // dir := s.FromContext(name)
221 | //
222 | // fs := osfs.New(dir)
223 | // dot, _ := fs.Chroot(".git")
224 | // storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
225 | //
226 | // r, err := git.Init(storage, fs)
227 | // if err != nil {
228 | // return err
229 | // }
230 | // _, err = fs.ReadDir(".git")
231 | // if err != nil {
232 | // return err
233 | // }
234 | // _, err = r.Config()
235 | //
236 | // if err != nil {
237 | // return err
238 | // }
239 | // s.WorkdirPath = dir
240 | //
241 | // return err
242 | //
243 | // }
244 | //
245 | // func (s *managerTestSuite) createTestAuthors() error {
246 | //
247 | // data := `Администратор=Админ <Администратор@localhost>`
248 | //
249 | // filename := filepath.Join(s.WorkdirPath, AUTHORS_FILE)
250 | // err := ioutil.WriteFile(filename, []byte(data), 0644)
251 | // return err
252 | //
253 | // }
254 | //
255 | // func (s *managerTestSuite) createTestVersion(ver int) error {
256 | //
257 | // data := fmt.Sprintf(`
258 | // %d`, ver)
259 | //
260 | // filename := filepath.Join(s.WorkdirPath, VERSION_FILE)
261 | // err := ioutil.WriteFile(filename, []byte(data), 0644)
262 | // return err
263 | //
264 | // }
265 | //
266 | // func (s *managerTestSuite) copyTestRepoFromContext(name string) error {
267 | //
268 | // s.RepositoryPath = s.FromContext(name)
269 | //
270 | // srcRepository := filepath.Join(pwd, "..", "tests", "fixtures", "1cv8ddb.1CD")
271 | // // dstRepoFile := filepath.Join(s.RepositoryPath, "1cv8ddb.1CD")
272 | //
273 | // err := CopyDir(srcRepository, s.RepositoryPath)
274 | // return err
275 | //
276 | // }
277 | //
278 | // func (s *managerTestSuite) CopyDirToDirFromContext(dir, name string) error {
279 | //
280 | // s.RepositoryPath = s.FromContext(name)
281 | //
282 | // srcRepositoryDir := filepath.Join(pwd, "..", dir)
283 | // dstRepoDir := filepath.Join(s.RepositoryPath)
284 | //
285 | // err := CopyDir(srcRepositoryDir, dstRepoDir)
286 | // return err
287 | //
288 | // }
289 | //
290 | // func (s *managerTestSuite) setAuth(name string, pass string) error {
291 | //
292 | // if len(name) == 0 {
293 | // return nil
294 | // }
295 | //
296 | // s.SycnRepo.User = name
297 | // s.SycnRepo.Password = pass
298 | // return nil
299 | //
300 | // }
301 | //
302 | // func (s *managerTestSuite) setPlatformVersion(ver string) error {
303 | //
304 | // s.v8Version = ver
305 | // return nil
306 | //
307 | // }
308 | //
309 | // func (s *managerTestSuite) versionFileContain(ver int) error {
310 | //
311 | // type versionReader struct {
312 | // CurrentVersion int `xml:"VERSION"`
313 | // }
314 | // fileVersion := filepath.Join(s.WorkdirPath, VERSION_FILE)
315 | //
316 | // // Open our xmlFile
317 | // xmlFile, err := os.Open(fileVersion)
318 | // // if we os.Open returns an error then handle it
319 | // if err != nil {
320 | // return err
321 | // }
322 | //
323 | // // defer the closing of our xmlFile so that we can parse it later on
324 | // defer xmlFile.Close()
325 | //
326 | // var r = versionReader{}
327 | //
328 | // // read our opened xmlFile as a byte array.
329 | // byteValue, _ := ioutil.ReadAll(xmlFile)
330 | //
331 | // // xmlFiles content into 'users' which we defined above
332 | // err = xml.Unmarshal(byteValue, &r.CurrentVersion)
333 | //
334 | // if err != nil {
335 | // return err
336 | // }
337 | //
338 | // if r.CurrentVersion != ver {
339 | // return fmt.Errorf("файл не содержит нужной версии: %s", string(byteValue))
340 | // }
341 | //
342 | // return nil
343 | //
344 | // }
345 | //
346 | // func (s *managerTestSuite) doSync() error {
347 | //
348 | // repo := SyncRepository{
349 | // Name: "TestRepo",
350 | // Repository: designer.Repository{
351 | // Path: s.RepositoryPath,
352 | // User: s.SycnRepo.User,
353 | // Password: s.SycnRepo.Password,
354 | // },
355 | // Workdir: s.WorkdirPath,
356 | // }
357 | //
358 | // logger := log.NewLogger()
359 | // logger.SetDebug()
360 | //
361 | // err := repo.Sync(
362 | // Options{
363 | // TempDir: v8.NewTempDir("", "tests_"),
364 | // Logger: logger,
365 | // })
366 | //
367 | // return err
368 | //
369 | // }
370 | //
371 | // func (s *managerTestSuite) doSyncExt(extension string) error {
372 | //
373 | // repo := SyncRepository{
374 | // Name: "TestRepo",
375 | // Repository: designer.Repository{
376 | // Path: s.RepositoryPath,
377 | // User: s.SycnRepo.User,
378 | // Password: s.SycnRepo.Password,
379 | // Extension: extension,
380 | // },
381 | //
382 | // Workdir: s.WorkdirPath,
383 | // }
384 | // logger := log.NewLogger()
385 | // logger.SetDebug()
386 | //
387 | // err := repo.Sync(
388 | // Options{
389 | // TempDir: v8.NewTempDir("", "tests_"),
390 | // // Logger: logger,
391 | // },
392 | // )
393 | //
394 | // return err
395 | //
396 | // }
397 | //
398 | // func InitializeScenario(ctx *godog.ScenarioContext) {
399 | // feature := &managerTestSuite{
400 | // ctx: make(map[string]string),
401 | // SycnRepo: &SyncRepository{},
402 | // }
403 | //
404 | // ctx.Step(`^Я устанавливаю версию платформы "([^"]*)"$`, feature.setPlatformVersion)
405 | // ctx.Step(`^Я выполняю выполняют синхронизацию$`, feature.doSync)
406 | // ctx.Step(`^Я выполняю выполняют синхронизацию для расширения "([^"]*)"$`, feature.doSyncExt)
407 | // ctx.Step(`^Я создаю временный каталог и сохраняю его в переменной "([^"]*)"$`, feature.createTempDirAndSaveToContext)
408 | // ctx.Step(`^я скопировал каталог тестового хранилища конфигурации в каталог из переменной "([^"]*)"$`, feature.copyTestRepoFromContext)
409 | // ctx.Step(`^Я инициализирую репозиторий в каталоге из переменной "([^"]*)"$`, feature.initGitRepoFromContext)
410 | // // ctx.Step(`^Я включаю отладку лога с именем "([^"]*)"$`, StepDefinitioninition7)
411 | // ctx.Step(`^Я устанавливаю авторизацию в хранилище пользователя "([^"]*)" с паролем "([^"]*)"$`, feature.setAuth)
412 | // ctx.Step(`^Я создаю тестовой файл AUTHORS$`, feature.createTestAuthors)
413 | // ctx.Step(`^Я записываю "([^"]*)" в файл VERSION$`, feature.createTestVersion)
414 | // ctx.Step(`^Файл VERSION содержит (\d+)$`, feature.versionFileContain)
415 | // ctx.Step(`^я скопировал каталог "([^"]*)" в каталог из переменной "([^"]*)"$`, feature.CopyDirToDirFromContext)
416 | // ctx.AfterScenario(func(sc *godog.Scenario, err error) {
417 | // // os.RemoveAll(feature.RepositoryPath)
418 | // // os.RemoveAll(feature.WorkdirPath)
419 | // })
420 | // }
421 | //
422 | // func TestSync(t *testing.T) {
423 | //
424 | // if testing.Short() {
425 | // t.Skip("Integrated tests slipped")
426 | // }
427 | //
428 | // type args struct {
429 | // r SyncRepository
430 | // options Options
431 | // }
432 | //
433 | // tests := []struct {
434 | // name string
435 | // args args
436 | // wantErr bool
437 | // }{
438 | // {
439 | // "simple",
440 | // args{
441 | // r: SyncRepository{
442 | // Name: "simple",
443 | // Workdir: os.TempDir(),
444 | // Repository: designer.Repository{
445 | // Path: "",
446 | // },
447 | // },
448 | // options: Options{},
449 | // },
450 | // false,
451 | // },
452 | // }
453 | // for _, tt := range tests {
454 | // t.Run(tt.name, func(t *testing.T) {
455 | // if err := Sync(tt.args.r, tt.args.options); (err != nil) != tt.wantErr {
456 | // t.Errorf("Sync() error = %v, wantErr %v", err, tt.wantErr)
457 | // }
458 | // })
459 | // }
460 | // }
461 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3 | github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
4 | github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
5 | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
6 | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
7 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
8 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
9 | github.com/aslakhellesoy/gox v1.0.100/go.mod h1:AJl542QsKKG96COVsv0N74HHzVQgDIQPceVUh1aeU2M=
10 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
11 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
12 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
13 | github.com/cucumber/gherkin-go/v11 v11.0.0 h1:cwVwN1Qn2VRSfHZNLEh5x00tPBmZcjATBWDpxsR5Xug=
14 | github.com/cucumber/gherkin-go/v11 v11.0.0/go.mod h1:CX33k2XU2qog4e+TFjOValoq6mIUq0DmVccZs238R9w=
15 | github.com/cucumber/godog v0.10.0 h1:W01u1+o8bRpgqJRLrclN3iAanU1jAao+TwOMoSV9g1Y=
16 | github.com/cucumber/godog v0.10.0/go.mod h1:0Q+MOUg8Z9AhzLV+nNMbThQ2x1b17yYwGyahApTLjJA=
17 | github.com/cucumber/messages-go/v10 v10.0.1/go.mod h1:kA5T38CBlBbYLU12TIrJ4fk4wSkVVOgyh7Enyy8WnSg=
18 | github.com/cucumber/messages-go/v10 v10.0.3 h1:m/9SD/K/A15WP7i1aemIv7cwvUw+viS51Ui5HBw1cdE=
19 | github.com/cucumber/messages-go/v10 v10.0.3/go.mod h1:9jMZ2Y8ZxjLY6TG2+x344nt5rXstVVDYSdS5ySfI1WY=
20 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
21 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
23 | github.com/duke-git/lancet v1.1.8 h1:neOJRDmfeBKKc1tLmSpQPsM09h318COLv32dTqrmufE=
24 | github.com/duke-git/lancet v1.1.8/go.mod h1:d0jAaqqpHbJdPtWCtPfZ74BOaNvxdSQFyhYu/tjdP84=
25 | github.com/elastic/go-ucfg v0.8.3 h1:leywnFjzr2QneZZWhE6uWd+QN/UpP0sdJRHYyuFvkeo=
26 | github.com/elastic/go-ucfg v0.8.3/go.mod h1:iaiY0NBIYeasNgycLyTvhJftQlQEUO2hpF+FX0JKxzo=
27 | github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
28 | github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
29 | github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
30 | github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
31 | github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
32 | github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
33 | github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
34 | github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
35 | github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
36 | github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
37 | github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
38 | github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk=
39 | github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
40 | github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
41 | github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
42 | github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
43 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
44 | github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
45 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
46 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
47 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
48 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
49 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
50 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
51 | github.com/hashicorp/go-immutable-radix v1.2.0 h1:l6UW37iCXwZkZoAbEYnptSHVE/cQ5bOTPYG5W3vf9+8=
52 | github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
53 | github.com/hashicorp/go-memdb v1.2.1 h1:wI9btDjYUOJJHTCnRlAG/TkRyD/ij7meJMrLK9X31Cc=
54 | github.com/hashicorp/go-memdb v1.2.1/go.mod h1:OSvLJ662Jim8hMM+gWGyhktyWk2xPCnWMc7DWIqtkGA=
55 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
56 | github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
57 | github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
58 | github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
59 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
60 | github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
61 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
62 | github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
63 | github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
64 | github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
65 | github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
66 | github.com/jawher/mow.cli v1.2.0 h1:e6ViPPy+82A/NFF/cfbq3Lr6q4JHKT9tyHwTCcUQgQw=
67 | github.com/jawher/mow.cli v1.2.0/go.mod h1:y+pcA3jBAdo/GIZx/0rFjw/K2bVEODP9rfZOfaiq8Ko=
68 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
69 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
70 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
71 | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
72 | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
73 | github.com/khorevaa/go-v8platform v0.0.0-20200604183936-0990660c2e4f h1:XUxIxTBTVeSgdueqHIbC14d7qoa22atzt+t80g9WOak=
74 | github.com/khorevaa/go-v8platform v0.0.0-20200604183936-0990660c2e4f/go.mod h1:4i/ouKapwu2dxlZ5r4TZjBAg7wAfrRQ2bTzS4Yf5X9E=
75 | github.com/khorevaa/logos v0.9.8 h1:ZBRnxOJ5ORnELHH/Rarm1OQoIUHhae4WdHBwI4kgwZE=
76 | github.com/khorevaa/logos v0.9.8/go.mod h1:wLXbpwEXx1Je5HTf7EwgbJntj2kGPvvvAEbxqWlOZNA=
77 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
78 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
79 | github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
80 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
81 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
82 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
83 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
84 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
85 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
86 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
87 | github.com/lithammer/shortuuid/v3 v3.0.4 h1:uj4xhotfY92Y1Oa6n6HUiFn87CdoEHYUlTy0+IgbLrs=
88 | github.com/lithammer/shortuuid/v3 v3.0.4/go.mod h1:RviRjexKqIzx/7r1peoAITm6m7gnif/h+0zmolKJjzw=
89 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
90 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
91 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
92 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
93 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
94 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
95 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
96 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
97 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
98 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
99 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
100 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
101 | github.com/pkg/sftp v1.11.0 h1:4Zv0OGbpkg4yNuUtH0s8rvoYxRCNyT29NVUo6pgPmxI=
102 | github.com/pkg/sftp v1.11.0/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
103 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
104 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
105 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
106 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
107 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
108 | github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
109 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
110 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
111 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
112 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
113 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
114 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
115 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
116 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
117 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
118 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
119 | github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
120 | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
121 | github.com/v8platform/agent v0.0.0-20200703051804-b06e6737a7b5 h1:exdR2JPaLRuRvaLLyPzVHAZV7KkQGrblL2ch5J3Dkpg=
122 | github.com/v8platform/agent v0.0.0-20200703051804-b06e6737a7b5/go.mod h1:fLdJkSja8K++qa7+Lw4RQBHsEdS18GcE2F2BlFK33Z4=
123 | github.com/v8platform/api v0.2.2 h1:J+uyf8hfSHl5BiRf2DfEFPzLl5xXdu7KsGxqe4deQJM=
124 | github.com/v8platform/api v0.2.2/go.mod h1:w3d6YVdj3bRplPQ/61GkY5XEfKHLgLULIlif8BCSbV0=
125 | github.com/v8platform/designer v0.2.0/go.mod h1:pPkrPaXbTXLQHBfUu9+ikp4W6XRTN3iIF2/MNDTj4Sc=
126 | github.com/v8platform/designer v0.2.2 h1:9WbvhIPF33I3qb6t8W2UAqk7Ou/YaCAVFJzUMVS9z+4=
127 | github.com/v8platform/designer v0.2.2/go.mod h1:pPkrPaXbTXLQHBfUu9+ikp4W6XRTN3iIF2/MNDTj4Sc=
128 | github.com/v8platform/enterprise v0.1.0 h1:OKJ3ig9AvUDvIN+R0GRWJUPVNy5rPNtOKoqS2JPLnvw=
129 | github.com/v8platform/enterprise v0.1.0/go.mod h1:A2XY7UYAi/o9xdKrHzU63XnVD8wvIe6jMBUlUrNANQs=
130 | github.com/v8platform/errors v0.1.0 h1:7167okMmxBb76FA3+irT4LW9KTVura0vhMWnFDMHcZw=
131 | github.com/v8platform/errors v0.1.0/go.mod h1:7tASRzzC2AeE0NrQaYT6qfGO2alI0hW91fpoC3lPbQA=
132 | github.com/v8platform/find v0.0.0-20200629131701-72a40bdf1034 h1:tUWtou0ZdFgxfiePSkO9uQGuN+GkrA4nEWDjOb/OqZ8=
133 | github.com/v8platform/find v0.0.0-20200629131701-72a40bdf1034/go.mod h1:tfhUIhAlIplptMrqi6I2+ygI4CIsbMwCR1SMQ/4tDC0=
134 | github.com/v8platform/marshaler v0.0.0-20200630110446-ab0bd14c5414/go.mod h1:te7WaUpacxK3+jPl1Q9JtkxdNrgtxyAvmM1f3NFvLz8=
135 | github.com/v8platform/marshaler v0.1.1 h1:fcQIx0c818gYW1W45pP/NPttH8iZdYXjpkcKvaFKKQY=
136 | github.com/v8platform/marshaler v0.1.1/go.mod h1:te7WaUpacxK3+jPl1Q9JtkxdNrgtxyAvmM1f3NFvLz8=
137 | github.com/v8platform/runner v0.0.0-20200630132946-b282ee2b45e9/go.mod h1:k6Uxq8zjwUpcoswG0/OeJ60i91yeMKxBuPAHZbtJrSc=
138 | github.com/v8platform/runner v0.3.1 h1:jQfk3qXeUxCzof82KYi1QmeBSh9qqj9/EdK5MIXCnTU=
139 | github.com/v8platform/runner v0.3.1/go.mod h1:HAprOTYNuVMOyXLYGEL1Y4+BHzkrF46jB/h4Bn7TRUw=
140 | github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
141 | github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
142 | go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
143 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
144 | go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
145 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
146 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
147 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
148 | go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
149 | go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
150 | golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
151 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
152 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
153 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
154 | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
155 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
156 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
157 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
158 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
159 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
160 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
161 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
162 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
163 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
164 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
165 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
166 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
167 | golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
168 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
169 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
170 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
171 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
172 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
173 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
174 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
175 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
176 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
177 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
178 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
179 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
180 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
181 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
182 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
183 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
184 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
185 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
186 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
187 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
188 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
189 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
190 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
191 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
192 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
193 | gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
194 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
195 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
196 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
197 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
198 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
199 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
200 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
201 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
202 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
203 | honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
204 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
205 |
--------------------------------------------------------------------------------
/internal/manager/tasks.go:
--------------------------------------------------------------------------------
1 | package manager
2 |
3 | import (
4 | "bytes"
5 | "encoding/xml"
6 | "fmt"
7 | "github.com/khorevaa/r2gitsync/internal/manager/types"
8 | "github.com/khorevaa/r2gitsync/pkg/plugin/subscription"
9 | v8 "github.com/v8platform/api"
10 | "github.com/v8platform/designer"
11 | "io/ioutil"
12 | "os"
13 | "path/filepath"
14 | "regexp"
15 | "sort"
16 | "strconv"
17 | "strings"
18 | "time"
19 | )
20 |
21 | type UpdateCfg struct {
22 | V8end V8Endpoint
23 | WorkDir string
24 | Number int
25 | }
26 |
27 | func (t UpdateCfg) Before(pm *subscription.SubscribeManager) error {
28 | if pm == nil {
29 | return nil
30 | }
31 | return pm.UpdateCfg.Before(t.V8end, t.WorkDir, t.Number)
32 | }
33 |
34 | func (t UpdateCfg) After(pm *subscription.SubscribeManager) error {
35 | if pm == nil {
36 | return nil
37 | }
38 | return pm.UpdateCfg.After(t.V8end, t.WorkDir, t.Number)
39 | }
40 |
41 | func (t UpdateCfg) On(pm *subscription.SubscribeManager, useStdHandler *bool) error {
42 | if pm == nil {
43 | return nil
44 | }
45 | return pm.UpdateCfg.On(t.V8end, t.WorkDir, t.Number, useStdHandler)
46 | }
47 |
48 | func (t UpdateCfg) Action(useStdHandler bool) error {
49 |
50 | if !useStdHandler {
51 | return nil
52 | }
53 |
54 | updateCfg := t.V8end.Repository().UpdateCfg(int64(t.Number), true)
55 | return v8.Run(*t.V8end.Infobase(), updateCfg, t.V8end.Options()...)
56 |
57 | }
58 |
59 | type DumpConfigToFiles struct {
60 | V8end V8Endpoint
61 | WorkDir string
62 | TempDir string
63 | Number int
64 | Increment bool
65 | IsIncremented *bool
66 | }
67 |
68 | func (t DumpConfigToFiles) Before(pm *subscription.SubscribeManager) error {
69 | if pm == nil {
70 | return nil
71 | }
72 | return pm.DumpConfigToFiles.Before(t.V8end, t.WorkDir, t.TempDir, t.Number, &t.Increment)
73 | }
74 |
75 | func (t DumpConfigToFiles) After(pm *subscription.SubscribeManager) error {
76 | if pm == nil {
77 | return nil
78 | }
79 | return pm.DumpConfigToFiles.After(t.V8end, t.WorkDir, t.TempDir, t.Number, *t.IsIncremented)
80 | }
81 |
82 | func (t DumpConfigToFiles) On(pm *subscription.SubscribeManager, useStdHandler *bool) error {
83 | if pm == nil {
84 | return nil
85 | }
86 | return pm.DumpConfigToFiles.On(t.V8end, t.WorkDir, t.TempDir, t.Number, &t.Increment, useStdHandler)
87 | }
88 |
89 | func (t DumpConfigToFiles) Action(useStdHandler bool) error {
90 |
91 | if !useStdHandler {
92 | return nil
93 | }
94 |
95 | var configDumpInfoFile = ""
96 |
97 | if t.IsIncremented == nil {
98 | t.IsIncremented = new(bool)
99 | }
100 |
101 | if t.Increment {
102 | configDumpInfoFile = filepath.Join(t.WorkDir, ConfigDumpInfoFileName)
103 |
104 | if ok, _ := Exists(configDumpInfoFile); !ok {
105 | t.Increment = false
106 | configDumpInfoFile = ""
107 | }
108 | }
109 |
110 | if t.Increment {
111 |
112 | changesFile := v8.NewTempFile("", ".txt")
113 |
114 | getChangesForConfigDumpOptions := designer.GetChangesForConfigDumpOptions{
115 | Dir: t.TempDir,
116 | Force: true,
117 | GetChanges: changesFile,
118 | Extension: t.V8end.Extention(),
119 | ConfigDumpInfoForChanges: configDumpInfoFile,
120 | }
121 |
122 | err := v8.Run(*t.V8end.Infobase(), getChangesForConfigDumpOptions, t.V8end.Options()...)
123 |
124 | if err != nil {
125 | return err
126 | }
127 |
128 | t.Increment, err = t.checkChangesFile(changesFile)
129 | if err != nil {
130 | return err
131 | }
132 |
133 | if !t.Increment {
134 | configDumpInfoFile = ""
135 | }
136 | }
137 |
138 | DumpConfigToFilesOptions := designer.DumpConfigToFilesOptions{
139 | Dir: t.TempDir,
140 | Force: true,
141 | Update: t.Increment,
142 | Extension: t.V8end.Extention(),
143 | ConfigDumpInfoForChanges: configDumpInfoFile,
144 | }
145 |
146 | err := v8.Run(*t.V8end.Infobase(), DumpConfigToFilesOptions, t.V8end.Options()...)
147 | if err == nil && t.Increment {
148 | *t.IsIncremented = true
149 | }
150 |
151 | return err
152 |
153 | }
154 |
155 | func (t DumpConfigToFiles) checkChangesFile(filename string) (bool, error) {
156 | // Open our xmlFile
157 | file, err := os.Open(filename)
158 | // if we os.Open returns an error then handle it
159 | if err != nil {
160 | return false, err
161 | }
162 |
163 | // defer the closing of our xmlFile so that we can parse it later on
164 | defer file.Close()
165 |
166 | // read our opened xmlFile as a byte array.
167 | byteValue, _ := ioutil.ReadAll(file)
168 |
169 | fullDump := bytes.Contains(byteValue, []byte("FullDump"))
170 |
171 | return !fullDump, nil
172 | }
173 |
174 | type StartSyncVersion struct {
175 | V8end V8Endpoint
176 | WorkDir string
177 | TempDir string
178 | Number int
179 | }
180 |
181 | func (t StartSyncVersion) Before(pm *subscription.SubscribeManager) error {
182 | return nil
183 | }
184 |
185 | func (t StartSyncVersion) After(pm *subscription.SubscribeManager) error {
186 | return nil
187 | }
188 |
189 | func (t StartSyncVersion) On(pm *subscription.SubscribeManager, _ *bool) error {
190 | if pm == nil {
191 | return nil
192 | }
193 |
194 | pm.SyncVersion.Start(t.V8end, t.WorkDir, t.TempDir, t.Number)
195 |
196 | return nil
197 | }
198 |
199 | func (t StartSyncVersion) Action(useStdHandler bool) error {
200 | return nil
201 | }
202 |
203 | type FinishSyncVersion struct {
204 | V8end V8Endpoint
205 | WorkDir string
206 | TempDir string
207 | Number int
208 | Err *error
209 | }
210 |
211 | func (t FinishSyncVersion) Before(_ *subscription.SubscribeManager) error {
212 | return nil
213 | }
214 |
215 | func (t FinishSyncVersion) After(_ *subscription.SubscribeManager) error {
216 | return nil
217 | }
218 |
219 | func (t FinishSyncVersion) On(pm *subscription.SubscribeManager, _ *bool) error {
220 | if pm == nil {
221 | return nil
222 | }
223 |
224 | pm.SyncVersion.Finish(t.V8end, t.WorkDir, t.TempDir, t.Number, t.Err)
225 |
226 | return nil
227 | }
228 |
229 | func (t FinishSyncVersion) Action(_ bool) error {
230 | return nil
231 | }
232 |
233 | type StartSyncProcess struct {
234 | V8end V8Endpoint
235 | WorkDir string
236 | }
237 |
238 | func (t StartSyncProcess) Before(pm *subscription.SubscribeManager) error {
239 | return nil
240 | }
241 |
242 | func (t StartSyncProcess) After(pm *subscription.SubscribeManager) error {
243 | return nil
244 | }
245 |
246 | func (t StartSyncProcess) On(pm *subscription.SubscribeManager, _ *bool) error {
247 | if pm == nil {
248 | return nil
249 | }
250 |
251 | pm.SyncProcess.Start(t.V8end, t.WorkDir)
252 |
253 | return nil
254 | }
255 |
256 | func (t StartSyncProcess) Action(useStdHandler bool) error {
257 | return nil
258 | }
259 |
260 | type FinishSyncProcess struct {
261 | V8end V8Endpoint
262 | WorkDir string
263 | Err *error
264 | }
265 |
266 | func (t FinishSyncProcess) Before(_ *subscription.SubscribeManager) error {
267 | return nil
268 | }
269 |
270 | func (t FinishSyncProcess) After(_ *subscription.SubscribeManager) error {
271 | return nil
272 | }
273 |
274 | func (t FinishSyncProcess) On(pm *subscription.SubscribeManager, _ *bool) error {
275 | if pm == nil {
276 | return nil
277 | }
278 |
279 | pm.SyncProcess.Finish(t.V8end, t.WorkDir, t.Err)
280 |
281 | return nil
282 | }
283 |
284 | func (t FinishSyncProcess) Action(_ bool) error {
285 | return nil
286 | }
287 |
288 | type ConfigureRepositoryVersions struct {
289 | V8end V8Endpoint
290 | Versions *types.RepositoryVersionsList
291 | NBegin, NNext, NMax *int
292 | }
293 |
294 | func (t ConfigureRepositoryVersions) Before(pm *subscription.SubscribeManager) error {
295 | return nil
296 | }
297 |
298 | func (t ConfigureRepositoryVersions) After(pm *subscription.SubscribeManager) error {
299 | return nil
300 | }
301 |
302 | func (t ConfigureRepositoryVersions) On(pm *subscription.SubscribeManager, std *bool) error {
303 | if pm == nil {
304 | return nil
305 | }
306 |
307 | return pm.ConfigureRepositoryVersions.On(t.V8end, t.Versions, t.NBegin, t.NNext, t.NMax)
308 | }
309 |
310 | func (t ConfigureRepositoryVersions) Action(useStdHandler bool) error {
311 |
312 | if !useStdHandler {
313 | return nil
314 | }
315 |
316 | // TODO Добавить логику работы органичения
317 | // TODO Добавить логику получения максимальной версии
318 |
319 | ver := *t.Versions
320 |
321 | if len(ver) > 0 {
322 | maxVersion := ver[len(ver)-1].Number()
323 | *t.NMax = maxVersion
324 | }
325 |
326 | return nil
327 | }
328 |
329 | type GetRepositoryVersions struct {
330 | V8end V8Endpoint
331 | Workdir string
332 | NBegin, NEnd int
333 | Versions *types.RepositoryVersionsList
334 | }
335 |
336 | func (t GetRepositoryVersions) Before(pm *subscription.SubscribeManager) error {
337 | if pm == nil {
338 | return nil
339 | }
340 |
341 | err := pm.GetRepositoryHistory.Before(t.V8end, t.Workdir, t.NBegin)
342 |
343 | return err
344 | }
345 |
346 | func (t GetRepositoryVersions) After(pm *subscription.SubscribeManager) error {
347 |
348 | if pm == nil {
349 | return nil
350 | }
351 |
352 | err := pm.GetRepositoryHistory.After(t.V8end, t.Workdir, t.NBegin, t.Versions)
353 |
354 | return err
355 | }
356 |
357 | func (t GetRepositoryVersions) On(pm *subscription.SubscribeManager, std *bool) error {
358 | if pm == nil {
359 | return nil
360 | }
361 |
362 | v, err := pm.GetRepositoryHistory.On(t.V8end, t.Workdir, t.NBegin, std)
363 |
364 | if err == nil {
365 | *t.Versions = v
366 | }
367 |
368 | return err
369 | }
370 |
371 | func (t GetRepositoryVersions) Action(useStdHandler bool) (err error) {
372 |
373 | if !useStdHandler {
374 | return nil
375 | }
376 | //
377 | //t.log.Infow("Get repository versions",
378 | // zap.String("path", t.Workdir),
379 | // zap.Int("nBegin", t.NBegin))
380 |
381 | report := v8.NewTempFile("", "v8_rep_history")
382 | defer os.Remove(report)
383 |
384 | getReport := t.V8end.Repository().Report(report, int64(t.NBegin)).GroupByComment()
385 |
386 | err = v8.Run(t.V8end.Infobase(), getReport, t.V8end.Options()...)
387 |
388 | if err != nil {
389 | return
390 | }
391 |
392 | //t.log.Debugw("Parse repository report", zap.String("file", report))
393 |
394 | versions, err := t.parseRepositoryReport(report)
395 |
396 | if err != nil {
397 | return
398 | }
399 |
400 | sort.Slice(versions, func(i, j int) bool {
401 | return versions[i].Number() < versions[j].Number()
402 | })
403 |
404 | *t.Versions = versions
405 |
406 | return nil
407 | }
408 |
409 | func (t GetRepositoryVersions) parseRepositoryReport(file string) (versions []types.RepositoryVersion, err error) {
410 |
411 | err, bytes := readFile(file, nil)
412 | if err != nil {
413 | return
414 | }
415 |
416 | report := string(*bytes)
417 | // Двойные кавычки в комментарии мешают, по этому мы заменяем из на одинарные
418 | report = strings.Replace(report, "\"\"", "'", -1)
419 |
420 | tmpArray := [][]string{}
421 | reg := regexp.MustCompile(`[{]"#","([^"]+)["][\}]`)
422 | matches := reg.FindAllStringSubmatch(report, -1)
423 | for _, s := range matches {
424 | if s[1] == "Версия:" {
425 | tmpArray = append(tmpArray, []string{})
426 | }
427 |
428 | if len(tmpArray) > 0 {
429 | tmpArray[len(tmpArray)-1] = append(tmpArray[len(tmpArray)-1], s[1])
430 | }
431 | }
432 |
433 | for _, array := range tmpArray {
434 | versionInfo := repositoryVersion{}
435 | for id, s := range array {
436 | switch s {
437 | case "Версия:":
438 | if ver, err := strconv.Atoi(array[id+1]); err == nil {
439 | versionInfo.number = ver
440 | }
441 | case "Версия конфигурации:":
442 | versionInfo.version = array[id+1]
443 | case "Пользователь:":
444 | versionInfo.author = array[id+1]
445 | case "Комментарий:":
446 | // Комментария может не быть, по этому вот такой костыльчик
447 | if array[id+1] != "Изменены:" {
448 | versionInfo.comment = strings.Replace(array[id+1], "\n", " ", -1)
449 | versionInfo.comment = strings.Replace(array[id+1], "\r", "", -1)
450 | }
451 | case "Дата создания:":
452 | if t, err := time.Parse("02.01.2006", array[id+1]); err == nil {
453 | versionInfo.date = t
454 | }
455 | case "Время создания:":
456 | if !versionInfo.date.IsZero() {
457 | str := versionInfo.date.Format("02.01.2006") + " " + array[id+1]
458 | if t, err := time.Parse("02.01.2006 15:04:05", str); err == nil {
459 | versionInfo.date = t
460 | }
461 | }
462 | }
463 | }
464 | versions = append(versions, versionInfo)
465 | }
466 |
467 | return
468 | }
469 |
470 | type GetRepositoryAuthors struct {
471 | V8end V8Endpoint
472 | Workdir string
473 | Filename string
474 | Authors *types.RepositoryAuthorsList
475 | }
476 |
477 | func (t GetRepositoryAuthors) Before(pm *subscription.SubscribeManager) error {
478 | if pm == nil {
479 | return nil
480 | }
481 |
482 | err := pm.GetRepositoryAuthors.Before(t.V8end, t.Workdir, t.Filename)
483 |
484 | return err
485 | }
486 |
487 | func (t GetRepositoryAuthors) After(pm *subscription.SubscribeManager) error {
488 |
489 | if pm == nil {
490 | return nil
491 | }
492 |
493 | err := pm.GetRepositoryAuthors.After(t.V8end, t.Workdir, t.Authors)
494 |
495 | return err
496 | }
497 |
498 | func (t GetRepositoryAuthors) On(pm *subscription.SubscribeManager, std *bool) error {
499 | if pm == nil {
500 | return nil
501 | }
502 |
503 | v, err := pm.GetRepositoryAuthors.On(t.V8end, t.Workdir, t.Filename, std)
504 |
505 | if err == nil {
506 | *t.Authors = v
507 | }
508 |
509 | return err
510 | }
511 |
512 | func (t GetRepositoryAuthors) Action(useStdHandler bool) (err error) {
513 |
514 | if !useStdHandler {
515 | return nil
516 | }
517 | authors := make(map[string]types.RepositoryAuthor)
518 |
519 | file := filepath.Join(t.Workdir, t.Filename)
520 | if ok, _ := Exists(file); !ok {
521 |
522 | return nil
523 |
524 | }
525 |
526 | bytesRead, _ := ioutil.ReadFile(file)
527 | fileContent := string(bytesRead)
528 | lines := strings.Split(fileContent, "\n")
529 |
530 | for _, line := range lines {
531 |
532 | line = strings.TrimSpace(line)
533 |
534 | if len(line) == 0 || strings.HasPrefix(line, "//") {
535 | continue
536 | }
537 |
538 | data := strings.Split(line, "=")
539 |
540 | authors[data[0]] = NewAuthor(decodeAuthor([]byte(data[1])))
541 |
542 | }
543 |
544 | *t.Authors = authors
545 |
546 | return nil
547 | }
548 |
549 | type ClearWorkdir struct {
550 | V8end V8Endpoint
551 | Workdir string
552 | TempDir string
553 | SkipFiles []string
554 | }
555 |
556 | func (t ClearWorkdir) Before(pm *subscription.SubscribeManager) error {
557 | if pm == nil {
558 | return nil
559 | }
560 |
561 | return pm.ClearWorkdir.Before(t.V8end, t.Workdir, t.TempDir)
562 | }
563 |
564 | func (t ClearWorkdir) After(pm *subscription.SubscribeManager) error {
565 |
566 | if pm == nil {
567 | return nil
568 | }
569 |
570 | return pm.ClearWorkdir.After(t.V8end, t.Workdir, t.TempDir)
571 | }
572 |
573 | func (t ClearWorkdir) On(pm *subscription.SubscribeManager, std *bool) error {
574 | if pm == nil {
575 | return nil
576 | }
577 |
578 | return pm.ClearWorkdir.On(t.V8end, t.Workdir, t.TempDir, std)
579 | }
580 |
581 | func (t ClearWorkdir) Action(useStdHandler bool) (err error) {
582 |
583 | if !useStdHandler {
584 | return nil
585 | }
586 | err = clearDir(t.Workdir, t.SkipFiles...)
587 |
588 | return
589 | }
590 |
591 | type MoveToWorkdir struct {
592 | V8end V8Endpoint
593 | Workdir string
594 | TempDir string
595 | }
596 |
597 | func (t MoveToWorkdir) Before(pm *subscription.SubscribeManager) error {
598 | if pm == nil {
599 | return nil
600 | }
601 |
602 | return pm.MoveToWorkdir.Before(t.V8end, t.Workdir, t.TempDir)
603 | }
604 |
605 | func (t MoveToWorkdir) After(pm *subscription.SubscribeManager) error {
606 |
607 | if pm == nil {
608 | return nil
609 | }
610 |
611 | return pm.MoveToWorkdir.After(t.V8end, t.Workdir, t.TempDir)
612 | }
613 |
614 | func (t MoveToWorkdir) On(pm *subscription.SubscribeManager, std *bool) error {
615 | if pm == nil {
616 | return nil
617 | }
618 |
619 | return pm.MoveToWorkdir.On(t.V8end, t.Workdir, t.TempDir, std)
620 | }
621 |
622 | func (t MoveToWorkdir) Action(useStdHandler bool) (err error) {
623 |
624 | if !useStdHandler {
625 | return nil
626 | }
627 | err = CopyDir(t.TempDir, t.Workdir)
628 |
629 | return
630 | }
631 |
632 | type WriteVersionFile struct {
633 | V8end V8Endpoint
634 | Workdir string
635 | Filename string
636 | Version int
637 | }
638 |
639 | func (t WriteVersionFile) Before(pm *subscription.SubscribeManager) error {
640 | if pm == nil {
641 | return nil
642 | }
643 |
644 | return pm.WriteVersionFile.Before(t.V8end, t.Workdir, t.Version, t.Filename)
645 | }
646 |
647 | func (t WriteVersionFile) After(pm *subscription.SubscribeManager) error {
648 |
649 | if pm == nil {
650 | return nil
651 | }
652 |
653 | return pm.WriteVersionFile.After(t.V8end, t.Workdir, t.Version, t.Filename)
654 | }
655 |
656 | func (t WriteVersionFile) On(pm *subscription.SubscribeManager, std *bool) error {
657 | if pm == nil {
658 | return nil
659 | }
660 |
661 | return pm.WriteVersionFile.On(t.V8end, t.Workdir, t.Version, t.Filename, std)
662 | }
663 |
664 | func (t WriteVersionFile) Action(useStdHandler bool) (err error) {
665 |
666 | if !useStdHandler {
667 | return nil
668 | }
669 |
670 | data := fmt.Sprintf(`
671 | %d`, t.Version)
672 |
673 | filename := filepath.Join(t.Workdir, t.Filename)
674 | err = ioutil.WriteFile(filename, []byte(data), 0644)
675 |
676 | return
677 | }
678 |
679 | type CommitFiles struct {
680 | V8end V8Endpoint
681 | Workdir string
682 | Author types.RepositoryAuthor
683 | Date time.Time
684 | Comment string
685 | }
686 |
687 | func (t CommitFiles) Before(pm *subscription.SubscribeManager) error {
688 | if pm == nil {
689 | return nil
690 | }
691 |
692 | return pm.CommitFiles.Before(t.V8end, t.Workdir, t.Author, t.Date, t.Comment)
693 | }
694 |
695 | func (t CommitFiles) After(pm *subscription.SubscribeManager) error {
696 |
697 | if pm == nil {
698 | return nil
699 | }
700 |
701 | return pm.CommitFiles.After(t.V8end, t.Workdir, t.Author, t.Date, t.Comment)
702 | }
703 |
704 | func (t CommitFiles) On(pm *subscription.SubscribeManager, std *bool) error {
705 | if pm == nil {
706 | return nil
707 | }
708 |
709 | return pm.CommitFiles.On(t.V8end, t.Workdir, t.Author, &t.Date, &t.Comment, std)
710 | }
711 |
712 | func (t CommitFiles) Action(useStdHandler bool) (err error) {
713 |
714 | if !useStdHandler {
715 | return nil
716 | }
717 |
718 | return commitFiles(t.Workdir, t.Author, t.Date, t.Comment)
719 | }
720 |
721 | type ReadVersionFile struct {
722 | V8end V8Endpoint
723 | Workdir string
724 | Filename string
725 | Version *int
726 | }
727 |
728 | func (t ReadVersionFile) Before(pm *subscription.SubscribeManager) error {
729 | if pm == nil {
730 | return nil
731 | }
732 |
733 | return pm.ReadVersionFile.Before(t.V8end, t.Workdir, t.Filename)
734 | }
735 |
736 | func (t ReadVersionFile) After(pm *subscription.SubscribeManager) error {
737 |
738 | if pm == nil {
739 | return nil
740 | }
741 |
742 | return pm.ReadVersionFile.After(t.V8end, t.Workdir, t.Filename, t.Version)
743 | }
744 |
745 | func (t ReadVersionFile) On(pm *subscription.SubscribeManager, std *bool) error {
746 | if pm == nil {
747 | return nil
748 | }
749 |
750 | v, err := pm.ReadVersionFile.On(t.V8end, t.Workdir, t.Filename, std)
751 |
752 | if err == nil && t.Version != nil {
753 | *t.Version = v
754 | }
755 |
756 | return err
757 | }
758 |
759 | func (t ReadVersionFile) Action(useStdHandler bool) (err error) {
760 |
761 | if !useStdHandler {
762 | return nil
763 | }
764 |
765 | if t.Version == nil {
766 | t.Version = new(int)
767 | }
768 |
769 | type versionReader struct {
770 | CurrentVersion int `xml:"VERSION"`
771 | }
772 |
773 | fileVersion := filepath.Join(t.Workdir, t.Filename)
774 |
775 | // Open our xmlFile
776 | xmlFile, err := os.Open(fileVersion)
777 | // if we os.Open returns an error then handle it
778 | if err != nil {
779 | return err
780 | }
781 |
782 | // defer the closing of our xmlFile so that we can parse it later on
783 | defer xmlFile.Close()
784 |
785 | var r = versionReader{}
786 |
787 | // read our opened xmlFile as a byte array.
788 | byteValue, _ := ioutil.ReadAll(xmlFile)
789 |
790 | // xmlFiles content into 'users' which we defined above
791 | err = xml.Unmarshal(byteValue, &r.CurrentVersion)
792 |
793 | if err != nil {
794 | return err
795 | }
796 |
797 | *t.Version = r.CurrentVersion
798 |
799 | return nil
800 | }
801 |
--------------------------------------------------------------------------------