subprocess

package
v0.40.1 Latest Latest
Warning

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

Go to latest
Published: Nov 13, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package subprocess provides the subprocess extension library.

Index

Constants

View Source
const LibraryName = "subprocess"

LibraryName is the script-visible name of the subprocess library.

Variables

View Source
var CompletedProcessClass = &object.Class{
	Name: "CompletedProcess",
	Methods: map[string]object.Object{
		"check_returncode": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.ExactArgs(args, 1); err != nil {
					return err
				}
				if instance, ok := args[0].(*object.Instance); ok {
					if returncode, ok := instance.Field("returncode").(*object.Integer); ok {
						if returncode.IntValue() != 0 {
							return errors.NewError("Command returned non-zero exit status %d", returncode.IntValue())
						}
						return args[0]
					}
				}
				return errors.NewError("Invalid CompletedProcess instance")
			},
			HelpText: `check_returncode() - Check if the process returned successfully

Raises an exception if returncode is non-zero.`,
		},
	},
}

CompletedProcessClass defines the CompletedProcess class

View Source
var Library = object.NewLibrary(LibraryName, map[string]*object.Builtin{
	"run": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.MinArgs(args, 1); err != nil {
				return err
			}

			// Parse args - can be string or list
			var cmdArgs []string
			var cmdStr string
			if args[0].Type() == object.STRING_OBJ {
				cmdStr, _ = args[0].AsString()

				shell := false
				if sh, exists := kwargs.Kwargs["shell"]; exists {
					if b, ok := sh.(*object.Boolean); ok {
						shell = b.BoolValue()
					}
				}
				if shell {

					cmdArgs = []string{cmdStr}
				} else {

					cmdArgs = strings.Fields(cmdStr)
				}
			} else if args[0].Type() == object.LIST_OBJ {
				list, _ := args[0].AsList()
				cmdArgs = make([]string, len(list))
				for i, arg := range list {
					if str, err := arg.AsString(); err == nil {
						cmdArgs[i] = str
					} else {
						return errors.NewTypeError("STRING", arg.Type().String())
					}
				}
			} else {
				return errors.NewTypeError("STRING or LIST", args[0].Type().String())
			}

			captureOutput := false
			shell := false
			cwd := ""
			timeout := 0.0
			check := false
			text := false
			encoding := "utf-8"
			inputData := ""
			env := make(map[string]string)

			if capture, exists := kwargs.Kwargs["capture_output"]; exists {
				if b, ok := capture.(*object.Boolean); ok {
					captureOutput = b.BoolValue()
				}
			}
			if sh, exists := kwargs.Kwargs["shell"]; exists {
				if b, ok := sh.(*object.Boolean); ok {
					shell = b.BoolValue()
				}
			}
			if wd, exists := kwargs.Kwargs["cwd"]; exists {
				if s, ok := wd.(*object.String); ok {
					cwd = s.StringValue()
				}
			}
			if to, exists := kwargs.Kwargs["timeout"]; exists {
				if f, ok := to.(*object.Float); ok {
					timeout = f.FloatValue()
				} else if i, ok := to.(*object.Integer); ok {
					timeout = float64(i.IntValue())
				}
			}
			if ch, exists := kwargs.Kwargs["check"]; exists {
				if b, ok := ch.(*object.Boolean); ok {
					check = b.BoolValue()
				}
			}
			if txt, exists := kwargs.Kwargs["text"]; exists {
				if b, ok := txt.(*object.Boolean); ok {
					text = b.BoolValue()
				}
			}
			if enc, exists := kwargs.Kwargs["encoding"]; exists {
				if s, ok := enc.(*object.String); ok {
					encoding = s.StringValue()
				}
			}
			if inp, exists := kwargs.Kwargs["input"]; exists {
				if s, ok := inp.(*object.String); ok {
					inputData = s.StringValue()
				}
			}
			if envDict, exists := kwargs.Kwargs["env"]; exists {
				if d, ok := envDict.(*object.Dict); ok {
					for _, pair := range d.Pairs {
						if valStr, ok := pair.Value.(*object.String); ok {
							env[pair.StringKey()] = valStr.StringValue()
						}
					}
				}
			}

			if shell && args[0].Type() == object.STRING_OBJ {
				cmdArgs = []string{"sh", "-c", cmdStr}
			}

			// Execute command
			var cmd *exec.Cmd
			if shell && args[0].Type() == object.STRING_OBJ {
				cmd = exec.Command(cmdArgs[0], cmdArgs[1:]...)
			} else {
				cmd = exec.Command(cmdArgs[0], cmdArgs[1:]...)
			}

			if cwd != "" {
				cmd.Dir = cwd
			}

			if len(env) > 0 {
				cmd.Env = make([]string, 0, len(env))
				for k, v := range env {
					cmd.Env = append(cmd.Env, k+"="+v)
				}
			}

			if inputData != "" {
				cmd.Stdin = strings.NewReader(inputData)
			}

			if timeout > 0 {
				ctx, cancel := context.WithTimeout(ctx, time.Duration(timeout*float64(time.Second)))
				defer cancel()
				cmd = exec.CommandContext(ctx, cmd.Path, cmd.Args[1:]...)
				cmd.Dir = cwd
				if len(env) > 0 {
					cmd.Env = make([]string, 0, len(env))
					for k, v := range env {
						cmd.Env = append(cmd.Env, k+"="+v)
					}
				}
				if inputData != "" {
					cmd.Stdin = strings.NewReader(inputData)
				}
			}

			var stdout, stderr []byte
			var err error

			object.RunBlocking(ctx, func() {
				if captureOutput {
					stdout, err = cmd.Output()
					if exitErr, ok := err.(*exec.ExitError); ok {
						stderr = exitErr.Stderr
					}
				} else {
					err = cmd.Run()
				}
			})

			returncode := 0
			if err != nil {
				if exitErr, ok := err.(*exec.ExitError); ok {
					returncode = exitErr.ExitCode()
				} else {
					return errors.NewError("Command execution failed: %v", err)
				}
			}

			// Convert output based on text/encoding settings
			var stdoutStr, stderrStr string
			if text {

				_ = encoding
				stdoutStr = string(stdout)
				stderrStr = string(stderr)
			} else {

				stdoutStr = string(stdout)
				stderrStr = string(stderr)
			}
			instance := object.NewInstanceWithFields(CompletedProcessClass, map[string]object.Object{
				"args":       &object.List{Elements: make([]object.Object, len(cmdArgs))},
				"returncode": object.NewInteger(int64(returncode)),
				"stdout":     object.NewString(stdoutStr),
				"stderr":     object.NewString(stderrStr),
			})
			for i, arg := range cmdArgs {
				instance.Field("args").(*object.List).Elements[i] = object.NewString(arg)
			}

			if check && returncode != 0 {
				return errors.NewError("Command returned non-zero exit status %d", returncode)
			}

			return instance
		},
		HelpText: `run(args, options={}) - Run a command

Runs a command and returns a CompletedProcess instance.

Parameters:
  args (string or list): Command to run. If string, split on spaces. If list, each element is an argument.
  options (dict, optional): Options
    - capture_output (bool): Capture stdout and stderr (default: false)
    - shell (bool): Run command through shell (default: false)
    - cwd (string): Working directory for command
    - timeout (int): Timeout in seconds
    - check (bool): Raise exception if returncode is non-zero

Returns:
  CompletedProcess instance with args, returncode, stdout, stderr`,
	},
}, map[string]object.Object{}, "Subprocess library for running external commands")

Library provides Python's subprocess module.

Functions

func Register

func Register(registrar interface{ RegisterLibrary(*object.Library) })

Register registers the subprocess library.

Types

type CompletedProcess

type CompletedProcess struct {
	Args       []string
	Returncode int
	Stdout     string
	Stderr     string
}

CompletedProcess represents the result of a subprocess.run call

func (*CompletedProcess) AsBool

func (cp *CompletedProcess) AsBool() (bool, object.Object)

func (*CompletedProcess) AsDict

func (cp *CompletedProcess) AsDict() (map[string]object.Object, object.Object)

func (*CompletedProcess) AsFloat

func (cp *CompletedProcess) AsFloat() (float64, object.Object)

func (*CompletedProcess) AsInt

func (cp *CompletedProcess) AsInt() (int64, object.Object)

func (*CompletedProcess) AsList

func (cp *CompletedProcess) AsList() ([]object.Object, object.Object)

func (*CompletedProcess) AsString

func (cp *CompletedProcess) AsString() (string, object.Object)

func (*CompletedProcess) Inspect

func (cp *CompletedProcess) Inspect() string

func (*CompletedProcess) Type

func (cp *CompletedProcess) Type() object.ObjectType

Jump to

Keyboard shortcuts

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