55 "os"
66 "os/exec"
77 "path"
8+ "path/filepath"
89 "sort"
910 "strings"
1011 "text/tabwriter"
@@ -65,30 +66,57 @@ func createListCommand() *cobra.Command {
6566 return cmdList
6667}
6768
69+ func countBooleans (values ... bool ) int {
70+ count := 0
71+ for _ , v := range values {
72+ if v {
73+ count ++
74+ }
75+ }
76+ return count
77+ }
78+
6879func createExecCommand () * cobra.Command {
80+ var argDevcontainerName string
81+ var argDevcontainerPath string
82+ var argPromptForDevcontainer bool
83+
6984 cmd := & cobra.Command {
70- Use : "exec DEVCONTAINER_NAME COMMAND [ args...] (args will default to /bin/bash if none provided)" ,
85+ Use : "exec [--name <name>| --path <path> | --prompt ] [<command> [< args...>]] (command will default to /bin/bash if none provided)" ,
7186 Short : "Execute a command in a devcontainer" ,
72- Long : "Execute a command in a devcontainer, similar to `docker exec`. Pass `?` as DEVCONTAINER_NAME to be prompted. " ,
87+ Long : "Execute a command in a devcontainer, similar to `docker exec`" ,
7388 RunE : func (cmd * cobra.Command , args []string ) error {
7489
75- if len (args ) < 1 {
76- return cmd .Usage ()
90+ // Default to executing /bin/bash
91+ if len (args ) == 0 {
92+ args = []string {"/bin/bash" }
7793 }
7894
79- // Default to executing /bin/bash
80- if (len (args ) == 1 ) {
81- args = append (args , "/bin/bash" )
95+ sourceCount := countBooleans (
96+ argDevcontainerName != "" ,
97+ argDevcontainerPath != "" ,
98+ argPromptForDevcontainer ,
99+ )
100+ if sourceCount > 0 {
101+ fmt .Println ("Can specify at most one of --name/--path/--prompt" )
102+ return cmd .Usage ()
82103 }
83104
84- devcontainerName := args [ 0 ]
105+ containerID := ""
85106 devcontainerList , err := devcontainers .ListDevcontainers ()
86107 if err != nil {
87108 return err
88109 }
89-
90- containerID := ""
91- if devcontainerName == "?" {
110+ if argDevcontainerName != "" {
111+ var devcontainerName string
112+ devcontainerName = argDevcontainerName
113+ for _ , devcontainer := range devcontainerList {
114+ if devcontainer .ContainerName == devcontainerName || devcontainer .DevcontainerName == devcontainerName {
115+ containerID = devcontainer .ContainerID
116+ break
117+ }
118+ }
119+ } else if argPromptForDevcontainer {
92120 // prompt user
93121 fmt .Println ("Specify the devcontainer to use:" )
94122 for index , devcontainer := range devcontainerList {
@@ -101,15 +129,34 @@ func createExecCommand() *cobra.Command {
101129 }
102130 containerID = devcontainerList [selection ].ContainerID
103131 } else {
132+ devcontainerPath := argDevcontainerPath
133+ if devcontainerPath == "" {
134+ devcontainerPath = "."
135+ }
136+ absPath , err := filepath .Abs (devcontainerPath )
137+ if err != nil {
138+ return fmt .Errorf ("Error handling path %q: %s" , devcontainerPath , err )
139+ }
140+
141+ windowsPath := absPath
142+ if wsl .IsWsl () {
143+ var err error
144+ windowsPath , err = wsl .ConvertWslPathToWindowsPath (windowsPath )
145+ if err != nil {
146+ return err
147+ }
148+ }
104149 for _ , devcontainer := range devcontainerList {
105- if devcontainer .ContainerName == devcontainerName || devcontainer . DevcontainerName == devcontainerName {
150+ if devcontainer .LocalFolderPath == windowsPath {
106151 containerID = devcontainer .ContainerID
107152 break
108153 }
109154 }
110- if containerID == "" {
111- return cmd .Usage ()
112- }
155+ }
156+
157+ if containerID == "" {
158+ fmt .Println ("Failed to find dev container" )
159+ return cmd .Usage ()
113160 }
114161
115162 localPath , err := devcontainers .GetLocalFolderFromDevContainer (containerID )
@@ -130,8 +177,8 @@ func createExecCommand() *cobra.Command {
130177 }
131178 }
132179
133- devcontainerJsonPath := path .Join (wslPath , ".devcontainer/devcontainer.json" )
134- userName , err := devcontainers .GetDevContainerUserName (devcontainerJsonPath )
180+ devcontainerJSONPath := path .Join (wslPath , ".devcontainer/devcontainer.json" )
181+ userName , err := devcontainers .GetDevContainerUserName (devcontainerJSONPath )
135182 if err != nil {
136183 return err
137184 }
@@ -141,24 +188,24 @@ func createExecCommand() *cobra.Command {
141188 dockerArgs = append (dockerArgs , "--user" , userName )
142189 }
143190 dockerArgs = append (dockerArgs , containerID )
144- dockerArgs = append (dockerArgs , args [ 1 :] ... )
191+ dockerArgs = append (dockerArgs , args ... )
145192
146193 dockerCmd := exec .Command ("docker" , dockerArgs ... )
147194 dockerCmd .Stdin = os .Stdin
148195 dockerCmd .Stdout = os .Stdout
149196
150197 err = dockerCmd .Start ()
151198 if err != nil {
152- return fmt .Errorf ("Exec: start error: %s\n " , err )
199+ return fmt .Errorf ("Exec: start error: %s" , err )
153200 }
154201 err = dockerCmd .Wait ()
155202 if err != nil {
156- return fmt .Errorf ("Exec: wait error: %s\n " , err )
203+ return fmt .Errorf ("Exec: wait error: %s" , err )
157204 }
158205 return nil
159206 },
160- Args : cobra .ArbitraryArgs ,
161- DisableFlagParsing : true ,
207+ Args : cobra .ArbitraryArgs ,
208+ // DisableFlagParsing: true,
162209 DisableFlagsInUseLine : true ,
163210 ValidArgsFunction : func (cmd * cobra.Command , args []string , toComplete string ) ([]string , cobra.ShellCompDirective ) {
164211 // only completing the first arg (devcontainer name)
@@ -177,5 +224,8 @@ func createExecCommand() *cobra.Command {
177224 return names , cobra .ShellCompDirectiveNoFileComp
178225 },
179226 }
227+ cmd .Flags ().StringVarP (& argDevcontainerName , "name" , "n" , "" , "name of dev container to exec into" )
228+ cmd .Flags ().StringVarP (& argDevcontainerPath , "path" , "" , "" , "path containing the dev container to exec into" )
229+ cmd .Flags ().BoolVarP (& argPromptForDevcontainer , "prompt" , "" , false , "prompt for the dev container to exec into" )
180230 return cmd
181231}
0 commit comments