github.com/bazelbuild/bazel-watcher@v0.25.2/internal/ibazel/workspace/workspace.go (about) 1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package workspace 16 17 import ( 18 "context" 19 "errors" 20 "os" 21 "os/exec" 22 "path/filepath" 23 "strings" 24 25 "github.com/bazelbuild/bazel-watcher/internal/ibazel/log" 26 ) 27 28 type Workspace interface { 29 FindWorkspace() (string, error) 30 ExecuteCommand(command string, args []string) 31 } 32 33 type MainWorkspace struct{} 34 35 func (m *MainWorkspace) FindWorkspace() (string, error) { 36 path, err := os.Getwd() 37 if err != nil { 38 return "", err 39 } 40 41 volume := filepath.VolumeName(path) 42 43 for { 44 // filepath.Dir() includes a trailing separator if we're at the root 45 if path == volume+string(filepath.Separator) { 46 path = volume 47 } 48 49 // Check if we're at the workspace path 50 if s, err := os.Stat(filepath.Join(path, "WORKSPACE")); err == nil { 51 if !s.IsDir() && s.Name() == "WORKSPACE" { 52 // In macOS directories called "workspace" will match because the file 53 // system isn't case sensitive. 54 return path, nil 55 } 56 } 57 58 if _, err := os.Stat(filepath.Join(path, "WORKSPACE.bazel")); err == nil { 59 return path, nil 60 } 61 62 // If we've reached the root, then we know the cwd isn't within a workspace 63 if path == volume { 64 return "", errors.New("ibazel was not invoked from within a workspace\n") 65 } 66 67 // Move one level up the path 68 path = filepath.Dir(path) 69 } 70 } 71 72 func (m *MainWorkspace) ExecuteCommand(command string, args []string) { 73 for i, arg := range args { 74 args[i] = strings.TrimSpace(arg) 75 } 76 log.Logf("Executing command: %s", command) 77 workspacePath, err := m.FindWorkspace() 78 if err != nil { 79 log.Fatalf("Error finding workspace: %v", err) 80 os.Exit(5) 81 } 82 log.Logf("Workspace path: %s", workspacePath) 83 84 ctx, cancel := context.WithCancel(context.Background()) 85 defer cancel() 86 cmd := exec.CommandContext(ctx, command, args...) 87 log.Logf("Executing command: `%s`", strings.Join(cmd.Args, " ")) 88 cmd.Stdout = os.Stdout 89 cmd.Stderr = os.Stderr 90 cmd.Dir = workspacePath 91 92 err = cmd.Run() 93 if err != nil { 94 log.Errorf("Command failed: %s %s. Error: %s", command, args, err) 95 } 96 } 97 98 type FakeWorkspace struct{} 99 100 func (f *FakeWorkspace) FindWorkspace() (string, error) { 101 return "", nil 102 } 103 104 func (f *FakeWorkspace) ExecuteCommand(command string, args []string) {}