├── .github └── workflows │ └── releaser.yaml ├── .gitignore ├── .goreleaser.yml ├── .run └── go build github.com_khorevaa_r2gitsync.run.xml ├── LICENSE ├── README.md ├── TODO ├── cmd └── r2gitsync.go ├── features └── cmd │ ├── clone.feature │ ├── init.Feature │ ├── plugins.feature │ ├── setVersion.feature │ └── sync.feature ├── go.mod ├── go.sum ├── goreleaser.bat ├── goreleaser.sh ├── internal ├── commands │ ├── cmdInit.go │ ├── cmdPlugins.go │ ├── cmdSetVersion.go │ ├── commands.go │ ├── context_test.go │ ├── setVersion_test.go │ ├── shared_test.go │ ├── syncCmd.go │ └── syncCmd_test.go ├── config │ └── config.go ├── manager │ ├── features │ │ ├── sync-ext.feature │ │ └── sync.feature │ ├── flow.go │ ├── git.go │ ├── helpers.go │ ├── init.go │ ├── manager.go │ ├── manager_test.go │ ├── options.go │ ├── sync.go │ ├── tasks.go │ ├── tempExtension.cfe │ ├── types.go │ ├── types │ │ └── types.go │ └── v8Endpoint.go ├── plugins │ ├── limit │ │ └── limit.go │ ├── load.go │ └── plugins.go └── utils │ └── appdata.go ├── pkg └── plugin │ ├── config │ └── fileConfig.go │ ├── helpers.go │ ├── loader.go │ ├── manager.go │ ├── metadata │ ├── pkg.go │ ├── plugin.go │ └── types.go │ ├── plugin.go │ ├── storage │ └── storage.go │ ├── subscription │ ├── commitFiles.go │ ├── doc.go │ ├── dumpConfigToFiles.go │ ├── getRepositoryAuthors.go │ ├── getRepositoryHistory.go │ ├── handlers.go │ ├── helpers.go │ ├── subscription.go │ ├── sync.go │ ├── updatecfg.go │ ├── versionFile.go │ └── workdir.go │ ├── types.go │ └── types │ ├── commitFiles.go │ ├── doc.go │ ├── dumpConfigToFiles.go │ ├── getRepositoryAuthors.go │ ├── repositoryHistory.go │ ├── subscriber.go │ ├── syncProcess.go │ ├── syncVersion.go │ ├── updateCfg.go │ ├── versionFile.go │ └── workdir.go └── tests ├── bdd ├── run.go └── suite.go ├── fixtures ├── bigRepository │ └── 1cv8ddb.1CD ├── extension_storage │ ├── 1cv8ddb.1CD │ └── data │ │ ├── objects │ │ ├── 15 │ │ │ └── af5e8f18aea8397ae287ef2f0f237eca7ba410 │ │ ├── 51 │ │ │ └── ddb08f4a5453469fb93b1cdc90304d747357b7 │ │ ├── 90 │ │ │ └── 5786cba6e9271268f277226315b61c46427718 │ │ ├── 09 │ │ │ └── 0694564fb2cc20d4ee82dff29581aea6ebceb2 │ │ ├── 3e │ │ │ └── 09dd8ca40ee4c38920ec37b53860a6335d9749 │ │ └── fd │ │ │ └── 94de288b43ff531cadf282f9664dd70031a9cb │ │ ├── pack │ │ ├── pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.ind │ │ └── pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.pck │ │ └── ver ├── ibWithAccess │ └── 1Cv8.1CD └── storage │ └── 1cv8ddb.1CD └── r2gitsync.yaml /.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 -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # r2gitsync 2 | Sync 1C repository to git. Written on golang 3 | 4 | [![Release](https://img.shields.io/github/release/v8platform/oneget.svg?style=for-the-badge)](https://github.com/v8platform/oneget/releases/latest) 5 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=for-the-badge)](/LICENSE.md) 6 | [![Build status](https://img.shields.io/github/workflow/status/v8platform/oneget/goreleaser?style=for-the-badge)](https://github.com/v8platform/oneget/actions?workflow=goreleaser) 7 | [![Codecov branch](https://img.shields.io/codecov/c/github/v8platform/oneget/master.svg?style=for-the-badge)](https://codecov.io/gh/v8platform/oneget) 8 | [![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](http://godoc.org/github.com/v8platform/oneget) 9 | [![SayThanks.io](https://img.shields.io/badge/SayThanks.io-%E2%98%BC-1EAEDB.svg?style=for-the-badge)](https://saythanks.io/to/khorevaa) 10 | [![Powered By: GoReleaser](https://img.shields.io/badge/powered%20by-goreleaser-green.svg?style=for-the-badge)](https://github.com/goreleaser) 11 | [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=for-the-badge)](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 | ``` -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | [] Что-то сделать 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /features/cmd/clone.feature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/features/cmd/clone.feature -------------------------------------------------------------------------------- /features/cmd/init.Feature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/features/cmd/init.Feature -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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| -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /internal/manager/tempExtension.cfe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/internal/manager/tempExtension.cfe -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pkg/plugin/metadata/types.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | const ( 4 | PkgSymbolName = "PluginPackage" 5 | PluginSymbolName = "NewPlugin" 6 | ) 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /pkg/plugin/subscription/handlers.go: -------------------------------------------------------------------------------- 1 | package subscription 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/doc.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | //WriteVersionFile(v8end V8Endpoint, dir string, number int64, filename string) error 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests/fixtures/bigRepository/1cv8ddb.1CD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/bigRepository/1cv8ddb.1CD -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/1cv8ddb.1CD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/1cv8ddb.1CD -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/objects/09/0694564fb2cc20d4ee82dff29581aea6ebceb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/data/objects/09/0694564fb2cc20d4ee82dff29581aea6ebceb2 -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/objects/15/af5e8f18aea8397ae287ef2f0f237eca7ba410: -------------------------------------------------------------------------------- 1 | {0,0} -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/objects/3e/09dd8ca40ee4c38920ec37b53860a6335d9749: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/data/objects/3e/09dd8ca40ee4c38920ec37b53860a6335d9749 -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/objects/51/ddb08f4a5453469fb93b1cdc90304d747357b7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/data/objects/51/ddb08f4a5453469fb93b1cdc90304d747357b7 -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/objects/90/5786cba6e9271268f277226315b61c46427718: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/data/objects/90/5786cba6e9271268f277226315b61c46427718 -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/objects/fd/94de288b43ff531cadf282f9664dd70031a9cb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/data/objects/fd/94de288b43ff531cadf282f9664dd70031a9cb -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.ind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.ind -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.pck: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/extension_storage/data/pack/pack-c262dc49d0c6254821c6af2f1aaced0d0d28d2b3.pck -------------------------------------------------------------------------------- /tests/fixtures/extension_storage/data/ver: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /tests/fixtures/ibWithAccess/1Cv8.1CD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/ibWithAccess/1Cv8.1CD -------------------------------------------------------------------------------- /tests/fixtures/storage/1cv8ddb.1CD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khorevaa/r2gitsync/c4175ccb6ed6a95a79598531b2bd8d25925c133e/tests/fixtures/storage/1cv8ddb.1CD -------------------------------------------------------------------------------- /tests/r2gitsync.yaml: -------------------------------------------------------------------------------- 1 | debug: true 2 | tempdir: ./temp 3 | v8version: 8.3.1546 4 | plugins: 5 | limit: --------------------------------------------------------------------------------