Skip to content

Commit

Permalink
Merge pull request #15 from devzero-inc/debo/shells
Browse files Browse the repository at this point in the history
add support to instrument all shells at install time
  • Loading branch information
dray92 authored Oct 8, 2024
2 parents b5e6d29 + 2e30805 commit 3a5340f
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 149 deletions.
187 changes: 111 additions & 76 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"lda/util"
"net/http"
"os"
"strings"

"github.com/pkg/errors"
"github.com/spf13/cobra"
Expand All @@ -31,12 +32,7 @@ var (
Run: lda,
}

installCmd = &cobra.Command{
Use: "install",
Short: "Install daemon runner",
Long: `Install daemon runner for LDA Project.`,
RunE: install,
}
installCmd = newInstallCmd()

uninstallCmd = &cobra.Command{
Use: "uninstall",
Expand Down Expand Up @@ -81,6 +77,23 @@ var (
}
)

var installFlags struct {
shells []string
}

func newInstallCmd() *cobra.Command {
installCmd := &cobra.Command{
Use: "install",
Short: "Install daemon runner",
Long: `Install daemon runner for LDA Project.`,
RunE: install,
}

installCmd.Flags().StringSliceVarP(&installFlags.shells, "shell", "s", []string{}, fmt.Sprintf("Shells to instrument %+v; --shell=all for all shells", config.SupportedShells))

return installCmd
}

