66 "os"
77 "path/filepath"
88 "regexp"
9+ "runtime"
10+ "strings"
911)
1012
1113// ExtractFileExtension extracts the extension from a filename. This is defined
@@ -90,12 +92,13 @@ var LookupImageByExtension = func() func(string) DexecImage {
9092const dexecPath = "/tmp/dexec/build"
9193const dexecImageTemplate = "%s:%s"
9294const dexecVolumeTemplate = "%s/%s:%s/%s"
95+ const dexecSanitisedWindowsPathPattern = "/%s%s"
9396
9497// ExtractBasenameAndPermission takes an include string and splits it into
9598// its file or folder name and the permission string if present or the empty
9699// string if not.
97100func ExtractBasenameAndPermission (path string ) (string , string ) {
98- pathPattern := regexp .MustCompile ("([\\ w.-]+)(:(rw|ro))" )
101+ pathPattern := regexp .MustCompile ("([\\ w.: -]+)(:(rw|ro))" )
99102 match := pathPattern .FindStringSubmatch (path )
100103
101104 basename := path
@@ -108,30 +111,64 @@ func ExtractBasenameAndPermission(path string) (string, string) {
108111 return basename , permission
109112}
110113
111- // RunDexecContainer runs an anonymous Docker container with a Docker Exec
112- // image, mounting the specified sources and includes and passing the
113- // list of sources and arguments to the entrypoint.
114- func RunDexecContainer (dexecImage DexecImage , options map [OptionType ][]string ) {
115- dockerImage := fmt .Sprintf (dexecImageTemplate , dexecImage .image , dexecImage .version )
116-
117- path := "."
118- if len (options [TargetDir ]) > 0 {
119- path = options [TargetDir ][0 ]
120- }
121- absPath , _ := filepath .Abs (path )
114+ // BuildVolumeArgs takes a base path and returns an array of Docker volume
115+ // arguments. The array takes the form {"-v", "/foo:/bar:[rw|ro]", ...} for
116+ // each source or include.
117+ func BuildVolumeArgs (path string , targets []string ) []string {
118+ var volumeArgs []string
122119
123- var dockerArgs []string
124- for _ , source := range append (options [Source ], options [Include ]... ) {
120+ for _ , source := range targets {
125121 basename , _ := ExtractBasenameAndPermission (source )
126122
127- dockerArgs = append (
128- dockerArgs ,
123+ volumeArgs = append (
124+ volumeArgs ,
129125 []string {
130126 "-v" ,
131- fmt .Sprintf (dexecVolumeTemplate , absPath , basename , dexecPath , source ),
127+ fmt .Sprintf (dexecVolumeTemplate , path , basename , dexecPath , source ),
132128 }... ,
133129 )
134130 }
131+ return volumeArgs
132+ }
133+
134+ // SanitisePath takes an absolute path as provided by filepath.Abs() and
135+ // makes it ready to be passed to Docker based on the current OS. So far
136+ // the only OS format that requires transforming is Windows which is provided
137+ // in the form 'C:\some\path' but Docker requires '/c/some/path'.
138+ func SanitisePath (path string , platform string ) string {
139+ sanitised := path
140+ if platform == "windows" {
141+ windowsPathPattern := regexp .MustCompile ("^([A-Za-z]):(.*)" )
142+ match := windowsPathPattern .FindStringSubmatch (path )
143+
144+ driveLetter := strings .ToLower (match [1 ])
145+ pathRemainder := strings .Replace (match [2 ], "\\ " , "/" , - 1 )
146+
147+ sanitised = fmt .Sprintf (dexecSanitisedWindowsPathPattern , driveLetter , pathRemainder )
148+ }
149+ return sanitised
150+ }
151+
152+ // RetrievePath takes an array whose first element may contain an overridden
153+ // path and converts either this, or the default of "." to an absolute path
154+ // using Go's file utilities. This is then passed to SanitisedPath with the
155+ // current OS to get it into a Docker ready format.
156+ func RetrievePath (targetDirs []string ) string {
157+ path := "."
158+ if len (targetDirs ) > 0 {
159+ path = targetDirs [0 ]
160+ }
161+ absPath , _ := filepath .Abs (path )
162+ return SanitisePath (absPath , runtime .GOOS )
163+ }
164+
165+ // RunDexecContainer runs an anonymous Docker container with a Docker Exec
166+ // image, mounting the specified sources and includes and passing the
167+ // list of sources and arguments to the entrypoint.
168+ func RunDexecContainer (dexecImage DexecImage , options map [OptionType ][]string ) {
169+ dockerImage := fmt .Sprintf (dexecImageTemplate , dexecImage .image , dexecImage .version )
170+
171+ volumeArgs := BuildVolumeArgs (RetrievePath (options [TargetDir ]), append (options [Source ], options [Include ]... ))
135172
136173 var sourceBasenames []string
137174 for _ , source := range options [Source ] {
@@ -151,7 +188,7 @@ func RunDexecContainer(dexecImage DexecImage, options map[OptionType][]string) {
151188
152189 RunAnonymousContainer (
153190 dockerImage ,
154- dockerArgs ,
191+ volumeArgs ,
155192 entrypointArgs ,
156193 )
157194}
0 commit comments