Compare commits
12 Commits
Author | SHA1 | Date |
---|---|---|
DataHearth | 1241858027 | |
DataHearth | fab9533da1 | |
DataHearth | 1cfd84b8cf | |
DataHearth | f526bf1f5d | |
DataHearth | 3af07f159e | |
DataHearth | 638e0ff3a2 | |
DataHearth | 35d8210ca9 | |
DataHearth | 584fe09fe2 | |
DataHearth | a85165e8fe | |
DataHearth | 94b2838f7e | |
DataHearth | 71526ec28d | |
DataHearth | 759604ebda |
|
@ -2,13 +2,17 @@ storage:
|
|||
# Where will be the repository folder located ? [DEFAULT: MacOS($TMPDIR/config-mapper) | Linux(/tmp/config-mapper)]
|
||||
location: /path/to/folder
|
||||
git:
|
||||
# * by default, if ssh dict is set with its keys filled, I'll try to clone with SSH
|
||||
# username used for commit author
|
||||
name: USERNAME
|
||||
# email used for commit author
|
||||
email: EMAIL
|
||||
repository: git@github.com:DataHearth/my-config.git
|
||||
basic-auth:
|
||||
username: USERNAME
|
||||
# * NOTE: if you're having trouble with error "authentication required", you should maybe use a token access
|
||||
# * In some cases, it's due to 2FA authentication enabled on the git hosting provided
|
||||
password: TOKEN
|
||||
# * by default, if ssh dict is set with its keys filled, I'll try to clone with SSH
|
||||
ssh:
|
||||
# path can be relative and can contain environment variables
|
||||
private-key: /path/to/private/key
|
||||
|
|
|
@ -3,4 +3,6 @@
|
|||
.gitignore
|
||||
LICENSE
|
||||
README.md
|
||||
demo
|
||||
CHANGELOG.md
|
||||
.chglog
|
||||
build
|
|
@ -1,3 +1,3 @@
|
|||
.config-mapper.yml
|
||||
demo
|
||||
build
|
||||
build
|
||||
.DS_Store
|
37
CHANGELOG.md
37
CHANGELOG.md
|
@ -3,8 +3,38 @@
|
|||
## [Unreleased]
|
||||
|
||||
|
||||
<a name="0.1.0"></a>
|
||||
## 0.1.0 - 2022-02-27
|
||||
<a name="v0.2.0"></a>
|
||||
## [v0.2.0] - 2022-05-23
|
||||
### Bug Fixes
|
||||
- **config:** fix config path check
|
||||
- **copy:** use io.Copy instead of custom copy
|
||||
- **git:** use git binary for "git add"
|
||||
- **git:** deleted files are not pushed
|
||||
- **git:** add error handling and repo URL from config
|
||||
- **rm:** remove dir even if not empty
|
||||
- **stderr:** add stderr to brew command output
|
||||
|
||||
### Code Refactoring
|
||||
- **archi:** reduce base code to one struct
|
||||
- **cli:** separate functions from CLI for lisibility
|
||||
- **config:** unmarshal configuration instead of raw read
|
||||
- **logging:** drop pterm
|
||||
|
||||
### Features
|
||||
- **cli:** add configuration-file persistant flag
|
||||
- **cli:** add git push option with message
|
||||
- **cli:** add save and load features
|
||||
- **cli:** add init sub-command
|
||||
- **cli:** add copy folder
|
||||
- **cli:** add save command
|
||||
- **cli:** implement pkgs installation
|
||||
- **config:** update git configuration
|
||||
- **config:** add yaml tags for yaml.v3
|
||||
- **index:** add indexing system
|
||||
|
||||
|
||||
<a name="v0.1.0"></a>
|
||||
## v0.1.0 - 2022-02-27
|
||||
### Bug Fixes
|
||||
- **config:** fix config path check
|
||||
- **copy:** use io.Copy instead of custom copy
|
||||
|
@ -23,4 +53,5 @@
|
|||
- **config:** add yaml tags for yaml.v3
|
||||
|
||||
|
||||
[Unreleased]: https://github.com/DataHearth/config-mapper/compare/0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/DataHearth/config-mapper/compare/v0.2.0...HEAD
|
||||
[v0.2.0]: https://github.com/DataHearth/config-mapper/compare/v0.1.0...v0.2.0
|
||||
|
|
10
README.md
10
README.md
|
@ -107,12 +107,12 @@ The same ignore flags are used in the `save` command.
|
|||
|
||||
## TO-DO
|
||||
|
||||
- [] load configuration though SSH
|
||||
- [] save configuration though SSH
|
||||
- [ ] load configuration though SSH
|
||||
- [ ] save configuration though SSH
|
||||
- add more storage options
|
||||
- [] smb storage
|
||||
- [] nfs storage
|
||||
- [] zip
|
||||
- [ ] smb storage
|
||||
- [ ] nfs storage
|
||||
- [ ] zip
|
||||
|
||||
## Known issues
|
||||
|
||||
|
|
195
cmd/cli.go
195
cmd/cli.go
|
@ -1,12 +1,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
mapper "github.com/datahearth/config-mapper/internal"
|
||||
"github.com/pterm/pterm"
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
@ -28,89 +29,21 @@ var initCmd = &cobra.Command{
|
|||
Short: "Initialize your configuration folder",
|
||||
Long: `Initialize will retrieve your configuration folder from the source location and
|
||||
copy it into the destination field`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var config mapper.Configuration
|
||||
|
||||
if err := viper.Unmarshal(&config); err != nil {
|
||||
errLogger.Printf(pterm.Red(fmt.Sprintf("failed to decode configuration: %v\n", err)))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logger.Println("initializing config-mapper folder from configuration...")
|
||||
|
||||
if _, err := mapper.OpenGitRepo(config.Storage.Git, config.Storage.Location); err != nil {
|
||||
errLogger.Printf(pterm.Red(fmt.Sprintf("failed to initialize folder: %v\n", err)))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logger.Printf("repository initialized at \"%v\"\n", viper.GetString("storage.location"))
|
||||
},
|
||||
Run: initCommand,
|
||||
}
|
||||
var loadCmd = &cobra.Command{
|
||||
Use: "load",
|
||||
Short: "Load your configurations onto your system",
|
||||
Long: `Load your files, folders and package managers deps configurations onto your new
|
||||
onto your new system based on your configuration file`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var config mapper.Configuration
|
||||
|
||||
if err := viper.Unmarshal(&config); err != nil {
|
||||
errLogger.Printf(pterm.Red(fmt.Sprintf("failed to decode configuration: %v\n", err)))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !viper.GetBool("load-disable-files") {
|
||||
if err := mapper.LoadFiles(config.Files, config.Storage.Location); err != nil {
|
||||
errLogger.Printf(pterm.Red(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if !viper.GetBool("load-disable-folders") {
|
||||
if err := mapper.LoadFolders(config.Folders, config.Storage.Location); err != nil {
|
||||
errLogger.Printf(pterm.Red(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if !viper.GetBool("load-disable-pkgs") {
|
||||
if err := mapper.LoadPkgs(config.PackageManagers); err != nil {
|
||||
errLogger.Printf(pterm.Red(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
},
|
||||
Run: load,
|
||||
}
|
||||
var saveCmd = &cobra.Command{
|
||||
Use: "save",
|
||||
Short: "save your configurations onto your saved location",
|
||||
Long: `Save your files, folders and package managers deps configurations onto your
|
||||
saved location based on your configuration file`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var config mapper.Configuration
|
||||
|
||||
if err := viper.Unmarshal(&config); err != nil {
|
||||
errLogger.Printf(pterm.Red(fmt.Sprintf("failed to decode configuration: %v\n", err)))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !viper.GetBool("save-disable-files") {
|
||||
if err := mapper.SaveFiles(config.Files, config.Storage.Location); err != nil {
|
||||
errLogger.Printf(pterm.Red(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if !viper.GetBool("save-disable-folders") {
|
||||
if err := mapper.SaveFolders(config.Folders, config.Storage.Location); err != nil {
|
||||
errLogger.Printf(pterm.Red(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if !viper.GetBool("save-disable-pkgs") {
|
||||
if err := mapper.SavePkgs(config); err != nil {
|
||||
errLogger.Printf(pterm.Red(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
},
|
||||
Run: save,
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -132,9 +65,15 @@ func init() {
|
|||
saveCmd.PersistentFlags().Bool("disable-files", false, "files will be ignored")
|
||||
saveCmd.PersistentFlags().Bool("disable-folders", false, "folders will be ignored")
|
||||
saveCmd.PersistentFlags().Bool("disable-pkgs", false, "package managers will be ignored")
|
||||
saveCmd.Flags().BoolP("push", "p", false, "new configurations will be committed and pushed")
|
||||
saveCmd.Flags().StringP("message", "m", strconv.FormatInt(time.Now().Unix(), 10), "combined with --push to set a commit message")
|
||||
saveCmd.Flags().Bool("disable-index", false, "configuration index will not be updated")
|
||||
viper.BindPFlag("save-disable-files", saveCmd.PersistentFlags().Lookup("disable-files"))
|
||||
viper.BindPFlag("save-disable-folders", saveCmd.PersistentFlags().Lookup("disable-folders"))
|
||||
viper.BindPFlag("save-disable-pkgs", saveCmd.PersistentFlags().Lookup("disable-pkgs"))
|
||||
viper.BindPFlag("push", saveCmd.Flags().Lookup("push"))
|
||||
viper.BindPFlag("disable-index-update", saveCmd.Flags().Lookup("disable-index"))
|
||||
viper.BindPFlag("message", saveCmd.Flags().Lookup("message"))
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
|
@ -143,3 +82,113 @@ func Execute() {
|
|||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func save(cmd *cobra.Command, args []string) {
|
||||
var c mapper.Configuration
|
||||
if err := viper.Unmarshal(&c); err != nil {
|
||||
mapper.PrintError("failed to decode configuration: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
indexer, err := mapper.NewIndexer(c.Storage.Path)
|
||||
if err != nil {
|
||||
mapper.PrintError("failed to open the indexer: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
r, err := mapper.NewRepository(c.Storage.Git, c.Storage.Path)
|
||||
if err != nil {
|
||||
mapper.PrintError("failed to open repository at %s: %v\n", c.Storage.Path, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
el := mapper.NewItemsActions(nil, c.Storage.Path, r, indexer)
|
||||
|
||||
if !viper.GetBool("save-disable-files") {
|
||||
el.AddItems(c.Files)
|
||||
}
|
||||
if !viper.GetBool("save-disable-folders") {
|
||||
el.AddItems(c.Folders)
|
||||
}
|
||||
|
||||
el.Action("save")
|
||||
|
||||
if !viper.GetBool("save-disable-pkgs") {
|
||||
if err := mapper.SavePkgs(c); err != nil {
|
||||
mapper.PrintError(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if err := el.CleanUp(indexer.RemovedLines()); err != nil {
|
||||
mapper.PrintError("failed to clean repository: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if viper.GetBool("push") {
|
||||
color.Blue("# Pushing items")
|
||||
|
||||
if err := r.PushChanges(viper.GetString("message"), indexer.Lines(), indexer.RemovedLines()); err != nil {
|
||||
mapper.PrintError("failed to push changes to repository: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
color.Green("Items pushed")
|
||||
}
|
||||
}
|
||||
|
||||
func load(cmd *cobra.Command, args []string) {
|
||||
var c mapper.Configuration
|
||||
if err := viper.Unmarshal(&c); err != nil {
|
||||
mapper.PrintError("failed to decode configuration: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
i, err := mapper.NewIndexer(c.Storage.Path)
|
||||
if err != nil {
|
||||
mapper.PrintError("failed to open the indexer: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
r, err := mapper.NewRepository(c.Storage.Git, c.Storage.Path)
|
||||
if err != nil {
|
||||
mapper.PrintError("failed to open repository at %s: %v\n", c.Storage.Path, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
el := mapper.NewItemsActions(nil, c.Storage.Path, r, i)
|
||||
|
||||
if !viper.GetBool("load-disable-files") {
|
||||
el.AddItems(c.Files)
|
||||
}
|
||||
if !viper.GetBool("load-disable-folders") {
|
||||
el.AddItems(c.Folders)
|
||||
}
|
||||
|
||||
el.Action("load")
|
||||
|
||||
if !viper.GetBool("load-disable-pkgs") {
|
||||
if err := mapper.LoadPkgs(c.PackageManagers); err != nil {
|
||||
mapper.PrintError(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initCommand(cmd *cobra.Command, args []string) {
|
||||
var config mapper.Configuration
|
||||
|
||||
if err := viper.Unmarshal(&config); err != nil {
|
||||
mapper.PrintError("failed to decode configuration: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logger.Println("initializing config-mapper folder from configuration...")
|
||||
|
||||
if _, err := mapper.NewRepository(config.Storage.Git, config.Storage.Path); err != nil {
|
||||
mapper.PrintError("failed to initialize folder: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logger.Printf("repository initialized at \"%v\"\n", viper.GetString("storage.location"))
|
||||
}
|
||||
|
|
9
go.mod
9
go.mod
|
@ -4,7 +4,6 @@ go 1.17
|
|||
|
||||
require (
|
||||
github.com/go-git/go-git/v5 v5.4.2
|
||||
github.com/pterm/pterm v0.12.37
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/viper v1.10.1
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
|
@ -14,23 +13,22 @@ require (
|
|||
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/atomicgo/cursor v0.0.1 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.3.1 // indirect
|
||||
github.com/gookit/color v1.4.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
|
@ -38,7 +36,6 @@ require (
|
|||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
|
||||
|
|
31
go.sum
31
go.sum
|
@ -49,12 +49,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
|
||||
github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
|
||||
github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
|
||||
github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k=
|
||||
github.com/MarvinJWendt/testza v0.2.12 h1:/PRp/BF+27t2ZxynTiqj0nyND5PbOtfJS0SuTuxmgeg=
|
||||
github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
|
@ -77,8 +71,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
|||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/atomicgo/cursor v0.0.1 h1:xdogsqa6YYlLfM+GyClC/Lchf7aiMerFiZQn7soTOoU=
|
||||
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
|
@ -126,6 +118,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
|
@ -225,8 +218,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
|||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
|
||||
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
|
||||
|
@ -281,8 +272,6 @@ github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgy
|
|||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
|
@ -303,15 +292,15 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
|
|||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
|
@ -356,15 +345,6 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
|
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
|
||||
github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
|
||||
github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
|
||||
github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU=
|
||||
github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
|
||||
github.com/pterm/pterm v0.12.37 h1:QGOyuaDUmY3yTbP0k6i0uPNqNHA9YofEBQDy0tIyKTA=
|
||||
github.com/pterm/pterm v0.12.37/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
@ -406,8 +386,6 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
|||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
@ -614,14 +592,11 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/pterm/pterm"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -23,14 +22,16 @@ type ItemLocation struct {
|
|||
}
|
||||
|
||||
type Storage struct {
|
||||
Location string `mapstructure:"location" yaml:"location"`
|
||||
Git Git `mapstructure:"git" yaml:"git"`
|
||||
Path string `mapstructure:"location" yaml:"location"`
|
||||
Git Git `mapstructure:"git" yaml:"git"`
|
||||
}
|
||||
|
||||
type Git struct {
|
||||
Repository string `mapstructure:"repository" yaml:"repository"`
|
||||
BasicAuth BasicAuth `mapstructure:"basic-auth" yaml:"basic-auth"`
|
||||
SSH Ssh `mapstructure:"ssh" yaml:"ssh"`
|
||||
URL string `mapstructure:"repository" yaml:"repository"`
|
||||
Name string `mapstructure:"name" yaml:"name"`
|
||||
Email string `mapstructure:"email" yaml:"email"`
|
||||
BasicAuth BasicAuth `mapstructure:"basic-auth" yaml:"basic-auth"`
|
||||
SSH Ssh `mapstructure:"ssh" yaml:"ssh"`
|
||||
}
|
||||
|
||||
type BasicAuth struct {
|
||||
|
@ -80,9 +81,9 @@ func InitConfig() {
|
|||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
errLogger.Println(pterm.Red(err))
|
||||
PrintError(err.Error())
|
||||
} else {
|
||||
errLogger.Printf(pterm.Red(fmt.Sprintf("failed to read config: %v\n", err)))
|
||||
PrintError("failed to read config: %v\n", err)
|
||||
}
|
||||
|
||||
os.Exit(1)
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/pterm/pterm"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCopy = errors.New("failed to copy some files")
|
||||
ErrUnsupportedOS = errors.New("unsupported OS. Please, contact the maintainer")
|
||||
)
|
||||
|
||||
func LoadFiles(files []ItemLocation, location string) error {
|
||||
pterm.DefaultSection.Println("Save files into saved location")
|
||||
haveErr := false
|
||||
p, _ := pterm.DefaultProgressbar.WithTotal(len(files)).Start()
|
||||
|
||||
for _, f := range files {
|
||||
src, dst, err := configPaths(f, location)
|
||||
if err != nil {
|
||||
if err == ErrUnsupportedOS {
|
||||
return err
|
||||
}
|
||||
pterm.Error.Println(fmt.Sprintf("failed to destination resolve path \"%s\": %v", f.Linux, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path.Dir(dst), 0755); err != nil {
|
||||
pterm.Error.Printfln(fmt.Sprintf("failed to create directory architecture for destination path \"%s\": %v", dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
p.UpdateTitle(fmt.Sprintf("copying %s", src))
|
||||
|
||||
if err := copyFile(src, dst); err != nil {
|
||||
pterm.Error.Println(fmt.Sprintf("failed to load file from \"%s\" to \"%s\": %v", src, dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
pterm.Success.Println(fmt.Sprintf("%s copied", src))
|
||||
p.Increment()
|
||||
}
|
||||
|
||||
p.Stop()
|
||||
if haveErr {
|
||||
return ErrCopy
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SaveFiles(files []ItemLocation, location string) error {
|
||||
haveErr := false
|
||||
pterm.DefaultSection.Println("Save files into saved location")
|
||||
p, _ := pterm.DefaultProgressbar.WithTotal(len(files)).Start()
|
||||
|
||||
for _, f := range files {
|
||||
dst, src, err := configPaths(f, location)
|
||||
if err != nil {
|
||||
if err == ErrUnsupportedOS {
|
||||
return err
|
||||
}
|
||||
pterm.Error.Println(fmt.Sprintf("failed to destination resolve path \"%s\": %v", f.Linux, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
p.UpdateTitle(fmt.Sprintf("copying \"%s\"", src))
|
||||
|
||||
if err := os.MkdirAll(path.Dir(dst), 0755); err != nil {
|
||||
pterm.Error.Printfln(fmt.Sprintf("failed to create directory architecture for destination path \"%s\": %v", dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
if err := copyFile(src, dst); err != nil {
|
||||
pterm.Error.Println(fmt.Sprintf("failed to load file from \"%s\" to \"%s\": %v", src, dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
pterm.Success.Println(fmt.Sprintf("\"%s\" copied", src))
|
||||
p.Increment()
|
||||
}
|
||||
|
||||
p.Stop()
|
||||
if haveErr {
|
||||
return ErrCopy
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/pterm/pterm"
|
||||
)
|
||||
|
||||
var ErrFolderCopy = errors.New("failed to copy some folders")
|
||||
|
||||
func LoadFolders(folders []ItemLocation, location string) error {
|
||||
haveErr := false
|
||||
pterm.DefaultSection.Println("Load folders into saved location")
|
||||
p, _ := pterm.DefaultProgressbar.WithTotal(len(folders)).Start()
|
||||
|
||||
for _, f := range folders {
|
||||
src, dst, err := configPaths(f, location)
|
||||
if err != nil {
|
||||
if err == ErrUnsupportedOS {
|
||||
return err
|
||||
}
|
||||
pterm.Error.Println(fmt.Sprintf("failed to destination resolve path \"%s\": %v", f.Linux, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
s, err := os.Stat(src)
|
||||
if err != nil {
|
||||
pterm.Error.Println(fmt.Sprintf("failed to check if source path is a folder \"%s\": %v", src, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
if !s.IsDir() {
|
||||
pterm.Error.Println(fmt.Sprintf("source path is a file \"%s\"", src))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
p.UpdateTitle(fmt.Sprintf("copying folder \"%s\"", src))
|
||||
|
||||
if err := os.MkdirAll(dst, 0755); err != nil {
|
||||
pterm.Error.Printfln(fmt.Sprintf("failed to create directory architecture for destination path \"%s\": %v", dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
if err := copyFolder(src, dst); err != nil {
|
||||
pterm.Error.Println(fmt.Sprintf("failed to load folder from \"%s\" to \"%s\": %v", src, dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
pterm.Success.Println(fmt.Sprintf("\"%s\" copied", src))
|
||||
p.Increment()
|
||||
}
|
||||
|
||||
p.Stop()
|
||||
if haveErr {
|
||||
return ErrCopy
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SaveFolders(folders []ItemLocation, location string) error {
|
||||
haveErr := false
|
||||
pterm.DefaultSection.Println("Save folders into saved location")
|
||||
p, _ := pterm.DefaultProgressbar.WithTotal(len(folders)).Start()
|
||||
|
||||
for _, f := range folders {
|
||||
dst, src, err := configPaths(f, location)
|
||||
if err != nil {
|
||||
if err == ErrUnsupportedOS {
|
||||
return err
|
||||
}
|
||||
pterm.Error.Println(fmt.Sprintf("failed to destination resolve path \"%s\": %v", f.Linux, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
s, err := os.Stat(src)
|
||||
if err != nil {
|
||||
pterm.Error.Println(fmt.Sprintf("failed to check if source path is a folder \"%s\": %v", src, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
if !s.IsDir() {
|
||||
pterm.Error.Println(fmt.Sprintf("source path is a file \"%s\"", src))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
p.UpdateTitle(fmt.Sprintf("copying folder \"%s\"", src))
|
||||
|
||||
if err := os.MkdirAll(dst, 0755); err != nil {
|
||||
pterm.Error.Printfln(fmt.Sprintf("failed to create directory architecture for destination path \"%s\": %v", dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
if err := copyFolder(src, dst); err != nil {
|
||||
pterm.Error.Println(fmt.Sprintf("failed to save folder from \"%s\" to \"%s\": %v", src, dst, err))
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
|
||||
pterm.Success.Println(fmt.Sprintf("\"%s\" copied", src))
|
||||
p.Increment()
|
||||
}
|
||||
|
||||
p.Stop()
|
||||
if haveErr {
|
||||
return ErrCopy
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFolder(src, dst string) error {
|
||||
var haveErr bool
|
||||
|
||||
items, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, i := range items {
|
||||
itemName := i.Name()
|
||||
srcItem := fmt.Sprintf("%s/%s", src, itemName)
|
||||
dstItem := fmt.Sprintf("%s/%s", dst, itemName)
|
||||
|
||||
if i.IsDir() {
|
||||
os.Mkdir(dstItem, i.Type().Perm())
|
||||
copyFolder(srcItem, dstItem)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := copyFile(srcItem, dstItem); err != nil {
|
||||
haveErr = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if haveErr {
|
||||
return ErrFolderCopy
|
||||
}
|
||||
return nil
|
||||
}
|
181
internal/git.go
181
internal/git.go
|
@ -3,8 +3,11 @@ package mapper
|
|||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
|
||||
|
@ -15,56 +18,150 @@ var (
|
|||
ErrInvalidEnv = errors.New("found invalid environment variable in path")
|
||||
)
|
||||
|
||||
func OpenGitRepo(c Git, l string) (*git.Repository, error) {
|
||||
s, err := os.Stat(l)
|
||||
type RepositoryActions interface {
|
||||
PushChanges(msg string, newLines, removedLines []string) error
|
||||
GetWorktree() (*git.Worktree, error)
|
||||
GetAuthor() *object.Signature
|
||||
openRepository() error
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
auth transport.AuthMethod
|
||||
repository *git.Repository
|
||||
repoPath string
|
||||
author author
|
||||
url string
|
||||
}
|
||||
|
||||
type author struct {
|
||||
name string
|
||||
email string
|
||||
}
|
||||
|
||||
func NewRepository(config Git, repoPath string) (RepositoryActions, error) {
|
||||
var auth transport.AuthMethod
|
||||
if config.URL == "" {
|
||||
return nil, errors.New("a repository URI is needed (either using GIT protocol or HTTPS)")
|
||||
}
|
||||
repoPath, err := absolutePath(repoPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
var auth transport.AuthMethod
|
||||
|
||||
if c.SSH.Passphrase != "" && c.SSH.PrivateKey != "" {
|
||||
privateKey, err := absolutePath(c.SSH.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(privateKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
auth, err = ssh.NewPublicKeysFromFile("git", privateKey, c.SSH.Passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
auth = &http.BasicAuth{
|
||||
Username: c.BasicAuth.Username,
|
||||
Password: c.BasicAuth.Password,
|
||||
}
|
||||
}
|
||||
|
||||
repo, err := git.PlainClone(l, false, &git.CloneOptions{
|
||||
URL: c.Repository,
|
||||
Progress: os.Stdout,
|
||||
Auth: auth,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !s.IsDir() {
|
||||
return nil, ErrDirIsFile
|
||||
if config.SSH.Passphrase != "" && config.SSH.PrivateKey != "" {
|
||||
privateKey, err := absolutePath(config.SSH.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(privateKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
auth, err = ssh.NewPublicKeysFromFile("git", privateKey, config.SSH.Passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
auth = &http.BasicAuth{
|
||||
Username: config.BasicAuth.Username,
|
||||
Password: config.BasicAuth.Password,
|
||||
}
|
||||
}
|
||||
|
||||
repo, err := git.PlainOpen(l)
|
||||
if err != nil {
|
||||
repo := &Repository{
|
||||
auth: auth,
|
||||
repository: nil,
|
||||
repoPath: repoPath,
|
||||
url: config.URL,
|
||||
author: author{
|
||||
name: config.Name,
|
||||
email: config.Email,
|
||||
},
|
||||
}
|
||||
|
||||
if err := repo.openRepository(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func (r *Repository) openRepository() error {
|
||||
s, err := os.Stat(r.repoPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
repo, err := git.PlainClone(r.repoPath, false, &git.CloneOptions{
|
||||
URL: r.url,
|
||||
Progress: os.Stdout,
|
||||
Auth: r.auth,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.repository = repo
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if !s.IsDir() {
|
||||
return ErrDirIsFile
|
||||
}
|
||||
|
||||
repo, err := git.PlainOpen(r.repoPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.Pull(&git.PullOptions{
|
||||
Auth: r.auth,
|
||||
})
|
||||
if err != nil && err != git.NoErrAlreadyUpToDate {
|
||||
return err
|
||||
}
|
||||
|
||||
r.repository = repo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) PushChanges(msg string, newLines, removedLines []string) error {
|
||||
w, err := r.repository.Worktree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: investigated why w.AddWithOptions doesn't add removed files and sometimes .index
|
||||
cmd := exec.Command("git", "add", ".")
|
||||
cmd.Dir = r.repoPath
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Commit(msg, &git.CommitOptions{
|
||||
Author: r.GetAuthor(),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.repository.Push(&git.PushOptions{})
|
||||
}
|
||||
|
||||
func (r *Repository) GetWorktree() (*git.Worktree, error) {
|
||||
return r.repository.Worktree()
|
||||
}
|
||||
|
||||
func (r *Repository) GetAuthor() *object.Signature {
|
||||
return &object.Signature{
|
||||
Name: r.author.name,
|
||||
Email: r.author.email,
|
||||
When: time.Now(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
lines []string
|
||||
path string
|
||||
perms fs.FileMode
|
||||
repoPath string
|
||||
removedLines []string
|
||||
}
|
||||
|
||||
type Indexer interface {
|
||||
Write(newLines []string) error
|
||||
filter(configLines []string) map[string]bool
|
||||
RemovedLines() []string
|
||||
Lines() []string
|
||||
}
|
||||
|
||||
func NewIndexer(repoPath string) (Indexer, error) {
|
||||
perms := fs.FileMode(0755)
|
||||
indexPath, err := absolutePath(fmt.Sprintf("%s/.index", repoPath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var l []string
|
||||
s, err := os.Stat(indexPath)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l = []string{}
|
||||
} else {
|
||||
perms = s.Mode()
|
||||
|
||||
b, err := os.ReadFile(indexPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l = strings.Split(string(b), "\n")
|
||||
}
|
||||
|
||||
return &Index{
|
||||
lines: l,
|
||||
path: indexPath,
|
||||
perms: perms,
|
||||
repoPath: repoPath,
|
||||
removedLines: []string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (i *Index) RemovedLines() []string {
|
||||
return i.removedLines
|
||||
}
|
||||
|
||||
func (i *Index) Lines() []string {
|
||||
return i.lines
|
||||
}
|
||||
|
||||
// filter removes lines that are no more used in configuration from the index
|
||||
func (i *Index) filter(newLines []string) map[string]bool {
|
||||
removedLines := []string{}
|
||||
foundLines := map[string]bool{}
|
||||
for _, nl := range newLines {
|
||||
foundLines[nl] = true
|
||||
}
|
||||
for _, ml := range i.lines {
|
||||
if _, ok := foundLines[ml]; !ok {
|
||||
removedLines = append(removedLines, ml)
|
||||
}
|
||||
}
|
||||
|
||||
i.removedLines = removedLines
|
||||
return foundLines
|
||||
}
|
||||
|
||||
// Write add lines stored in memory the .index file
|
||||
func (i *Index) Write(newLines []string) error {
|
||||
lines := i.filter(newLines)
|
||||
|
||||
linesNumber := len(lines)
|
||||
var data []byte
|
||||
index := 0
|
||||
i.lines = []string{}
|
||||
for path := range lines {
|
||||
if index+1 == linesNumber {
|
||||
data = append(data, []byte(fmt.Sprint(path))...)
|
||||
} else {
|
||||
data = append(data, []byte(fmt.Sprintln(path))...)
|
||||
}
|
||||
|
||||
index += 1
|
||||
i.lines = append(i.lines, path)
|
||||
}
|
||||
|
||||
os.WriteFile(i.path, data, i.perms)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Items struct {
|
||||
locations []ItemLocation
|
||||
storage string
|
||||
repository RepositoryActions
|
||||
indexer Indexer
|
||||
}
|
||||
|
||||
type ItemsActions interface {
|
||||
Action(action string)
|
||||
AddItems(items []ItemLocation)
|
||||
CleanUp(removedLines []string) error
|
||||
}
|
||||
|
||||
func NewItemsActions(items []ItemLocation, storage string, repository RepositoryActions, indexer Indexer) ItemsActions {
|
||||
if items == nil {
|
||||
items = []ItemLocation{}
|
||||
}
|
||||
|
||||
return &Items{
|
||||
locations: items,
|
||||
storage: storage,
|
||||
repository: repository,
|
||||
indexer: indexer,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Items) Action(a string) {
|
||||
color.Blue("# %s", a)
|
||||
newLines := []string{}
|
||||
|
||||
for i, l := range e.locations {
|
||||
var src, dst string
|
||||
storagePath, systemPath, err := configPaths(l, e.storage)
|
||||
if err != nil {
|
||||
PrintError("[%d] failed to resolve item paths \"%v\": %v", i, l, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if a == "save" {
|
||||
src = systemPath
|
||||
dst = storagePath
|
||||
} else {
|
||||
src = storagePath
|
||||
dst = systemPath
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path.Dir(dst), 0755); err != nil {
|
||||
PrintError("[%d] failed to create directory architecture for destination path \"%s\": %v", i, path.Dir(dst), err)
|
||||
continue
|
||||
}
|
||||
|
||||
s, err := os.Stat(src)
|
||||
if err != nil {
|
||||
PrintError("[%d] failed to check if source path is a folder \"%s\": %v", i, src, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if s.IsDir() {
|
||||
dstPerms := fs.FileMode(0755)
|
||||
s, err := os.Stat(dst)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
PrintError("[%d] failed to check if destination folder \"%s\" exists: %v", i, dst, err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
dstPerms = s.Mode()
|
||||
}
|
||||
|
||||
if err := os.Mkdir(dst, dstPerms); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
PrintError("[%d] failed to create destination folder \"%s\": %v", i, dst, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err := copyFolder(src, dst); err != nil {
|
||||
PrintError("[%d] failed to %s folder from \"%s\" to \"%s\": %v", i, a, src, dst, err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if err := copyFile(src, dst); err != nil {
|
||||
PrintError("[%d] failed to %s file from \"%s\" to \"%s\": %v", i, a, src, dst, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if a == "save" {
|
||||
p, err := absolutePath(e.storage)
|
||||
if err != nil {
|
||||
PrintError("[%d] failed resolve absolute path from configuration storage: %v", i, err)
|
||||
continue
|
||||
}
|
||||
newLines = append(newLines, strings.ReplaceAll(dst, p+"/", ""))
|
||||
}
|
||||
|
||||
color.Green("[%d] %s copied", i, src)
|
||||
}
|
||||
|
||||
if a == "save" && !viper.GetBool("disable-index-update") {
|
||||
if err := e.indexer.Write(newLines); err != nil {
|
||||
PrintError(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Items) AddItems(items []ItemLocation) {
|
||||
e.locations = append(e.locations, items...)
|
||||
}
|
||||
|
||||
func (e *Items) CleanUp(removedLines []string) error {
|
||||
for _, l := range removedLines {
|
||||
path, err := absolutePath(fmt.Sprintf("%s/%s", e.storage, l))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return fmt.Errorf("failed to remove item %s: %v", l, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/pterm/pterm"
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
@ -22,18 +22,18 @@ var (
|
|||
)
|
||||
|
||||
func LoadPkgs(c PkgManagers) error {
|
||||
pterm.DefaultSection.Println("Load folders into saved location")
|
||||
color.Blue("# Load folders into saved location")
|
||||
|
||||
for _, pkg := range c.InstallationOrder {
|
||||
switch pkg {
|
||||
case "homebrew":
|
||||
if err := installBrewPkgs(c.Homebrew); err != nil {
|
||||
errLogger.Println(pterm.Red(err))
|
||||
PrintError(err.Error())
|
||||
return ErrFailedInstallation
|
||||
}
|
||||
case "apt":
|
||||
if err := installAptPkgs(c.Aptitude); err != nil {
|
||||
errLogger.Println(pterm.Red(err))
|
||||
PrintError(err.Error())
|
||||
return ErrFailedInstallation
|
||||
}
|
||||
}
|
||||
|
@ -43,13 +43,13 @@ func LoadPkgs(c PkgManagers) error {
|
|||
}
|
||||
|
||||
func SavePkgs(cfg Configuration) error {
|
||||
pterm.DefaultSection.Println("Save user installed packages")
|
||||
color.Blue("# Save user installed packages")
|
||||
|
||||
for _, pkg := range cfg.PackageManagers.InstallationOrder {
|
||||
switch pkg {
|
||||
case "homebrew":
|
||||
if err := SaveBrewPkgs(cfg); err != nil {
|
||||
errLogger.Println(pterm.Red(err))
|
||||
PrintError(err.Error())
|
||||
return ErrFailedSaving
|
||||
}
|
||||
case "apt":
|
||||
|
@ -65,7 +65,7 @@ func SaveBrewPkgs(cfg Configuration) error {
|
|||
return err
|
||||
}
|
||||
|
||||
introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(true).WithRemoveWhenDone(false).Start("Installing homebrew packages")
|
||||
color.Blue("## Saving Homebrew packages")
|
||||
|
||||
o, err := exec.Command("brew", "leaves", "--installed-on-request").Output()
|
||||
if err != nil {
|
||||
|
@ -84,9 +84,7 @@ func SaveBrewPkgs(cfg Configuration) error {
|
|||
return err
|
||||
}
|
||||
|
||||
introSpinner.Stop()
|
||||
introSpinner.Success("Packages intalled succesfully")
|
||||
|
||||
color.Green("Packages saved succesfully !")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -96,22 +94,21 @@ func installBrewPkgs(pkgs []string) error {
|
|||
}
|
||||
|
||||
if len(pkgs) == 0 {
|
||||
pterm.Println(pterm.Blue("homebrew: nothing to do"))
|
||||
fmt.Println("homebrew: nothing to do")
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("brew", "install")
|
||||
cmd.Args = append(cmd.Args, pkgs...)
|
||||
introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(true).WithRemoveWhenDone(false).Start("Installing homebrew packages")
|
||||
color.Blue("## Installing Homebrew packages")
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
introSpinner.Stop()
|
||||
introSpinner.SuccessPrinter.PrintOnErrorf("brew command failed", err)
|
||||
PrintError("brew command failed: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
introSpinner.Stop()
|
||||
introSpinner.Success("Packages intalled succesfully")
|
||||
color.Green("Packages intalled succesfully !")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -122,34 +119,21 @@ func installAptPkgs(pkgs []string) error {
|
|||
}
|
||||
|
||||
if len(pkgs) == 0 {
|
||||
pterm.Println(pterm.Blue("aptitude: nothing to do"))
|
||||
fmt.Println("aptitude: nothing to do")
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("sudo", "apt-get", "install")
|
||||
cmd.Args = append(cmd.Args, pkgs...)
|
||||
|
||||
introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(true).WithRemoveWhenDone(false).Start("Installing aptitude packages")
|
||||
color.Blue("## Installing aptitude packages")
|
||||
|
||||
chErr := make(chan error)
|
||||
defer close(chErr)
|
||||
|
||||
go func(chErr chan error) {
|
||||
if err := cmd.Run(); err != nil {
|
||||
chErr <- err
|
||||
return
|
||||
}
|
||||
|
||||
chErr <- nil
|
||||
}(chErr)
|
||||
|
||||
err := <-chErr
|
||||
introSpinner.Stop()
|
||||
if err != nil {
|
||||
if err := cmd.Run(); err != nil {
|
||||
PrintError("aptitude command failed: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
introSpinner.Success("Packages intalled succesfully")
|
||||
color.Green("Packages intalled succesfully !")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
func absolutePath(p string) (string, error) {
|
||||
|
@ -99,8 +102,47 @@ func configPaths(f ItemLocation, location string) (string, string, error) {
|
|||
return "", "", err
|
||||
}
|
||||
default:
|
||||
return "", "", ErrUnsupportedOS
|
||||
return "", "", errors.New("unsupported OS. Please, contact the maintainer")
|
||||
}
|
||||
|
||||
return src, dst, nil
|
||||
}
|
||||
|
||||
func copyFolder(src, dst string) error {
|
||||
items, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, i := range items {
|
||||
itemName := i.Name()
|
||||
srcItem := fmt.Sprintf("%s/%s", src, itemName)
|
||||
dstItem := fmt.Sprintf("%s/%s", dst, itemName)
|
||||
|
||||
if i.IsDir() {
|
||||
info, err := i.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(dstItem, info.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyFolder(srcItem, dstItem); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if err := copyFile(srcItem, dstItem); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func PrintError(err string, values ...interface{}) {
|
||||
color.Error.Write([]byte(color.RedString(err+"\n", values...)))
|
||||
}
|
||||
|
|
Reference in New Issue