const (
// days are amount of days that old data will be retained
days = 5
Expand Down Expand Up @@ -121,7 +134,6 @@ func includeShowFlagsForInstall(cmd *cobra.Command) {
}

func setupConfig() {

// setting up the system configuration
config.SetupSysConfig()

Expand Down Expand Up @@ -203,12 +215,12 @@ func reload(_ *cobra.Command, _ []string) error {
user.ConfigureUserSystemInfo(user.Conf)

daemonConf := &daemon.Config{
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellLocation: user.Conf.ShellLocation,
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellTypeToLocation: user.Conf.ShellTypeToLocation,
}
dmn := daemon.NewDaemon(daemonConf, logging.Log)

Expand All @@ -226,12 +238,12 @@ func start(_ *cobra.Command, _ []string) error {
user.ConfigureUserSystemInfo(user.Conf)

daemonConf := &daemon.Config{
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellLocation: user.Conf.ShellLocation,
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellTypeToLocation: user.Conf.ShellTypeToLocation,
}
dmn := daemon.NewDaemon(daemonConf, logging.Log)

Expand All @@ -249,12 +261,12 @@ func stop(_ *cobra.Command, _ []string) error {
user.ConfigureUserSystemInfo(user.Conf)

daemonConf := &daemon.Config{
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellLocation: user.Conf.ShellLocation,
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellTypeToLocation: user.Conf.ShellTypeToLocation,
}
dmn := daemon.NewDaemon(daemonConf, logging.Log)

Expand All @@ -268,6 +280,26 @@ func stop(_ *cobra.Command, _ []string) error {
}

func install(cmd *cobra.Command, _ []string) error {
// validate the stuff
if len(installFlags.shells) > 0 {
for _, shellType := range installFlags.shells {
if strings.EqualFold(shellType, "all") {
installFlags.shells = config.SupportedShells
break
} else if config.GetShellType(shellType) == -1 {
fmt.Fprintf(config.SysConfig.ErrOut, "Unsupported shell: %s\nPlease choose one of: %+v\n", shellType, config.SupportedShells)
os.Exit(1)
}
}
}

// if shells are provided, lets deal with it
if len(installFlags.shells) > 0 {
user.Conf.ShellTypeToLocation = make(map[config.ShellType]string)
for _, shell := range installFlags.shells {
user.Conf.ShellTypeToLocation[config.GetShellType(shell)] = shell
}
}

autoCredentials, err := cmd.Flags().GetBool("auto-credentials")
if err != nil {
Expand All @@ -283,14 +315,14 @@ func install(cmd *cobra.Command, _ []string) error {
user.ConfigureUserSystemInfo(user.Conf)

daemonConf := &daemon.Config{
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellLocation: user.Conf.ShellLocation,
AutoCredential: autoCredentials,
IsWorkspace: isWorkspace,
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
AutoCredential: autoCredentials,
IsWorkspace: isWorkspace,
ShellTypeToLocation: user.Conf.ShellTypeToLocation,
}
dmn := daemon.NewDaemon(daemonConf, logging.Log)

Expand All @@ -300,30 +332,31 @@ func install(cmd *cobra.Command, _ []string) error {
return errors.Wrap(err, "failed to install LDA daemon configuration file")
}

shellConfig := &shell.Config{
ShellType: config.ShellType(user.Conf.ShellType),
ShellLocation: user.Conf.ShellLocation,
IsRoot: user.Conf.IsRoot,
SudoExecUser: user.Conf.User,
LdaDir: user.Conf.LdaDir,
HomeDir: user.Conf.HomeDir,
}
for shellType, shellLocation := range user.Conf.ShellTypeToLocation {
shellConfig := &shell.Config{
ShellType: config.ShellType(shellType),
ShellLocation: shellLocation,
IsRoot: user.Conf.IsRoot,
SudoExecUser: user.Conf.User,
LdaDir: user.Conf.LdaDir,
HomeDir: user.Conf.HomeDir,
}

shl, err := shell.NewShell(shellConfig, logging.Log)
shl, err := shell.NewShell(shellConfig, logging.Log)

if err != nil {
logging.Log.Error().Err(err).Msg("Failed to setup shell")
os.Exit(1)
}
if err != nil {
logging.Log.Error().Err(err).Msg("Failed to setup shell")
os.Exit(1)
}

if err := shl.InstallShellConfiguration(); err != nil {
logging.Log.Error().Err(err).Msg("Failed to install shell configuration")
return errors.Wrap(err, "failed to install LDA shell configuration files")
}
if err := shl.InstallShellConfiguration(); err != nil {
logging.Log.Error().Err(err).Msg("Failed to install shell configuration")
return errors.Wrap(err, "failed to install LDA shell configuration files")
}

if err := shl.InjectShellSource(); err != nil {
logging.Log.Error().Err(err).Msg("Failed to inject shell source")
return errors.Wrap(err, "failed to inject LDA shell source")
if err := shl.InjectShellSource(); err != nil {
logging.Log.Error().Err(err).Msgf("Failed to inject shell source (%s); will reattempt at `start` time", shellLocation)
}
}

fmt.Fprintln(config.SysConfig.Out, "LDA daemon installed successfully.")
Expand All @@ -335,28 +368,35 @@ func uninstall(_ *cobra.Command, _ []string) error {
user.ConfigureUserSystemInfo(user.Conf)

daemonConf := &daemon.Config{
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellLocation: user.Conf.ShellLocation,
ExePath: user.Conf.ExePath,
HomeDir: user.Conf.HomeDir,
IsRoot: user.Conf.IsRoot,
Os: config.OSType(user.Conf.Os),
SudoExecUser: user.Conf.User,
ShellTypeToLocation: user.Conf.ShellTypeToLocation,
}
dmn := daemon.NewDaemon(daemonConf, logging.Log)

shellConfig := &shell.Config{
ShellType: config.ShellType(user.Conf.ShellType),
ShellLocation: user.Conf.ShellLocation,
IsRoot: user.Conf.IsRoot,
SudoExecUser: user.Conf.User,
LdaDir: user.Conf.LdaDir,
HomeDir: user.Conf.HomeDir,
}
shl, err := shell.NewShell(shellConfig, logging.Log)
for shellType, shellLocation := range user.Conf.ShellTypeToLocation {
shellConfig := &shell.Config{
ShellType: config.ShellType(shellType),
ShellLocation: shellLocation,
IsRoot: user.Conf.IsRoot,
SudoExecUser: user.Conf.User,
LdaDir: user.Conf.LdaDir,
HomeDir: user.Conf.HomeDir,
}
shl, err := shell.NewShell(shellConfig, logging.Log)

if err != nil {
logging.Log.Error().Err(err).Msg("Failed to setup shell")
os.Exit(1)
if err != nil {
logging.Log.Error().Err(err).Msg("Failed to setup shell")
os.Exit(1)
}

if err := shl.DeleteShellConfiguration(); err != nil {
logging.Log.Error().Err(err).Msg("Failed to delete shell configuration")
return errors.Wrap(err, "failed to delete LDA shell configuration files")
}
}

fmt.Fprintln(config.SysConfig.Out, "Uninstalling LDA daemon...")
Expand All @@ -365,11 +405,6 @@ func uninstall(_ *cobra.Command, _ []string) error {
return errors.Wrap(err, "failed to uninstall LDA daemon configuration file")
}

if err := shl.DeleteShellConfiguration(); err != nil {
logging.Log.Error().Err(err).Msg("Failed to delete shell configuration")
return errors.Wrap(err, "failed to delete LDA shell configuration files")
}

fmt.Fprintln(config.SysConfig.Out, `Daemon service files and shell configuration deleted successfully,
~/.lda directory still holds database file, and your rc file stills has source script.
If you wish to remove those, delete them manually`)
Expand Down
1 change: 0 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ func SetupSysConfig() {

// SetupConfig initialize the configuration instance
func SetupConfig(ldaDir string, user *user.User) {

configPath := filepath.Join(ldaDir, "config.toml")

if _, err := os.Stat(configPath); errors.Is(err, os.ErrNotExist) {
Expand Down
50 changes: 27 additions & 23 deletions config/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ import (
"github.com/manifoldco/promptui"
)

var (
SupportedShells = []string{"/bin/bash", "/bin/zsh", "/bin/fish"}
)

func GetShellType(shellLocation string) ShellType {
shellType := path.Base(shellLocation)
switch shellType {
case "bash":
return Bash
case "zsh":
return Zsh
case "fish":
return Fish
default:
return -1
}
}

// ShellType is the type of the shell that is supported
type ShellType int

Expand Down Expand Up @@ -100,44 +118,30 @@ func GetLdaBinaryPath() (string, error) {
}

// GetShell sets the current active shell and location
func GetShell() (ShellType, string, error) {

func GetShell() (map[ShellType]string, error) {
shellLocation := os.Getenv("SHELL")

return configureShell(shellLocation)
}

func configureShell(shellLocation string) (ShellType, string, error) {
shellType := path.Base(shellLocation)

var shell ShellType
switch shellType {
case "bash":
shell = Bash
case "zsh":
shell = Zsh
case "fish":
shell = Fish
// TODO: consider supporting "sh" and "ash" as well.
default:
func configureShell(shellLocation string) (map[ShellType]string, error) {
shellTypeToLocation := make(map[ShellType]string)
shell := GetShellType(shellLocation)
if shell < 0 {
shellLocation, err := promptForShellType()
if err != nil {
return -1, "", err
return shellTypeToLocation, err
}
return configureShell(shellLocation)
}

return shell, shellLocation, nil
shellTypeToLocation[shell] = shellLocation
return shellTypeToLocation, nil
}

// promptForShellPath prompts the user to confirm the detected shell path or input a new one.
func promptForShellType() (string, error) {

supportedShells := []string{"/bin/bash", "/bin/zsh", "/bin/fish"}

prompt := promptui.Select{
Label: "We detected an unsupported shell, often this could happen because the script was run as sudo. Currently, we support the following shells. Please select one:",
Items: supportedShells,
Items: SupportedShells,
}

_, result, err := prompt.Run()
Expand Down
17 changes: 8 additions & 9 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ var templateFS embed.FS

// Config is the configuration for the daemon service
type Config struct {
ExePath string
ShellLocation string
HomeDir string
Os config.OSType
IsRoot bool
SudoExecUser *user.User
AutoCredential bool
IsWorkspace bool
ExePath string
HomeDir string
Os config.OSType
IsRoot bool
SudoExecUser *user.User
AutoCredential bool
IsWorkspace bool
ShellTypeToLocation map[config.ShellType]string
}

// Daemon is the service that configures background service
Expand Down Expand Up @@ -79,7 +79,6 @@ func (d *Daemon) InstallDaemonConfiguration() error {
var content bytes.Buffer
var tmpConf = map[string]interface{}{
"BinaryPath": d.config.ExePath,
"Shell": d.config.ShellLocation,
"Home": d.config.HomeDir,
}

Expand Down
Loading

0 comments on commit 3a5340f

Please sign in to comment.