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+ var argWorkDir string
84+
6985 cmd := & cobra.Command {
70- Use : "exec DEVCONTAINER_NAME COMMAND [ args...] (args will default to /bin/bash if none provided)" ,
86+ Use : "exec [--name <name>| --path <path> | --prompt ] [--work-dir <work-dir>] [<command> [< args...>]] (command will default to /bin/bash if none provided)" ,
7187 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. " ,
88+ Long : "Execute a command in a devcontainer, similar to `docker exec`" ,
7389 RunE : func (cmd * cobra.Command , args []string ) error {
7490
75- if len (args ) < 1 {
76- return cmd .Usage ()
91+ // Default to executing /bin/bash
92+ if len (args ) == 0 {
93+ args = []string {"/bin/bash" }
7794 }
7895
79- // Default to executing /bin/bash
80- if (len (args ) == 1 ) {
81- args = append (args , "/bin/bash" )
96+ sourceCount := countBooleans (
97+ argDevcontainerName != "" ,
98+ argDevcontainerPath != "" ,
99+ argPromptForDevcontainer ,
100+ )
101+ if sourceCount > 0 {
102+ fmt .Println ("Can specify at most one of --name/--path/--prompt" )
103+ return cmd .Usage ()
82104 }
83105
84- devcontainerName := args [ 0 ]
106+ containerID := ""
85107 devcontainerList , err := devcontainers .ListDevcontainers ()
86108 if err != nil {
87109 return err
88110 }
89-
90- containerID := ""
91- if devcontainerName == "?" {
111+ if argDevcontainerName != "" {
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,25 +129,47 @@ 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 )
116163 if err != nil {
117164 return err
118165 }
119166
120- mountPath , err := devcontainers .GetWorkspaceMountPath (localPath )
121- if err != nil {
122- return err
167+ mountPath := argWorkDir
168+ if mountPath == "" {
169+ mountPath , err = devcontainers .GetWorkspaceMountPath (localPath )
170+ if err != nil {
171+ return err
172+ }
123173 }
124174
125175 wslPath := localPath
@@ -130,8 +180,8 @@ func createExecCommand() *cobra.Command {
130180 }
131181 }
132182
133- devcontainerJsonPath := path .Join (wslPath , ".devcontainer/devcontainer.json" )
134- userName , err := devcontainers .GetDevContainerUserName (devcontainerJsonPath )
183+ devcontainerJSONPath := path .Join (wslPath , ".devcontainer/devcontainer.json" )
184+ userName , err := devcontainers .GetDevContainerUserName (devcontainerJSONPath )
135185 if err != nil {
136186 return err
137187 }
@@ -141,24 +191,23 @@ func createExecCommand() *cobra.Command {
141191 dockerArgs = append (dockerArgs , "--user" , userName )
142192 }
143193 dockerArgs = append (dockerArgs , containerID )
144- dockerArgs = append (dockerArgs , args [ 1 :] ... )
194+ dockerArgs = append (dockerArgs , args ... )
145195
146196 dockerCmd := exec .Command ("docker" , dockerArgs ... )
147197 dockerCmd .Stdin = os .Stdin
148198 dockerCmd .Stdout = os .Stdout
149199
150200 err = dockerCmd .Start ()
151201 if err != nil {
152- return fmt .Errorf ("Exec: start error: %s\n " , err )
202+ return fmt .Errorf ("Exec: start error: %s" , err )
153203 }
154204 err = dockerCmd .Wait ()
155205 if err != nil {
156- return fmt .Errorf ("Exec: wait error: %s\n " , err )
206+ return fmt .Errorf ("Exec: wait error: %s" , err )
157207 }
158208 return nil
159209 },
160210 Args : cobra .ArbitraryArgs ,
161- DisableFlagParsing : true ,
162211 DisableFlagsInUseLine : true ,
163212 ValidArgsFunction : func (cmd * cobra.Command , args []string , toComplete string ) ([]string , cobra.ShellCompDirective ) {
164213 // only completing the first arg (devcontainer name)
@@ -177,5 +226,9 @@ func createExecCommand() *cobra.Command {
177226 return names , cobra .ShellCompDirectiveNoFileComp
178227 },
179228 }
229+ cmd .Flags ().StringVarP (& argDevcontainerName , "name" , "n" , "" , "name of dev container to exec into" )
230+ cmd .Flags ().StringVarP (& argDevcontainerPath , "path" , "" , "" , "path containing the dev container to exec into" )
231+ cmd .Flags ().BoolVarP (& argPromptForDevcontainer , "prompt" , "" , false , "prompt for the dev container to exec into" )
232+ cmd .Flags ().StringVarP (& argWorkDir , "work-dir" , "" , "" , "working directory to use in the dev container" )
180233 return cmd
181234}
0 commit comments