Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os.args() and passthru from CLI #102

Merged
merged 3 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion cmd/risor/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func init() {

rootCmd.Flags().Bool("timing", false, "Show timing information")
rootCmd.Flags().StringP("output", "o", "", "Set the output format")
rootCmd.Flags().SetInterspersed(false)
viper.BindPFlag("timing", rootCmd.Flags().Lookup("timing"))
viper.BindPFlag("output", rootCmd.Flags().Lookup("output"))

Expand Down Expand Up @@ -94,6 +95,45 @@ func fatal(msg string, args ...interface{}) {
os.Exit(1)
}

// this works around issues with cobra not passing args after -- to the script
// see: https://github.com/spf13/cobra/issues/1877
// passedargs is everything after the '--'
// If dropped is true, cobra dropped the double dash in its 'args' slice.
// argsout returns the cobra args but without the '--' and the items behind it
// this also supports multiple '--' in the args list
func getpassthruargs(args []string) (argsout []string, passedargs []string, dropped bool) {
// lenArgs := len(args)
argsout = args
ddashcnt := 0
for n, arg := range os.Args {
if arg == "--" {
ddashcnt++
if len(passedargs) == 0 {
if len(os.Args) > n {
passedargs = os.Args[n+1:]
}
}
}
}
// drop arg0 from count
noddash := true
for n2, argz := range args {
// don't go past the first '--' - this allows one to pass '--' to risor also
if argz == "--" {
noddash = false
argsout = args[:n2]
break
}
}
// cobra seems to drop the '--' in its args if everything before it was a flag
// if thats the case then args is just empty b/c evrything else is the '--' and the passed args
if (noddash || ddashcnt > 1) && len(passedargs) > 0 {
dropped = true
argsout = []string{}
}
return
}

var rootCmd = &cobra.Command{
Use: "risor",
Short: "Fast and flexible scripting for Go developers and DevOps",
Expand All @@ -102,7 +142,11 @@ var rootCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {

ctx := context.Background()
var passedargs []string

args, passedargs, _ = getpassthruargs(args)
// pass the 'passthru' args to risor's os package
ros.SetScriptArgs(passedargs)
// Optionally enable a virtual operating system and add it to
// the context so that it's made available to Risor VM.
if viper.GetBool("virtual-os") {
Expand All @@ -118,7 +162,7 @@ var rootCmd = &cobra.Command{
Target: dst,
}
}
vos := ros.NewVirtualOS(ctx, ros.WithMounts(mounts))
vos := ros.NewVirtualOS(ctx, ros.WithMounts(mounts), ros.WithArgs(passedargs))
ctx = ros.WithOS(ctx, vos)
}

Expand Down
13 changes: 13 additions & 0 deletions modules/os/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ func GetOS(ctx context.Context) os.OS {
return os.GetDefaultOS(ctx)
}

func Args(ctx context.Context, args ...object.Object) object.Object {
if err := arg.Require("os.args", 0, args); err != nil {
return err
}
argz := GetOS(ctx).Args()
items := make([]object.Object, len(argz))
for i, arg := range argz {
items[i] = object.NewString(arg)
}
return object.NewList(items)
}

func Exit(ctx context.Context, args ...object.Object) object.Object {
nArgs := len(args)
if nArgs > 1 {
Expand Down Expand Up @@ -476,6 +488,7 @@ func Cat(ctx context.Context, args ...object.Object) object.Object {

func Module() *object.Module {
return object.NewBuiltinsModule("os", map[string]object.Object{
"args": object.NewBuiltin("args", Args),
"chdir": object.NewBuiltin("chdir", Chdir),
"create": object.NewBuiltin("create", Create),
"environ": object.NewBuiltin("environ", Environ),
Expand Down
15 changes: 15 additions & 0 deletions os/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type FS interface {

type OS interface {
FS
Args() []string
Chdir(dir string) error
Environ() []string
Exit(code int)
Expand All @@ -69,6 +70,8 @@ type OS interface {

type contextKey string

var globalScriptargs []string

const osKey = contextKey("risor:os")

// WithOS adds an OS to the context. Subsequently, when this context is present
Expand All @@ -93,6 +96,18 @@ func GetDefaultOS(ctx context.Context) OS {
return NewSimpleOS(ctx)
}

// if risor is started from the comand line and args
// are passed in, this is is how the to tell the os package about them
func SetScriptArgs(args []string) {
globalScriptargs = args
}

// if risor is started from the comand line and args
// are passed in, this is is how the to get them
func GetScriptArgs() []string {
return globalScriptargs
}

// MassagePathError transforms a fs.PathError into a new one with the base path
// removed from the Path field.
func MassagePathError(basePath string, err error) error {
Expand Down
6 changes: 6 additions & 0 deletions os/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var (
type SimpleOS struct {
ctx context.Context
limits limits.Limits
args []string
}

func NewSimpleOS(ctx context.Context) *SimpleOS {
Expand All @@ -23,9 +24,14 @@ func NewSimpleOS(ctx context.Context) *SimpleOS {
} else {
sos.limits = limits.New()
}
sos.args = globalScriptargs
return sos
}

func (osObj *SimpleOS) Args() []string {
return osObj.args
}

func (osObj *SimpleOS) Chdir(dir string) error {
return os.Chdir(dir)
}
Expand Down
18 changes: 18 additions & 0 deletions os/virtual.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type VirtualOS struct {
exitHandler ExitHandler
stdin File
stdout File
args []string
}

// Option is a configuration function for a Virtual Machine.
Expand Down Expand Up @@ -75,6 +76,13 @@ func WithEnvironment(env map[string]string) Option {
}
}

// set the args passed to the os package for os.args()
func WithArgs(args []string) Option {
return func(vos *VirtualOS) {
vos.args = args
}
}

// WithCwd sets the current working directory.
func WithCwd(cwd string) Option {
return func(vos *VirtualOS) {
Expand Down Expand Up @@ -161,6 +169,16 @@ func NewVirtualOS(ctx context.Context, opts ...Option) *VirtualOS {
return vos
}

func (osObj *VirtualOS) Args() []string {
return osObj.args
}

// a way to override or set the args passed to the os package
// would typically be used when risor is employed in an embedded manner
func (osObj *VirtualOS) SetArgs(args []string) {
osObj.args = args
}

func (osObj *VirtualOS) Chdir(dir string) error {
osObj.cwd = dir
return nil
Expand Down