Asking if imports not in code should be imported
diff --git a/action/create.go b/action/create.go index 800ec48..bad74e1 100644 --- a/action/create.go +++ b/action/create.go
@@ -31,13 +31,13 @@ // If skipImport is set to true, this will not attempt to import from an existing // GPM, Godep, or GB project if one should exist. However, it will still attempt // to read the local source to determine required packages. -func Create(base string, skipImport bool) { +func Create(base string, skipImport, noInteract bool) { glidefile := gpath.GlideFile // Guard against overwrites. guardYAML(glidefile) // Guess deps - conf := guessDeps(base, skipImport) + conf := guessDeps(base, skipImport, noInteract) // Write YAML msg.Info("Writing glide.yaml file") if err := conf.WriteFile(glidefile); err != nil { @@ -64,7 +64,7 @@ // // FIXME: This function is likely a one-off that has a more standard alternative. // It's also long and could use a refactor. -func guessDeps(base string, skipImport bool) *cfg.Config { +func guessDeps(base string, skipImport, noInteract bool) *cfg.Config { buildContext, err := util.GetBuildContext() if err != nil { msg.Die("Failed to build an import context: %s", err) @@ -80,21 +80,17 @@ // Import by looking at other package managers and looking over the // entire directory structure. + var deps cfg.Dependencies // Attempt to import from other package managers. if !skipImport { - guessImportDeps(base, config) + deps = guessImportDeps(base) + if len(deps) == 0 { + msg.Info("No dependencies found to import") + } } - importLen := len(config.Imports) - if importLen > 0 { - msg.Info("Scanning code to look for additional dependencies") - } else if !skipImport { - msg.Info("No dependencies found to import") - msg.Info("Scanning code to look for dependencies") - } else { - msg.Info("Scanning code to look for dependencies") - } + msg.Info("Scanning code to look for dependencies") // Resolve dependencies by looking at the tree. r, err := dependency.NewResolver(base) @@ -124,37 +120,72 @@ if !config.HasDependency(root) { count++ - msg.Info("--> Found reference to %s\n", n) - d := &cfg.Dependency{ - Name: root, + d := deps.Get(root) + if d == nil { + d = &cfg.Dependency{ + Name: root, + } + msg.Info("--> Found reference to %s", n) + } else { + msg.Info("--> Found reference to %s. Importing version %s", n, d.Reference) } - if len(subpkg) > 0 { - d.Subpackages = []string{subpkg} + + if subpkg != "" { + if !d.HasSubpackage(subpkg) { + d.Subpackages = append(d.Subpackages, subpkg) + } + msg.Verbose("--> Noting sub-package %s to %s", subpkg, root) } + config.Imports = append(config.Imports, d) } else { if len(subpkg) > 0 { subpkg = strings.TrimPrefix(subpkg, "/") d := config.Imports.Get(root) if !d.HasSubpackage(subpkg) { - count++ - msg.Info("--> Adding sub-package %s to %s\n", subpkg, root) d.Subpackages = append(d.Subpackages, subpkg) } + msg.Verbose("--> Noting sub-package %s to %s", subpkg, root) + } + } + } + + if !skipImport && len(deps) > count { + var res string + if noInteract { + res = "y" + } else { + msg.Info("%d unused imported dependencies found. These are likely transitive dependencies ", len(deps)-count) + msg.Info("(dependencies of your dependencies). Would you like to track them in your") + msg.Info("glide.yaml file? Note, Glide will automatically scan your codebase to detect") + msg.Info("the complete dependency tree and import the complete tree. If your dependencies") + msg.Info("do not track dependency version information some version information may be lost.") + msg.Info("Yes (y) or No (n)?") + res, err = msg.PromptUntil([]string{"y", "yes", "n", "no"}) + if err != nil { + msg.Die("Error processing response: %s", err) + } + } + if res == "y" || res == "yes" { + msg.Info("Including additional imports in the glide.yaml file") + for _, dep := range deps { + found := config.Imports.Get(dep.Name) + if found == nil { + config.Imports = append(config.Imports, dep) + if dep.Reference != "" { + msg.Info("--> Adding %s at version %s", dep.Name, dep.Reference) + } else { + msg.Info("--> Adding %s", dep.Name) + } + } } } } - if count == 0 && importLen > 0 { - msg.Info("--> Scanning found no additional dependencies to import") - } else if count == 0 { - msg.Info("--> Scanning found no dependencies to import") - } - return config } -func guessImportDeps(base string, config *cfg.Config) { +func guessImportDeps(base string) cfg.Dependencies { msg.Info("Attempting to import from other package managers (use --skip-import to skip)") deps := []*cfg.Dependency{} absBase, err := filepath.Abs(base) @@ -178,7 +209,7 @@ } if len(deps) > 0 { - msg.Info("--> Attempting to detect versions from commit ids") + msg.Info("--> Attempting to detect versions from imported commit ids") } var wg sync.WaitGroup @@ -194,19 +225,19 @@ } ver := createGuessVersion(remote, dep.Reference) if ver != dep.Reference { - msg.Info("--> Found imported reference to %s at version %s", dep.Name, ver) + msg.Verbose("--> Found imported reference to %s at version %s", dep.Name, ver) dep.Reference = ver - } else { - msg.Info("--> Found imported reference to %s", dep.Name) } + msg.Debug("--> Found imported reference to %s at revision %s", dep.Name, dep.Reference) + wg.Done() }(i) - - config.Imports = append(config.Imports, i) } wg.Wait() + + return deps } func guessImportGodep(dir string) ([]*cfg.Dependency, bool) {
diff --git a/action/debug.go b/action/debug.go index 7b8eea6..6af9d26 100644 --- a/action/debug.go +++ b/action/debug.go
@@ -7,6 +7,15 @@ // Debug sets the debugging flags across components. func Debug(on bool) { msg.Default.IsDebugging = on + + if on == true { + msg.Default.IsVerbose = on + } +} + +// Verbose sets the verbose flags across components. +func Verbose(on bool) { + msg.Default.IsVerbose = on } // Quiet sets the quiet flags across components.
diff --git a/glide.go b/glide.go index 2ce9fcc..3f703b4 100644 --- a/glide.go +++ b/glide.go
@@ -92,8 +92,12 @@ Usage: "Quiet (no info or debug messages)", }, cli.BoolFlag{ + Name: "verbose", + Usage: "Print detailed informational messages", + }, + cli.BoolFlag{ Name: "debug", - Usage: "Print Debug messages (verbose)", + Usage: "Print debug verbose informational messages", }, cli.StringFlag{ Name: "home", @@ -146,9 +150,13 @@ Name: "skip-import", Usage: "When initializing skip importing from other package managers.", }, + cli.BoolFlag{ + Name: "non-interactive", + Usage: "Disable interactive prompts.", + }, }, Action: func(c *cli.Context) { - action.Create(".", c.Bool("skip-import")) + action.Create(".", c.Bool("skip-import"), c.Bool("non-interactive")) }, }, { @@ -664,6 +672,7 @@ // so it can be used by any Glide command. func startup(c *cli.Context) error { action.Debug(c.Bool("debug")) + action.Verbose(c.Bool("verbose")) action.NoColor(c.Bool("no-color")) action.Quiet(c.Bool("quiet")) action.Init(c.String("yaml"), c.String("home"))
diff --git a/msg/msg.go b/msg/msg.go index b2a7bfe..2f9c6c8 100644 --- a/msg/msg.go +++ b/msg/msg.go
@@ -1,6 +1,7 @@ package msg import ( + "bufio" "fmt" "io" "os" @@ -16,9 +17,12 @@ // Quiet, if true, suppresses chatty levels, like Info. Quiet bool - // IsDebugging, if true, shows verbose levels, like Debug. + // IsDebugging, if true, shows Debug. IsDebugging bool + // IsVerbose, if true, shows detailed informational messages. + IsVerbose bool + // NoColor, if true, will not use color in the output. NoColor bool @@ -28,6 +32,9 @@ // Stderr is the location where this prints logs. Stderr io.Writer + // Stdin is the location where input is read. + Stdin io.Reader + // PanicOnDie if true Die() will panic instead of exiting. PanicOnDie bool @@ -43,9 +50,11 @@ m := &Messenger{ Quiet: false, IsDebugging: false, + IsVerbose: false, NoColor: false, Stdout: os.Stdout, Stderr: os.Stderr, + Stdin: os.Stdin, PanicOnDie: false, ecode: 1, } @@ -76,7 +85,7 @@ return } prefix := "[DEBUG] " - Msg(prefix+msg, args...) + m.Msg(prefix+msg, args...) } // Debug logs debug information using the Default Messenger @@ -84,6 +93,19 @@ Default.Debug(msg, args...) } +// Verbose logs detailed information +func (m *Messenger) Verbose(msg string, args ...interface{}) { + if m.Quiet || !m.IsVerbose { + return + } + m.Info(msg, args...) +} + +// Verbose detailed information using the Default Messenger +func Verbose(msg string, args ...interface{}) { + Default.Verbose(msg, args...) +} + // Warn logs a warning func (m *Messenger) Warn(msg string, args ...interface{}) { prefix := m.Color(Yellow, "[WARN] ") @@ -238,3 +260,30 @@ func Color(code, msg string) string { return Default.Color(code, msg) } + +// PromptUntil provides a prompt until one of the passed in strings has been +// entered and return is hit. Note, the comparisons are case insensitive meaning +// Y == y. The returned value is the one from the passed in options (same case). +func (m *Messenger) PromptUntil(opts []string) (string, error) { + reader := bufio.NewReader(os.Stdin) + for { + text, err := reader.ReadString('\n') + if err != nil { + return "", err + } + + for _, c := range opts { + if strings.EqualFold(c, strings.TrimSpace(text)) { + return c, nil + } + } + } +} + +// PromptUntil provides a prompt until one of the passed in strings has been +// entered and return is hit. Note, the comparisons are case insensitive meaning +// Y == y. The returned value is the one from the passed in options (same case). +// Uses the default setup. +func PromptUntil(opts []string) (string, error) { + return Default.PromptUntil(opts) +}