aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rw-r--r--cmd/beku/command.go17
-rw-r--r--cmd/beku/command_test.go3
-rw-r--r--cmd/beku/main.go12
-rw-r--r--cmd/beku/operation.go1
-rw-r--r--env.go168
6 files changed, 204 insertions, 7 deletions
diff --git a/README.md b/README.md
index 5d2234b..94ccb97 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/env.go b/env.go
index a2ce351..cf23771 100644
--- a/env.go
+++ b/env.go
@@ -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)