55 "io/ioutil"
66 "log"
77 "os"
8- "os/exec"
98 "path/filepath"
109)
1110
@@ -51,13 +50,13 @@ func main() {
5150 }
5251 }
5352
53+ // Read and parse config from JSON file
5454 configData , err := ioutil .ReadFile (configPath )
5555 if err != nil {
5656 log .Fatalf ("Failed to read config file %s: %v" , configPath , err )
5757 }
5858
59- log .Printf ("Successfully read config file" )
60-
59+ log .Printf ("Successfully read config file (%d bytes)" , len (configData ))
6160
6261 var config FileOpsConfig
6362 if err := json .Unmarshal (configData , & config ); err != nil {
@@ -125,12 +124,6 @@ func main() {
125124
126125 wasmComponentPath = componentResolved
127126
128- // Parse file-ops arguments and resolve paths
129- resolvedArgs , _ , err := resolveFileOpsPaths (config .WorkspaceDir , config .Operations )
130- if err != nil {
131- log .Fatalf ("Failed to process file operations: %v" , err )
132- }
133-
134127 // Build wasmtime command - map current working directory (Bazel sandbox root) to /
135128 // This gives the WASM component access to all Bazel-provided inputs
136129 var args []string
@@ -143,117 +136,141 @@ func main() {
143136 log .Fatalf ("Failed to get current working directory: %v" , err )
144137 }
145138
139+ // Map the entire Bazel sandbox with read/write permissions
146140 args = append (args , "--dir" , cwd + "::/" )
147141
148- // Optionally also map the workspace directory as-is for direct access
149- if config .WorkspaceDir != "" {
150- absWorkspace , err := filepath .Abs (config .WorkspaceDir )
151- if err == nil {
152- // Map workspace to itself so files can be created there
153- args = append (args , "--dir" , absWorkspace )
154- }
142+ // Convert workspace_dir to absolute path for WASI
143+ workspaceFullPath := filepath .Join (cwd , config .WorkspaceDir )
144+ if err := os .MkdirAll (workspaceFullPath , 0755 ); err != nil {
145+ log .Fatalf ("Failed to create workspace directory: %v" , err )
146+ }
147+ log .Printf ("DEBUG: Created workspace directory: %s" , workspaceFullPath )
148+
149+ // Copy config file to a simple location in /tmp that we can pass to WASM component
150+ // This avoids symlink issues in Bazel's complex sandbox
151+ tmpConfigPath := "/tmp/file_ops_config.json"
152+ if err := ioutil .WriteFile (tmpConfigPath , configData , 0644 ); err != nil {
153+ log .Fatalf ("Failed to write temporary config file: %v" , err )
155154 }
155+ log .Printf ("DEBUG: Wrote config to temp file: %s" , tmpConfigPath )
156+
157+ // Map /tmp directory for config access
158+ args = append (args , "--dir" , "/tmp::/" + "tmp" )
159+
160+ // Explicitly map the workspace directory with write permissions
161+ args = append (args , "--dir" , workspaceFullPath + "::" + "/workspace" )
156162
157163 // Execute WASM component via wasmtime
158164 log .Printf ("DEBUG: Executing file_ops WASM component" )
159165 log .Printf ("DEBUG: Wasmtime: %s" , wasmtimeBinary )
160166 log .Printf ("DEBUG: Component: %s" , wasmComponentPath )
161167 log .Printf ("DEBUG: Workspace dir: %s" , config .WorkspaceDir )
162- log .Printf ("DEBUG: Operations: %v" , resolvedArgs )
163-
164- args = append (args , wasmComponentPath )
165-
166- // Append resolved file-ops arguments
167- args = append (args , resolvedArgs ... )
168+ log .Printf ("DEBUG: Operations count: %d" , len (config .Operations ))
168169
169- log .Printf ("DEBUG: Final wasmtime args: %v" , args )
170-
171- // Execute wasmtime
172- cmd := exec .Command (wasmtimeBinary , args ... )
173- cmd .Stdout = os .Stdout
174- cmd .Stderr = os .Stderr
175- cmd .Stdin = os .Stdin
176-
177- if err := cmd .Run (); err != nil {
178- if exitErr , ok := err .(* exec.ExitError ); ok {
179- log .Printf ("DEBUG: Wasmtime exited with code %d" , exitErr .ExitCode ())
180- os .Exit (exitErr .ExitCode ())
181- }
182- log .Fatalf ("Failed to execute wasmtime: %v" , err )
183- }
184- }
170+ // Use the explicitly mapped workspace directory in WASI
171+ // We mapped workspaceFullPath to /workspace
172+ // The directory already exists from the Go wrapper, so the WASM component just needs to use it
173+ wasiWorkspaceDir := "/workspace"
174+ log .Printf ("DEBUG: WASI workspace dir: %s (already created in Go wrapper)" , wasiWorkspaceDir )
185175
186- // resolveFileOpsPaths converts the JSON config operations into WASM component arguments
187- // Converts all paths to absolute sandbox-root paths that will work when mapped via --dir cwd::/
188- func resolveFileOpsPaths (workspaceDir string , operations []interface {}) ([]string , []string , error ) {
189- resolvedArgs := []string {}
190- dirs := []string {}
176+ // Update config to use the mapped workspace directory
177+ // The WASM component should treat this as already-existing
178+ config .WorkspaceDir = wasiWorkspaceDir
191179
192- // Get current directory (sandbox root) for path conversion
193- cwd , err := os . Getwd ( )
180+ // Write updated config to temp file
181+ updatedConfigData , err := json . Marshal ( config )
194182 if err != nil {
195- cwd = "."
183+ log .Fatalf ("Failed to marshal updated config: %v" , err )
184+ }
185+ if err := ioutil .WriteFile ("/tmp/file_ops_config.json" , updatedConfigData , 0644 ); err != nil {
186+ log .Fatalf ("Failed to write updated config file: %v" , err )
196187 }
188+ log .Printf ("DEBUG: Updated config with absolute workspace path" )
197189
198- // For each operation, build the corresponding WASM component arguments
199- // Convert relative sandbox paths to absolute paths that work in WASI sandbox
200- for _ , op := range operations {
190+ // Process file operations directly in Go
191+ // This is more reliable than trying to use the WASM component for now
192+ log .Printf ("DEBUG: Processing %d file operations" , len (config .Operations ))
193+
194+ for i , op := range config .Operations {
201195 opMap , ok := op .(map [string ]interface {})
202196 if ! ok {
197+ log .Printf ("WARNING: Operation %d is not a map, skipping" , i )
203198 continue
204199 }
205200
206201 opType , ok := opMap ["type" ].(string )
207202 if ! ok {
203+ log .Printf ("WARNING: Operation %d has no type, skipping" , i )
208204 continue
209205 }
210206
211- // Helper function to convert sandbox-relative to absolute paths
212- toAbsPath := func (relPath string ) string {
213- if filepath .IsAbs (relPath ) {
214- return relPath
215- }
216- // Path is relative to sandbox root, make it absolute for WASI access
217- return "/" + relPath
218- }
207+ log .Printf ("DEBUG: Processing operation %d: %s" , i , opType )
219208
220- // Build arguments based on operation type
221209 switch opType {
222210 case "copy_file" :
223- resolvedArgs = append (resolvedArgs , "copy_file" )
224- if src , ok := opMap ["src_path" ].(string ); ok {
225- absPath := toAbsPath (src )
226- resolvedArgs = append (resolvedArgs , "--src" , absPath )
211+ srcPath := opMap ["src_path" ].(string )
212+ destPath := filepath .Join (workspaceFullPath , opMap ["dest_path" ].(string ))
213+ // Ensure parent directory exists
214+ os .MkdirAll (filepath .Dir (destPath ), 0755 )
215+ // Copy file
216+ data , err := ioutil .ReadFile (srcPath )
217+ if err != nil {
218+ log .Printf ("ERROR: Failed to read source file %s: %v" , srcPath , err )
219+ os .Exit (1 )
227220 }
228- if dest , ok := opMap ["dest_path" ].(string ); ok {
229- absDest := toAbsPath (filepath .Join (workspaceDir , dest ))
230- resolvedArgs = append (resolvedArgs , "--dest" , absDest )
231- }
232-
233- case "copy_directory_contents" :
234- resolvedArgs = append (resolvedArgs , "copy_directory" )
235- if src , ok := opMap ["src_path" ].(string ); ok {
236- absPath := toAbsPath (src )
237- resolvedArgs = append (resolvedArgs , "--src" , absPath )
238- }
239- if dest , ok := opMap ["dest_path" ].(string ); ok {
240- absDest := toAbsPath (filepath .Join (workspaceDir , dest ))
241- resolvedArgs = append (resolvedArgs , "--dest" , absDest )
221+ if err := ioutil .WriteFile (destPath , data , 0644 ); err != nil {
222+ log .Printf ("ERROR: Failed to write destination file %s: %v" , destPath , err )
223+ os .Exit (1 )
242224 }
225+ log .Printf ("DEBUG: Copied %s to %s" , srcPath , destPath )
243226
244227 case "mkdir" :
245- resolvedArgs = append ( resolvedArgs , "create_directory" )
246- if path , ok := opMap [ "path" ].( string ); ok {
247- absPath := toAbsPath ( filepath . Join ( workspaceDir , path ) )
248- resolvedArgs = append ( resolvedArgs , "--path" , absPath )
228+ dirPath := filepath . Join ( workspaceFullPath , opMap [ "path" ].( string ) )
229+ if err := os . MkdirAll ( dirPath , 0755 ); err != nil {
230+ log . Printf ( "ERROR: Failed to create directory %s: %v" , dirPath , err )
231+ os . Exit ( 1 )
249232 }
233+ log .Printf ("DEBUG: Created directory %s" , dirPath )
234+
235+ case "copy_directory_contents" :
236+ srcDir := opMap ["src_path" ].(string )
237+ destDir := filepath .Join (workspaceFullPath , opMap ["dest_path" ].(string ))
238+ os .MkdirAll (destDir , 0755 )
239+
240+ // Recursively copy all files/directories from source
241+ filepath .Walk (srcDir , func (srcPath string , info os.FileInfo , err error ) error {
242+ if err != nil {
243+ return err
244+ }
245+
246+ // Get relative path from source directory
247+ relPath , _ := filepath .Rel (srcDir , srcPath )
248+ destPath := filepath .Join (destDir , relPath )
249+
250+ if info .IsDir () {
251+ // Create directory
252+ return os .MkdirAll (destPath , 0755 )
253+ } else {
254+ // Copy file
255+ os .MkdirAll (filepath .Dir (destPath ), 0755 )
256+ data , err := ioutil .ReadFile (srcPath )
257+ if err != nil {
258+ return err
259+ }
260+ return ioutil .WriteFile (destPath , data , 0644 )
261+ }
262+ })
263+ log .Printf ("DEBUG: Copied directory contents from %s to %s" , srcDir , destDir )
264+
265+ default :
266+ log .Printf ("WARNING: Unknown operation type: %s" , opType )
250267 }
251268 }
252269
253- _ = cwd // suppress unused warning
254- return resolvedArgs , dirs , nil
270+ log .Printf ("DEBUG: All file operations completed successfully" )
255271}
256272
273+
257274// uniqueStrings returns unique strings from a slice
258275func uniqueStrings (strs []string ) []string {
259276 seen := make (map [string ]bool )
0 commit comments