clicommon

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2022 License: MIT Imports: 19 Imported by: 0

README

Go CLI Common

This repo contains shared code across Madwire's development CLI tooling, including in the secrets-cli

Examples

Interactive CLI helpers
package main

import (
    fmt
    os

    clicommon "github.com/madwire-media/go-cli-common"
)

func main() {
    if !clicommon.CliQuestionYesNo("Are you at least 13 years old?") {
        fmt.Println("You need to be 13 years or older to sign up")
        os.Exit(1)
    }

    username := clicommon.CliQuestion("Username")
    password := clicommon.CliQuestionHidden("Password")

    fmt.Println("Welcome!")
}
$ ./example
Are you at least 13 years old? (y/n): n
You need to be 13 years or older to sign up
$ ./example
Are you at least 13 years old? (y/n): y
Username: foo
Password (hidden):
Welcome!
Tiny privilege escalation framework
package main

import (
    fmt

    clicommon "github.com/madwire-media/go-cli-common"
)

func main() {
    // Handle a superuser action
    clicommon.TryHandleSudo()

    // Re-execute this binary with superuser permissions, and run the
    // DummyAction to log "Hello Github!"
    clicommon.CallSudo(DummyAction{
        log: "Hello GitHub!"
    })
}

func init() {
    // Register our DummyAction before main() gets run
    clicommon.RegisterAction(DummyAction{})
}

type DummyAction struct {
    log: string,
}

func (a DummyAction) Name() { return "dummyAction" }
func (a DummyAction) Params() { return []string{a.log} }

func (a DummyAction) Handle(params []string) error {
    fmt.Printf("Logging as superuser: %s", params[0])

    return nil
}
$ ./example
Logging as superuser: Hello Github!
User config file helpers
package main

import (
    fmt
    os

    clicommon "github.com/madwire-media/go-cli-common"
)

type Config struct {
    counter: int
}

func main() {
    // Use a user config folder named "my-app-name"
    configDir := clicommon.NewUserConfigDir("my-app-name")

    // Load 'myconfig.json' inside that folder and parse into the Config struct
    var config Config
    err := configDir.LoadConfig("myconfig", &config)
    if err != nil {
        fmt.Println("Error loading 'myconfig' file: %s", err)
        os.Exit(1)
    }

    config.counter++

    // Save the updated config back to 'myconfig.json' inside that folder
    err = configDir.SaveConfig("myconfig", &config)
    if err != nil {
        fmt.Println("Error saving 'myconfig' file: %s", err)
        os.Exit(1)
    }

    fmt.Printf("Incremented counter to %d", config.counter)
}
$ ./example
Incremented counter to 1
$ ./example
Incremented counter to 2
$ rm -r ~/.config/my-app-name
$ ./example
Incremented counter to 1
CLI self-update system
package main

import (
    fmt
    os

    clicommon "github.com/madwire-media/go-cli-common"
)

// This can be overridden by a linker, e.g. in a goreleaser build
var BuildVersion = "0.0.1"
const GithubRepo = "my-org/my-app-name"

func main() {
    maybeAutoUpdate()

    fmt.Println("Hello GitHub!")
    fmt.Println("Version:", BuildVersion)
}

func maybeAutoUpdate() {
    // Use the 'my-app-name' user config folder
    configDir := clicommon.NewUserConfigDir("my-app-name")

    // Set up a new auto-updater given our current build version, the repo to
    // update from, and that it's not private
    autoUpdater, err := clicommon.NewAutoUpdater(configDir, BuildVersion, GitHubRepo, false, nil)
    if err != nil {
        fmt.Println(err.Error())
    }

    // If there's an update available, download it, replace the current
    // executable, and re-execute it in place with the same arguments
    err = autoUpdater.TryAutoUpdateSelf()
    if err != nil {
        fmt.Println(err.Error())
    }
}
$ ./example
Automatic updating has not been configured, would you like to enable it? (only checks for updates every 24 hours)
Auto Update? (Y/n):
Checking for updates...
Hello Github!
Version: 0.0.1
$ ./example
Hello Github!
Version: 0.0.1

Then if you publish v0.0.2 in GitHub Releases and wait 24 hours:

