aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md6
-rw-r--r--beku.go1
-rw-r--r--cmd/beku/command.go12
-rw-r--r--cmd/beku/main.go18
-rw-r--r--cmd/beku/operation.go1
-rw-r--r--env.go86
-rw-r--r--package.go69
7 files changed, 189 insertions, 4 deletions
diff --git a/README.md b/README.md
index 8bf039d..0c2d81e 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,12 @@ package database into "$GOPATH/var/beku/gopath.deps".
Query the package database.
+## Remove Operation
+
+ -R, --remove [pkg]
+
+Remove package from GOPATH.
+
## Sync Operation
diff --git a/beku.go b/beku.go
index f63e393..9b838cf 100644
--- a/beku.go
+++ b/beku.go
@@ -28,6 +28,7 @@ const (
msgUpdateProceed = "Proceed with update?"
msgUpdateView = "View commit logs?"
+ msgContinue = "Continue?"
prefixTag = 'v'
diff --git a/cmd/beku/command.go b/cmd/beku/command.go
index 160b7dc..8558955 100644
--- a/cmd/beku/command.go
+++ b/cmd/beku/command.go
@@ -14,6 +14,7 @@ const (
flagHelpUsage = "Show the short usage."
flagQueryUsage = "Query the package database."
+ flagRemoveUsage = "Remove package from GOPATH."
flagSyncUsage = "Synchronize `package`."
flagSyncIntoUsage = "Package download `directory`."
)
@@ -24,6 +25,7 @@ type command struct {
help bool
query bool
queryPkg []string
+ rmPkg string
syncPkg string
syncInto string
}
@@ -35,6 +37,8 @@ operations:
` + flagHelpUsage + `
beku {-Q|--query} [pkg ...]
` + flagQueryUsage + `
+ beku {-R|--remove} [pkg ...]
+ ` + flagRemoveUsage + `
beku {-S|--sync} <pkg@version> [--into <directory>]
` + flagSyncUsage + `
`
@@ -53,9 +57,11 @@ func (cmd *command) setFlags() {
flag.BoolVar(&cmd.query, "Q", false, flagQueryUsage)
flag.BoolVar(&cmd.query, "query", false, flagQueryUsage)
+ flag.StringVar(&cmd.rmPkg, "R", emptyString, flagRemoveUsage)
+ flag.StringVar(&cmd.rmPkg, "remove", emptyString, flagRemoveUsage)
+
flag.StringVar(&cmd.syncPkg, "S", emptyString, flagSyncUsage)
flag.StringVar(&cmd.syncPkg, "sync", emptyString, flagSyncUsage)
-
flag.StringVar(&cmd.syncInto, "into", emptyString, flagSyncIntoUsage)
flag.Parse()
@@ -88,6 +94,10 @@ func (cmd *command) checkFlags() {
}
}
+ if len(cmd.rmPkg) > 0 {
+ cmd.op |= opRemove
+ }
+
// Invalid command parameters
if cmd.op == opNone || cmd.op == opSyncInto {
cmd.usage()
diff --git a/cmd/beku/main.go b/cmd/beku/main.go
index bf6666c..d3c040b 100644
--- a/cmd/beku/main.go
+++ b/cmd/beku/main.go
@@ -20,6 +20,12 @@
//
// Query the package database.
//
+// ## Remove Operation
+//
+// -R, --remove [pkg]
+//
+// Remove package from GOPATH.
+//
//
// ## Sync Operation
//
@@ -80,7 +86,9 @@
package main
import (
+ "fmt"
"log"
+ "os"
)
var (
@@ -96,15 +104,23 @@ func main() {
switch cmd.op {
case opQuery:
cmd.env.Query(cmd.queryPkg)
+ case opRemove:
+ err = cmd.env.Remove(cmd.rmPkg, false)
case opSync:
err = cmd.env.Sync(cmd.syncPkg, "")
case opSync | opSyncInto:
err = cmd.env.Sync(cmd.syncPkg, cmd.syncInto)
+ default:
+ fmt.Fprintln(os.Stderr, "Invalid operations or options")
+ os.Exit(1)
}
if err != nil {
log.Fatal(err)
}
- cmd.env.Save("")
+ err = cmd.env.Save("")
+ if err != nil {
+ log.Fatal(err)
+ }
}
diff --git a/cmd/beku/operation.go b/cmd/beku/operation.go
index 213a8ec..b10a446 100644
--- a/cmd/beku/operation.go
+++ b/cmd/beku/operation.go
@@ -6,6 +6,7 @@ const opNone operation = 0
const (
opQuery operation = 1 << iota
+ opRemove
opSync
opSyncInto
)
diff --git a/env.go b/env.go
index f1fa38e..d6ea134 100644
--- a/env.go
+++ b/env.go
@@ -37,6 +37,7 @@ type Env struct {
pkgsStd []string
db *ini.Ini
dbFile string
+ dirty bool
}
// NewEnvironment will gather all information in user system.
@@ -314,9 +315,92 @@ func (env *Env) Query(pkgs []string) {
}
//
-// Save the dependencies to `file`.
+// Remove package from GOPATH. If recursive is true, it will also remove their
+// dependencies, as long as they are not required by other package.
+//
+func (env *Env) Remove(rmPkg string, recursive bool) (err error) {
+ pkg := env.GetPackage(rmPkg, "")
+ if pkg == nil {
+ fmt.Println("Package", rmPkg, "not installed")
+ return
+ }
+
+ if len(pkg.RequiredBy) > 0 {
+ fmt.Fprintln(os.Stderr, `Can't remove package.
+This package is required by,
+`,
+ pkg.RequiredBy)
+ return
+ }
+
+ fmt.Println("The following package will be removed,\n", pkg)
+
+ ok := confirm(os.Stdin, msgContinue, false)
+ if !ok {
+ return
+ }
+
+ if !recursive {
+ err = pkg.Remove()
+ if err != nil {
+ err = fmt.Errorf("Remove: %s", err)
+ return
+ }
+
+ env.removePackage(pkg)
+ }
+
+ pkgImportPath := filepath.Join(env.pkgDir, pkg.ImportPath)
+
+ if Debug >= DebugL1 {
+ fmt.Println(">>> Remove $GOPATH/pkg:", pkgImportPath)
+ }
+
+ err = os.RemoveAll(pkgImportPath)
+ if err != nil {
+ err = fmt.Errorf("Remove: %s", err)
+ }
+
+ return
+}
+
+//
+// removePackage from list of packages, also remove in other packages
+// "RequiredBy" if exist.
+//
+func (env *Env) removePackage(pkg *Package) {
+ idx := -1
+ for x := 0; x < len(env.pkgs); x++ {
+ if env.pkgs[x].ImportPath == pkg.ImportPath {
+ idx = x
+ continue
+ }
+
+ ok := env.pkgs[x].RemoveRequiredBy(pkg.ImportPath)
+ if ok {
+ env.dirty = true
+ }
+ }
+
+ if idx >= 0 {
+ lenpkgs := len(env.pkgs)
+
+ copy(env.pkgs[idx:], env.pkgs[idx+1:])
+ env.pkgs[lenpkgs-1] = nil
+ env.pkgs = env.pkgs[:lenpkgs-1]
+
+ env.dirty = true
+ }
+}
+
+//
+// Save the dependencies to `file` only if it's dirty flag is true.
//
func (env *Env) Save(file string) (err error) {
+ if !env.dirty {
+ return
+ }
+
if len(file) == 0 {
if len(env.dbFile) == 0 {
file = env.defDBFile
diff --git a/package.go b/package.go
index e13ddf7..1537b85 100644
--- a/package.go
+++ b/package.go
@@ -82,6 +82,28 @@ func (pkg *Package) Fetch() (err error) {
}
//
+// GoClean will remove the package binaries and archives.
+//
+func (pkg *Package) GoClean() (err error) {
+ //nolint:gas
+ cmd := exec.Command("go", "clean", "-i", "-cache", "-testcache", "./...")
+ if Debug >= DebugL1 {
+ fmt.Println(">>>", cmd.Args)
+ }
+ cmd.Dir = pkg.FullPath
+ cmd.Stdout = defStdout
+ cmd.Stderr = defStderr
+
+ err = cmd.Run()
+ if err != nil {
+ err = fmt.Errorf("GoClean: %s", err)
+ return
+ }
+
+ return
+}
+
+//
// Install a package. Clone package to GOPATH/src, set to the latest tag if
// exist or to the latest commit, and scan dependencies.
//
@@ -124,6 +146,51 @@ func (pkg *Package) IsEqual(other *Package) bool {
}
//
+// Remove package installed binaries, archives, and source from GOPATH.
+//
+func (pkg *Package) Remove() (err error) {
+ err = pkg.GoClean()
+ if err != nil {
+ err = fmt.Errorf("Remove: %s", err)
+ return
+ }
+
+ if Debug >= DebugL1 {
+ fmt.Println(">>> Remove source:", pkg.FullPath)
+ }
+
+ err = os.RemoveAll(pkg.FullPath)
+ if err != nil {
+ err = fmt.Errorf("Remove: %s", err)
+ return
+ }
+
+ return
+}
+
+//
+// RemoveRequiredBy will remove package import path from current
+// package list of required-by.
+// If import-path found as required-by, it will return true, otherwise it will
+// return false.
+//
+func (pkg *Package) RemoveRequiredBy(importPath string) (ok bool) {
+ var requiredBy []string
+
+ for x := 0; x < len(pkg.RequiredBy); x++ {
+ if pkg.RequiredBy[x] == importPath {
+ ok = true
+ continue
+ }
+ requiredBy = append(requiredBy, pkg.RequiredBy[x])
+ }
+ if ok {
+ pkg.RequiredBy = requiredBy
+ }
+ return
+}
+
+//
// Scan will set the package version, `isTag` status, and remote URL using
// metadata in package repository.
//
@@ -172,7 +239,7 @@ func (pkg *Package) ScanDeps(env *Env) (err error) {
func (pkg *Package) GetRecursiveImports() (
imports []string, err error,
) {
- //nolint: gas
+ //nolint:gas
cmd := exec.Command("go", "list", "-e", "-f", `{{ join .Deps "\n"}}`, "./...")
fmt.Println(">>>", cmd.Args)