Skip to content

Commit

Permalink
Merge e6b9b39 into 60da38f
Browse files Browse the repository at this point in the history
  • Loading branch information
saheljalal committed Jan 29, 2022
2 parents 60da38f + e6b9b39 commit e1cc74e
Show file tree
Hide file tree
Showing 15 changed files with 226 additions and 126 deletions.
55 changes: 45 additions & 10 deletions cmd/completion.go
@@ -1,26 +1,61 @@
package cmd

import (
"fmt"
"os"

"github.com/pokanop/nostromo/task"
"github.com/spf13/cobra"
"os"
)

// completionCmd represents the completion command
var completionCmd = &cobra.Command{
Use: "completion",
Short: "Generates shell completion scripts",
Long: `To load completion now, run
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script",
Long: fmt.Sprintf(`To load completions:
Bash:
$ source <(%[1]s completion bash)
# To load completions for each session, execute once:
# Linux:
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
# macOS:
$ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
Zsh:
# If shell completion is not already enabled in your environment,
# you will need to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
# You will need to start a new shell for this setup to take effect.
fish:
$ %[1]s completion fish | source
# To load completions for each session, execute once:
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
eval "$(nostromo completion)"
PowerShell:
To configure your shell to load completions for each session add to your init files.
Note that "nostromo init" will add this automatically.
PS> %[1]s completion powershell | Out-String | Invoke-Expression
# In ~/.bashrc, ~/.bash_profile or ~/.zshrc
eval "$(nostromo completion)"`,
# To load completions for every new session, run:
PS> %[1]s completion powershell > %[1]s.ps1
# and source this file from your PowerShell profile.
`, rootCmd.Name()),
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.ExactValidArgs(1),
Run: func(cmd *cobra.Command, args []string) {
os.Exit(task.GenerateCompletions(cmd))
os.Exit(task.GenerateCompletions(args[0], cmd.Root(), false))
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/init.go
Expand Up @@ -17,7 +17,7 @@ By default the config file is located at ~/.nostromo/ships/manifest.yaml.
Customize this with the $NOSTROMO_HOME environment variable`,
Run: func(cmd *cobra.Command, args []string) {
os.Exit(task.InitConfig())
os.Exit(task.InitConfig(cmd.Root()))
},
}

Expand Down
13 changes: 8 additions & 5 deletions cmd/root.go
Expand Up @@ -15,13 +15,13 @@ var ver *version.Info
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "nostromo",
Short: "Nostromo is a tool to manage aliases",
Long: `Nostromo is a CLI to manage aliases through simple commands to add and remove
Short: "nostromo is a tool to manage aliases",
Long: `nostromo is a CLI to manage aliases through simple commands to add and remove
scoped aliases and substitutions.
Managing aliases can be tedious and difficult to set up. Nostromo makes this process easy
Managing aliases can be tedious and difficult to set up. nostromo makes this process easy
and reliable. The tool adds shortcuts to your .bashrc that call into the nostromo binary.
Nostromo reads and manages all aliases within its own config file.
nostromo reads and manages all aliases within its own config file.
This is used to find and execute the actual command intended as well as any
substitutions to simplify calls.`,
SilenceErrors: true,
Expand All @@ -47,6 +47,9 @@ func SetVersion(v, c, d string) {

func init() {
cobra.OnInitialize(initConfig)

// Disable default completion command
rootCmd.CompletionOptions.DisableDefaultCmd = true
}

// initConfig reads in config file and ENV variables if set.
Expand All @@ -65,5 +68,5 @@ func printUsage(cmd *cobra.Command) {
}

func printVersion() {
log.Regularf("Nostromo: %s\n", ver.Formatted())
log.Regularf("nostromo: %s\n", ver.Formatted())
}
22 changes: 22 additions & 0 deletions cmd/run.go
@@ -0,0 +1,22 @@
package cmd

import (
"github.com/pokanop/nostromo/task"
"github.com/spf13/cobra"
)

// runCmd represents the run command
var runCmd = &cobra.Command{
Use: "run",
Short: "Placeholder node for nostromo commands",
Long: `Placeholder node for nostromo commands`,
Hidden: true,
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
rootCmd.AddCommand(runCmd)

// Add all nostromo commands to the run command
runCmd.AddCommand(task.FetchCommands()...)
}
1 change: 0 additions & 1 deletion cmd/sync.go
Expand Up @@ -22,7 +22,6 @@ manifests from respective data sources.
Providing a [source] file will sync only that file. Omitting it
directs nostromo to sync all manifests.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
os.Exit(task.Sync(force, args))
},
Expand Down
30 changes: 25 additions & 5 deletions config/config.go
Expand Up @@ -19,11 +19,12 @@ import (

// Path for standard nostromo config
const (
DefaultBaseDir = "~/.nostromo"
DefaultConfigFile = "%s.yaml"
DefaultManifestsDir = "ships"
DefaultBackupsDir = "cargo"
DefaultDownloadsDir = "downloads"
DefaultBaseDir = "~/.nostromo"
DefaultConfigFile = "%s.yaml"
DefaultManifestsDir = "ships"
DefaultBackupsDir = "cargo"
DefaultDownloadsDir = "downloads"
DefaultCompletionsDir = "completions"
)

// URL scheme constants
Expand Down Expand Up @@ -123,6 +124,16 @@ func BaseDir() string {
return DefaultBaseDir
}

// WriteCompletion writes a file to the completions folder
func WriteCompletion(sh, s string) error {
if len(sh) == 0 || len(s) == 0 {
return fmt.Errorf("attempt to write 0 length file")
}

path := filepath.Join(completionsPath(), fmt.Sprintf("nostromo.%s", sh))
return os.WriteFile(path, []byte(s), 0644)
}

// Spaceport associated with this config
func (c *Config) Spaceport() *model.Spaceport {
return c.spaceport
Expand Down Expand Up @@ -257,6 +268,11 @@ func backupsPath() string {
return filepath.Join(pathutil.Abs(BaseDir()), DefaultBackupsDir)
}

// completionsPath joins the base directory and the manifest directory
func completionsPath() string {
return filepath.Join(pathutil.Abs(BaseDir()), DefaultCompletionsDir)
}

func coreManifestFile() string {
return fmt.Sprintf(DefaultConfigFile, model.CoreManifestName)
}
Expand Down Expand Up @@ -471,6 +487,10 @@ func sanitizeFiles() error {
return err
}

if err := pathutil.EnsurePath(completionsPath()); err != nil {
return err
}

// The core manifest was previously in the root folder of NOSTROMO_HOME.
// Check there first and move to new location if needed.
oldPath := filepath.Join(pathutil.Abs(BaseDir()), model.CoreManifestName+".yaml")
Expand Down
7 changes: 7 additions & 0 deletions config/sync.go
Expand Up @@ -24,6 +24,13 @@ func (c *Config) Sync(force bool, sources []string) error {

defer syncCleanup()

// Fallback to all existing manifests if no sources provided
if len(sources) == 0 {
for _, m := range c.spaceport.Manifests() {
sources = append(sources, m.Source)
}
}

for _, source := range sources {
err := syncDownload(source)
if err != nil {
Expand Down
6 changes: 4 additions & 2 deletions model/command.go
Expand Up @@ -77,7 +77,9 @@ func (c *Command) CobraCommand() *cobra.Command {
Use: c.Alias,
Short: c.Description,
Long: c.Description,
Hidden: true,
ValidArgs: c.commandList(),
Run: func(cmd *cobra.Command, args []string) {},
}
for _, childCmd := range c.Commands {
cmd.AddCommand(childCmd.CobraCommand())
Expand Down Expand Up @@ -337,7 +339,7 @@ func (c *Command) build(keyPath, command, description string, code *Code, aliasO
func (c *Command) commandList() []string {
var cmds []string
for _, cmd := range c.Commands {
cmds = append(cmds, cmd.Alias)
cmds = append(cmds, fmt.Sprintf("%s\t%s", cmd.Alias, cmd.Description))
}
sort.Strings(cmds)
return cmds
Expand All @@ -352,7 +354,7 @@ func (c *Command) checkDisabled() (bool, *Command) {
if cmd == nil {
break
}
if cmd.Disabled == true {
if cmd.Disabled {
return true, cmd
}
cmd = cmd.parent
Expand Down
10 changes: 10 additions & 0 deletions model/spaceport.go
Expand Up @@ -31,6 +31,16 @@ func (s *Spaceport) Manifests() []*Manifest {
return manifests
}

func (s *Spaceport) Commands() []*Command {
cmds := []*Command{}
for _, m := range s.Manifests() {
for _, c := range m.Commands {
cmds = append(cmds, c)
}
}
return cmds
}

func (s *Spaceport) Import(manifests []*Manifest) {
s.Sequence = []string{}
for _, m := range manifests {
Expand Down
44 changes: 22 additions & 22 deletions shell/completion.go
Expand Up @@ -2,7 +2,7 @@ package shell

import (
"bytes"
"io/ioutil"
"fmt"
"strings"

"github.com/pokanop/nostromo/model"
Expand All @@ -15,39 +15,39 @@ type CobraCompleter interface {
}

// Completion generates shell completion scripts
func Completion(cmd *cobra.Command) (string, error) {
func Completion(sh string, cmd *cobra.Command) (string, error) {
var buf bytes.Buffer
var err error
if Which() == Zsh {
switch sh {
case "bash":
err = cmd.GenBashCompletionV2(&buf, true)
case "zsh":
zshHead := fmt.Sprintf("#compdef %[1]s\ncompdef _%[1]s %[1]s\n", cmd.Name())
buf.Write([]byte(zshHead))
err = cmd.GenZshCompletion(&buf)
} else {
err = cmd.GenBashCompletion(&buf)
case "fish":
err = cmd.GenFishCompletion(&buf, true)
case "powershell":
err = cmd.GenPowerShellCompletionWithDesc(&buf)
}
if err != nil {
return "", err
}

b, err := ioutil.ReadAll(&buf)
if err != nil {
return "", err
}
s := string(b)

// This is required due to a bug in cobra and zsh support:
// https://github.com/spf13/cobra/pull/887
if Which() == Zsh {
s = strings.Replace(s, "#", "", 1)
s := buf.String()
if cmd.Name() != "nostromo" {
s = strings.ReplaceAll(s, "${words[1]} __complete ${words[2,-1]}", "nostromo __complete run ${words[1]} ${words[2,-1]}")
}

return s, nil
}

// SpaceportCompletion scripts for all manifests
func SpaceportCompletion(s *model.Spaceport) ([]string, error) {
func SpaceportCompletion(sh string, s *model.Spaceport) ([]string, error) {
var completions []string
completions = append(completions, shellWrapperFunc())
completions = append(completions, shellWrapperFunc(sh))
for _, m := range s.Manifests() {
mc, err := ManifestCompletion(m)
mc, err := ManifestCompletion(sh, m)
if err != nil {
return nil, err
}
Expand All @@ -57,7 +57,7 @@ func SpaceportCompletion(s *model.Spaceport) ([]string, error) {
}

// ManifestCompletion scripts for a manifest
func ManifestCompletion(m *model.Manifest) ([]string, error) {
func ManifestCompletion(sh string, m *model.Manifest) ([]string, error) {
var completions []string
completions = append(completions, shellAliasFuncs(m))
for _, cmd := range m.Commands {
Expand All @@ -66,7 +66,7 @@ func ManifestCompletion(m *model.Manifest) ([]string, error) {
if cmd.AliasOnly || len(cmd.Commands) == 0 {
continue
}
s, err := CommandCompletion(cmd)
s, err := CommandCompletion(sh, cmd)
if err != nil {
return nil, err
}
Expand All @@ -76,6 +76,6 @@ func ManifestCompletion(m *model.Manifest) ([]string, error) {
}

// CommandCompletion script for a command
func CommandCompletion(cmd *model.Command) (string, error) {
return Completion(cmd.CobraCommand())
func CommandCompletion(sh string, cmd *model.Command) (string, error) {
return Completion(sh, cmd.CobraCommand())
}

0 comments on commit e1cc74e

Please sign in to comment.