diff --git a/args/args.go b/args/args.go new file mode 100644 index 0000000..fe70f3a --- /dev/null +++ b/args/args.go @@ -0,0 +1,14 @@ +package args + +import ( + "fmt" + "strings" +) + +func InterpolateCommand(rawCommand string, optionalPositionalArgs []string) string { + // replace $1, $2, etc. with the optional positional args + for i, arg := range optionalPositionalArgs { + rawCommand = strings.ReplaceAll(rawCommand, fmt.Sprintf("$%d", i+1), arg) + } + return rawCommand +} diff --git a/checks/command.go b/checks/command.go index ebbbb90..6ba5ffe 100644 --- a/checks/command.go +++ b/checks/command.go @@ -3,16 +3,19 @@ package checks import ( "os/exec" + "github.com/bootdotdev/bootdev/args" api "github.com/bootdotdev/bootdev/client" ) func CLICommand( assignment api.Assignment, + optionalPositionalArgs []string, ) []api.CLICommandResult { data := assignment.Assignment.AssignmentDataCLICommand.CLICommandData responses := make([]api.CLICommandResult, len(data.Commands)) for i, command := range data.Commands { - cmd := exec.Command("sh", "-c", command.Command) + finalCommand := args.InterpolateCommand(command.Command, optionalPositionalArgs) + cmd := exec.Command("sh", "-c", finalCommand) b, err := cmd.Output() if ee, ok := err.(*exec.ExitError); ok { responses[i].ExitCode = ee.ExitCode() diff --git a/cmd/run.go b/cmd/run.go index 534a586..6909eae 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -12,7 +12,7 @@ func init() { // runCmd represents the run command var runCmd = &cobra.Command{ Use: "run UUID", - Args: cobra.ExactArgs(1), + Args: cobra.MatchAll(cobra.RangeArgs(1, 10)), Short: "Run an assignment without submitting", PreRun: compose(requireUpdated, requireAuth), RunE: submissionHandler, diff --git a/cmd/submit.go b/cmd/submit.go index 4621c97..bcb20f3 100644 --- a/cmd/submit.go +++ b/cmd/submit.go @@ -20,7 +20,7 @@ func init() { // submitCmd represents the submit command var submitCmd = &cobra.Command{ Use: "submit UUID", - Args: cobra.MatchAll(cobra.ExactArgs(1)), + Args: cobra.MatchAll(cobra.RangeArgs(1, 10)), Short: "Submit an assignment", PreRun: compose(requireUpdated, requireAuth), RunE: submissionHandler, @@ -30,6 +30,11 @@ func submissionHandler(cmd *cobra.Command, args []string) error { cmd.SilenceUsage = true isSubmit := cmd.Name() == "submit" assignmentUUID := args[0] + optionalPositionalArgs := []string{} + if len(args) > 1 { + optionalPositionalArgs = args[1:] + } + assignment, err := api.FetchAssignment(assignmentUUID) if err != nil { return err @@ -46,16 +51,16 @@ func submissionHandler(cmd *cobra.Command, args []string) error { fmt.Println("\nSubmitted! Check the lesson on Boot.dev for results") } case "type_cli_command": - results := checks.CLICommand(*assignment) + results := checks.CLICommand(*assignment, optionalPositionalArgs) data := *assignment.Assignment.AssignmentDataCLICommand if isSubmit { failure, err := api.SubmitCLICommandAssignment(assignmentUUID, results) if err != nil { return err } - render.CommandSubmission(data, results, failure) + render.CommandSubmission(data, results, failure, optionalPositionalArgs) } else { - render.CommandRun(data, results) + render.CommandRun(data, results, optionalPositionalArgs) } default: return errors.New("unsupported assignment type") diff --git a/render/command.go b/render/command.go index e85a9bc..e031c32 100644 --- a/render/command.go +++ b/render/command.go @@ -7,12 +7,12 @@ import ( "sync" "time" + "github.com/bootdotdev/bootdev/args" api "github.com/bootdotdev/bootdev/client" "github.com/charmbracelet/bubbles/spinner" + tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/muesli/termenv" - - tea "github.com/charmbracelet/bubbletea" ) var green = lipgloss.NewStyle().Foreground(lipgloss.Color("2")) @@ -131,7 +131,7 @@ func (m rootModel) View() string { if !cmd.finished { cmdStr += fmt.Sprintf("%s %s", s, cmd.command) } else if !m.isSubmit { - cmdStr += fmt.Sprintf("%s", cmd.command) + cmdStr += cmd.command } else if cmd.passed == nil { cmdStr += gray.Render(fmt.Sprintf("? %s", cmd.command)) } else if *cmd.passed { @@ -215,16 +215,18 @@ func pointerToBool(a bool) *bool { func CommandRun( data api.AssignmentDataCLICommand, results []api.CLICommandResult, + optionalPositionalArgs []string, ) { - commandRenderer(data, results, nil, false) + commandRenderer(data, results, nil, false, optionalPositionalArgs) } func CommandSubmission( data api.AssignmentDataCLICommand, results []api.CLICommandResult, failure *api.StructuredErrCLICommand, + optionalPositionalArgs []string, ) { - commandRenderer(data, results, failure, true) + commandRenderer(data, results, failure, true, optionalPositionalArgs) } func commandRenderer( @@ -232,6 +234,7 @@ func commandRenderer( results []api.CLICommandResult, failure *api.StructuredErrCLICommand, isSubmit bool, + optionalPositionalArgs []string, ) { var wg sync.WaitGroup ch := make(chan tea.Msg, 1) @@ -259,7 +262,8 @@ func commandRenderer( defer wg.Done() for i, cmd := range data.CLICommandData.Commands { - ch <- startCmdMsg{cmd: cmd.Command} + finalCommand := args.InterpolateCommand(cmd.Command, optionalPositionalArgs) + ch <- startCmdMsg{cmd: finalCommand} for _, test := range cmd.Tests { ch <- startTestMsg{text: prettyPrint(test)} }