github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/go/clean.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "strings" 13 ) 14 15 var cmdClean = &Command{ 16 UsageLine: "clean [-i] [-r] [-n] [-x] [packages]", 17 Short: "remove object files", 18 Long: ` 19 Clean removes object files from package source directories. 20 The go command builds most objects in a temporary directory, 21 so go clean is mainly concerned with object files left by other 22 tools or by manual invocations of go build. 23 24 Specifically, clean removes the following files from each of the 25 source directories corresponding to the import paths: 26 27 _obj/ old object directory, left from Makefiles 28 _test/ old test directory, left from Makefiles 29 _testmain.go old gotest file, left from Makefiles 30 test.out old test log, left from Makefiles 31 build.out old test log, left from Makefiles 32 *.[568ao] object files, left from Makefiles 33 34 DIR(.exe) from go build 35 DIR.test(.exe) from go test -c 36 MAINFILE(.exe) from go build MAINFILE.go 37 *.so from SWIG 38 39 In the list, DIR represents the final path element of the 40 directory, and MAINFILE is the base name of any Go source 41 file in the directory that is not included when building 42 the package. 43 44 The -i flag causes clean to remove the corresponding installed 45 archive or binary (what 'go install' would create). 46 47 The -n flag causes clean to print the remove commands it would execute, 48 but not run them. 49 50 The -r flag causes clean to be applied recursively to all the 51 dependencies of the packages named by the import paths. 52 53 The -x flag causes clean to print remove commands as it executes them. 54 55 For more about specifying packages, see 'go help packages'. 56 `, 57 } 58 59 var cleanI bool // clean -i flag 60 var cleanN bool // clean -n flag 61 var cleanR bool // clean -r flag 62 var cleanX bool // clean -x flag 63 64 func init() { 65 // break init cycle 66 cmdClean.Run = runClean 67 68 cmdClean.Flag.BoolVar(&cleanI, "i", false, "") 69 cmdClean.Flag.BoolVar(&cleanN, "n", false, "") 70 cmdClean.Flag.BoolVar(&cleanR, "r", false, "") 71 cmdClean.Flag.BoolVar(&cleanX, "x", false, "") 72 } 73 74 func runClean(cmd *Command, args []string) { 75 for _, pkg := range packagesAndErrors(args) { 76 clean(pkg) 77 } 78 } 79 80 var cleaned = map[*Package]bool{} 81 82 // TODO: These are dregs left by Makefile-based builds. 83 // Eventually, can stop deleting these. 84 var cleanDir = map[string]bool{ 85 "_test": true, 86 "_obj": true, 87 } 88 89 var cleanFile = map[string]bool{ 90 "_testmain.go": true, 91 "test.out": true, 92 "build.out": true, 93 "a.out": true, 94 } 95 96 var cleanExt = map[string]bool{ 97 ".5": true, 98 ".6": true, 99 ".8": true, 100 ".a": true, 101 ".o": true, 102 ".so": true, 103 } 104 105 func clean(p *Package) { 106 if cleaned[p] { 107 return 108 } 109 cleaned[p] = true 110 111 if p.Dir == "" { 112 errorf("can't load package: %v", p.Error) 113 return 114 } 115 dirs, err := ioutil.ReadDir(p.Dir) 116 if err != nil { 117 errorf("go clean %s: %v", p.Dir, err) 118 return 119 } 120 121 var b builder 122 b.print = fmt.Print 123 124 packageFile := map[string]bool{} 125 if p.Name != "main" { 126 // Record which files are not in package main. 127 // The others are. 128 keep := func(list []string) { 129 for _, f := range list { 130 packageFile[f] = true 131 } 132 } 133 keep(p.GoFiles) 134 keep(p.CgoFiles) 135 keep(p.TestGoFiles) 136 keep(p.XTestGoFiles) 137 } 138 139 _, elem := filepath.Split(p.Dir) 140 var allRemove []string 141 142 // Remove dir-named executable only if this is package main. 143 if p.Name == "main" { 144 allRemove = append(allRemove, 145 elem, 146 elem+".exe", 147 ) 148 } 149 150 // Remove package test executables. 151 allRemove = append(allRemove, 152 elem+".test", 153 elem+".test.exe", 154 ) 155 156 // Remove a potental executable for each .go file in the directory that 157 // is not part of the directory's package. 158 for _, dir := range dirs { 159 name := dir.Name() 160 if packageFile[name] { 161 continue 162 } 163 if !dir.IsDir() && strings.HasSuffix(name, ".go") { 164 // TODO(adg,rsc): check that this .go file is actually 165 // in "package main", and therefore capable of building 166 // to an executable file. 167 base := name[:len(name)-len(".go")] 168 allRemove = append(allRemove, base, base+".exe") 169 } 170 } 171 172 if cleanN || cleanX { 173 b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " ")) 174 } 175 176 toRemove := map[string]bool{} 177 for _, name := range allRemove { 178 toRemove[name] = true 179 } 180 for _, dir := range dirs { 181 name := dir.Name() 182 if dir.IsDir() { 183 // TODO: Remove once Makefiles are forgotten. 184 if cleanDir[name] { 185 if cleanN || cleanX { 186 b.showcmd(p.Dir, "rm -r %s", name) 187 if cleanN { 188 continue 189 } 190 } 191 if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil { 192 errorf("go clean: %v", err) 193 } 194 } 195 continue 196 } 197 198 if cleanN { 199 continue 200 } 201 202 if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] { 203 removeFile(filepath.Join(p.Dir, name)) 204 } 205 } 206 207 if cleanI && p.target != "" { 208 if cleanN || cleanX { 209 b.showcmd("", "rm -f %s", p.target) 210 } 211 if !cleanN { 212 removeFile(p.target) 213 } 214 } 215 216 if cleanI && p.usesSwig() { 217 for _, f := range stringList(p.SwigFiles, p.SwigCXXFiles) { 218 dir := p.swigDir(&buildContext) 219 soname := p.swigSoname(f) 220 target := filepath.Join(dir, soname) 221 if cleanN || cleanX { 222 b.showcmd("", "rm -f %s", target) 223 } 224 if !cleanN { 225 removeFile(target) 226 } 227 } 228 } 229 230 if cleanR { 231 for _, p1 := range p.imports { 232 clean(p1) 233 } 234 } 235 } 236 237 // removeFile tries to remove file f, if error other than file doesn't exist 238 // occurs, it will report the error. 239 func removeFile(f string) { 240 err := os.Remove(f) 241 if err == nil || os.IsNotExist(err) { 242 return 243 } 244 // Windows does not allow deletion of a binary file while it is executing. 245 if toolIsWindows { 246 // Remove lingering ~ file from last attempt. 247 if _, err2 := os.Stat(f + "~"); err2 == nil { 248 os.Remove(f + "~") 249 } 250 // Try to move it out of the way. If the move fails, 251 // which is likely, we'll try again the 252 // next time we do an install of this binary. 253 if err2 := os.Rename(f, f+"~"); err2 == nil { 254 os.Remove(f + "~") 255 return 256 } 257 } 258 errorf("go clean: %v", err) 259 }