$ ./example
Checking for updates...
Updating to v0.0.2
Complete, restarting command...
Hello Github!
Version: 0.0.2
$ ./example
Hello Github!
Version: 0.0.2

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CallSudo

func CallSudo(action SudoAction) error

CallSudo asks the user for superuser permissions, and then executes the currently-running program with those permissions for a particular action. TryHandleSudo should be called at the beginning of the program's main() function to catch these sudo calls.

func CliChoice

func CliChoice(question string, choices []string) (int, error)

CliChoice provides an interactive UI to select between one or more choices

func CliQuestion

func CliQuestion(question string) string

CliQuestion prints a prompt to stdout and reads a line of input from stdin, returning that read string

func CliQuestionHidden

func CliQuestionHidden(question string) (string, error)

CliQuestionHidden prints a prompt to stdout and reads a hidden line of input from stdin. This is meant to be used for passwords where you don't want them printed to the screen

func CliQuestionYesNo

func CliQuestionYesNo(question string) bool

CliQuestionYesNo prints a question prompt and allows either yes or no answers to be entered, returning "y" or "yes" as true and "n" or "no" as false

func CliQuestionYesNoDefault

func CliQuestionYesNoDefault(question string, defaultValue bool) bool

CliQuestionYesNoDefault prints a question prompt and allows either yes or no answers to be entered, or no answer at all. If no answer is entered, the defaultValue is returned, otherwise "y" or "yes" returns true and "n" or "no" returns false

func GetAutoUpdate

func GetAutoUpdate(configDir *UserConfigDir) (bool, error)

GetAutoUpdate gets if automatic updates are enabled

func LoadExternalConfig

func LoadExternalConfig(filename string, data interface{}) error

LoadExternalConfig reads an external config file, outside of the default user config directory

func RegisterAction

func RegisterAction(action SudoAction)

func SaveExternalConfig

func SaveExternalConfig(filename string, data interface{}) error

SaveExternalConfig saves a file outside of the default user config directory

func SetAutoUpdate

func SetAutoUpdate(configDir *UserConfigDir, shouldAutoUpdate bool) (bool, error)

SetAutoUpdate configures if automatic updates are enabled

func TryHandleSudo

func TryHandleSudo()

TryHandleSudo catches superuser self-executions to do certain actions that require superuser permissions

Types

type AutoUpdater

type AutoUpdater struct {
	// contains filtered or unexported fields
}

func NewAutoUpdater

func NewAutoUpdater(
	configDir *UserConfigDir,
	buildVersion, githubRepo string,
	isPrivate bool,
	configSubcommand *string,
) (*AutoUpdater, error)

func (*AutoUpdater) TryAutoUpdateSelf

func (updater *AutoUpdater) TryAutoUpdateSelf() error

TryAutoUpdateSelf checks for an update and replaces the existing executable with the new version if there is one. Update checks are debounced to every 24 hours, and can be disabled with a config option.

func (*AutoUpdater) TryManualUpdate

func (updater *AutoUpdater) TryManualUpdate() error

TryManualUpdate checks for an update and replaces the existing executable with the new version if there is one. This will always run, without any debouncing or config options to disable it.

type ReplaceExecutableSudoAction

type ReplaceExecutableSudoAction struct {
	NewExe string
}

func (ReplaceExecutableSudoAction) Handle

func (a ReplaceExecutableSudoAction) Handle(params []string) error

func (ReplaceExecutableSudoAction) Name

func (ReplaceExecutableSudoAction) Params

func (a ReplaceExecutableSudoAction) Params() []string

type SudoAction

type SudoAction interface {
	Name() string
	Params() []string
	Handle(params []string) error
}

type UserConfigDir

type UserConfigDir struct {
	// contains filtered or unexported fields
}

func NewUserConfigDir

func NewUserConfigDir(name string) *UserConfigDir

func (*UserConfigDir) GetConfigDir

func (userConfigDir *UserConfigDir) GetConfigDir() (string, error)

GetConfigDir gets the os-dependent user configuration directory

func (*UserConfigDir) LoadConfig

func (userConfigDir *UserConfigDir) LoadConfig(config string, data interface{}) error

LoadConfig loads a user config file of the given name

func (*UserConfigDir) SaveConfig

func (userConfigDir *UserConfigDir) SaveConfig(config string, data interface{}) error

SaveConfig saves a user config file of the given name

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL