diff options
| author | Shulhan <ms@kilabit.info> | 2018-05-27 06:17:06 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2018-05-27 06:17:06 +0700 |
| commit | c8635866b09a92ca42db2be2caf42bb6d4aab32c (patch) | |
| tree | fe41ed98fc99d496c4b2654225aa132113964949 | |
| parent | 7c4a8ec9afba55a7dbe7fbe56cb9e7d365ca892f (diff) | |
| download | beku-c8635866b09a92ca42db2be2caf42bb6d4aab32c.tar.xz | |
Implement freeze operation
Freeze operation operate on the package database and GOPATH. This
operation will ensure that all packages listed on database file is
installed with their specific version on GOPATH. Also, all packages that
are not registered will be removed from GOPATH "src" and "pkg" directories.
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | cmd/beku/command.go | 17 | ||||
| -rw-r--r-- | cmd/beku/command_test.go | 3 | ||||
| -rw-r--r-- | cmd/beku/main.go | 12 | ||||
| -rw-r--r-- | cmd/beku/operation.go | 1 | ||||
| -rw-r--r-- | env.go | 168 |
6 files changed, 204 insertions, 7 deletions
@@ -22,6 +22,16 @@ directory. If no file found, it will try to open package database, beku will scan entire "$GOPATH/src" and write the package database into "$GOPATH/var/beku/beku.db". +## Freeze Operation + + -B, --freeze + +Operate on the package database and GOPATH. This operation will ensure that +all packages listed on database file is installed with their specific +version on GOPATH. Also, all packages that are not registered will be +removed from GOPATH "src" and "pkg" directories. + + ## Query Operation -Q, --query [pkg ...] diff --git a/cmd/beku/command.go b/cmd/beku/command.go index 11392b3..d64c688 100644 --- a/cmd/beku/command.go +++ b/cmd/beku/command.go @@ -18,6 +18,7 @@ var ( const ( flagOperationHelp = "Show the short usage." + flagOperationFreeze = "Install all packages on database." flagOperationQuery = "Query the package database." flagOperationRemove = "Remove package." flagOperationSync = "Synchronize package. If no package is given, it will do rescan." @@ -41,6 +42,9 @@ operations: beku {-h|--help} ` + flagOperationHelp + ` + beku {-B|--freeze} + ` + flagOperationFreeze + ` + beku {-Q|--query} [pkg ...] ` + flagOperationQuery + ` @@ -116,6 +120,11 @@ func (cmd *command) parseShortFlags(arg string) (operation, error) { if len(arg) > 1 { return opNone, errInvalidOptions } + case 'B': + op = opFreeze + if len(arg) > 1 { + return opNone, errInvalidOptions + } case 'Q': op = opQuery if len(arg) > 1 { @@ -149,6 +158,8 @@ func (cmd *command) parseLongFlags(arg string) (op operation, err error) { switch arg { case "help": op = opHelp + case "freeze": + op = opFreeze case "into": op = opSyncInto case "query": @@ -224,7 +235,7 @@ func (cmd *command) parseFlags(args []string) (err error) { return } } - if cmd.op == opRecursive || cmd.op == opSyncInto { + if cmd.op == opRecursive || cmd.op == opSyncInto || cmd.op == opUpdate { return errInvalidOptions } if cmd.op&opSyncInto == opSyncInto { @@ -234,8 +245,8 @@ func (cmd *command) parseFlags(args []string) (err error) { } // (1) - op = cmd.op & (opQuery | opRemove | opSync) - if op == opQuery|opRemove || op == opQuery|opSync || op == opRemove|opSync { + op = cmd.op & (opFreeze | opQuery | opRemove | opSync) + if op != opFreeze && op != opQuery && op != opRemove && op != opSync { return errMultiOperations } diff --git a/cmd/beku/command_test.go b/cmd/beku/command_test.go index b64d3f4..8478c30 100644 --- a/cmd/beku/command_test.go +++ b/cmd/beku/command_test.go @@ -30,6 +30,9 @@ func TestParseFlags(t *testing.T) { args: []string{"--into"}, expErr: errInvalidOptions.Error(), }, { + args: []string{"--update"}, + expErr: errInvalidOptions.Error(), + }, { args: []string{"-s"}, expErr: errInvalidOptions.Error(), }, { diff --git a/cmd/beku/main.go b/cmd/beku/main.go index 6c15c38..2d0190c 100644 --- a/cmd/beku/main.go +++ b/cmd/beku/main.go @@ -14,6 +14,16 @@ // package database, beku will scan entire "$GOPATH/src" and write the // package database into "$GOPATH/var/beku/beku.db". // +// ## Freeze Operation +// +// -B, --freeze +// +// Operate on the package database and GOPATH. This operation will ensure that +// all packages listed on database file is installed with their specific +// version on GOPATH. Also, all packages that are not registered will be +// removed from GOPATH "src" and "pkg" directories. +// +// // ## Query Operation // // -Q, --query [pkg ...] @@ -143,6 +153,8 @@ func main() { case opHelp: cmd.usage() os.Exit(1) + case opFreeze: + err = cmd.env.Freeze() case opQuery: cmd.env.Query(cmd.pkgs) case opRemove: diff --git a/cmd/beku/operation.go b/cmd/beku/operation.go index 1b51ed7..5925166 100644 --- a/cmd/beku/operation.go +++ b/cmd/beku/operation.go @@ -6,6 +6,7 @@ const opNone operation = 0 const ( opHelp operation = 1 << iota + opFreeze opQuery opRecursive opRemove @@ -33,6 +33,7 @@ type Env struct { pkgs []*Package pkgsMissing []string pkgsStd []string + pkgsUnused []*Package db *ini.Ini dbDefFile string dbFile string @@ -74,6 +75,109 @@ func NewEnvironment() (env *Env, err error) { return } +func (env *Env) cleanUnused() { + for _, pkg := range env.pkgsUnused { + fmt.Println(">>> Removing source at", pkg.FullPath) + _ = pkg.Remove() + + pkgPath := filepath.Join(env.dirPkg, pkg.ImportPath) + + fmt.Println(">>> Removing installed binaries at", pkgPath) + _ = os.RemoveAll(pkgPath) + _ = RmdirEmptyAll(pkgPath) + } +} + +// +// Freeze all packages in GOPATH. Install all registered packages in database +// and remove non-registered from GOPATH "src" and "pkg" directories. +// +func (env *Env) Freeze() (err error) { + var localPkg *Package + + for _, pkg := range env.pkgs { + fmt.Printf(">>> Freezing %s@%s\n", pkg.ImportPath, pkg.Version) + + localPkg, err = env.GetPackage(pkg.ImportPath) + if err != nil { + return + } + if localPkg == nil { + err = pkg.Install() + if err != nil { + return + } + continue + } + + err = localPkg.Update(pkg) + if err != nil { + return + } + } + + env.pkgsUnused = nil + + err = env.GetUnused(env.dirSrc) + if err != nil { + err = fmt.Errorf("Freeze: %s", err.Error()) + return + } + + if len(env.pkgsUnused) == 0 { + fmt.Println(">>> No unused packages found.") + return + } + + fmt.Printf("\n>>> The following packages will be cleaned,\n\n") + for _, pkg := range env.pkgsUnused { + fmt.Printf(" * %s\n", pkg.ImportPath) + } + + fmt.Println() + + ok := confirm(os.Stdin, msgContinue, false) + if !ok { + return + } + + env.cleanUnused() + + fmt.Println(">>> Freeze completed.") + + return +} + +// +// GetPackage will return installed package from system. +// +func (env *Env) GetPackage(importPath string) (pkg *Package, err error) { + fullPath := filepath.Join(env.dirSrc, importPath) + dirGit := filepath.Join(fullPath, gitDir) + + _, err = os.Stat(fullPath) + if err != nil { + err = nil + return + } + + _, err = os.Stat(dirGit) + if err != nil { + if IsDirEmpty(fullPath) { + err = nil + } else { + err = fmt.Errorf(errDirNotEmpty, fullPath) + } + return + } + + pkg = NewPackage(importPath, importPath, VCSModeGit) + + err = pkg.Scan() + + return +} + // // GetPackageFromDB will return installed package registered on database. // If no package found, it will return nil. @@ -92,6 +196,62 @@ func (env *Env) GetPackageFromDB(importPath, remoteURL string) *Package { } // +// GetUnused will get all non-registered packages from GOPATH "src". +// +func (env *Env) GetUnused(srcPath string) (err error) { + fis, err := ioutil.ReadDir(srcPath) + if err != nil { + err = fmt.Errorf("CleanPackages: %s", err) + return + } + + var nextScan []string + + for _, fi := range fis { + // (0) + if !fi.IsDir() { + continue + } + + dirName := fi.Name() + fullPath := filepath.Join(srcPath, dirName) + dirGit := filepath.Join(fullPath, gitDir) + + // (1) + if IsIgnoredDir(dirName) { + continue + } + + // (2) + _, err = os.Stat(dirGit) + if err != nil { + nextScan = append(nextScan, fullPath) + err = nil + continue + } + + importPath := strings.TrimPrefix(fullPath, env.dirSrc+"/") + + pkg := env.GetPackageFromDB(importPath, "") + if pkg != nil { + continue + } + + pkg = NewPackage(importPath, importPath, VCSModeGit) + env.pkgsUnused = append(env.pkgsUnused, pkg) + } + + for x := 0; x < len(nextScan); x++ { + err = env.GetUnused(nextScan[x]) + if err != nil { + return + } + } + + return +} + +// // Scan will gather all package information in user system to start `beku`-ing. // func (env *Env) Scan() (err error) { @@ -154,12 +314,12 @@ func (env *Env) scanStdPackages(srcPath string) error { // (1) skip ignored directory // (2) skip directory without `.git` // -func (env *Env) scanPackages(rootPath string) (err error) { +func (env *Env) scanPackages(srcPath string) (err error) { if Debug >= DebugL2 { - fmt.Println(">>> Scanning", rootPath) + fmt.Println(">>> Scanning", srcPath) } - fis, err := ioutil.ReadDir(rootPath) + fis, err := ioutil.ReadDir(srcPath) if err != nil { err = fmt.Errorf("scanPackages: %s", err) return @@ -174,7 +334,7 @@ func (env *Env) scanPackages(rootPath string) (err error) { } dirName := fi.Name() - fullPath := filepath.Join(rootPath, dirName) + fullPath := filepath.Join(srcPath, dirName) dirGit := filepath.Join(fullPath, gitDir) // (1) |
