github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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] [build flags] [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 build flags, see 'go help build'. 56 57 For more about specifying packages, see 'go help packages'. 58 `, 59 } 60 61 var cleanI bool // clean -i flag 62 var cleanR bool // clean -r 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(&cleanR, "r", false, "") 70 // -n and -x are important enough to be 71 // mentioned explicitly in the docs but they 72 // are part of the build flags. 73 74 addBuildFlags(cmdClean) 75 } 76 77 func runClean(cmd *Command, args []string) { 78 for _, pkg := range packagesAndErrors(args) { 79 clean(pkg) 80 } 81 } 82 83 var cleaned = map[*Package]bool{} 84 85 // TODO: These are dregs left by Makefile-based builds. 86 // Eventually, can stop deleting these. 87 var cleanDir = map[string]bool{ 88 "_test": true, 89 "_obj": true, 90 } 91 92 var cleanFile = map[string]bool{ 93 "_testmain.go": true, 94 "test.out": true, 95 "build.out": true, 96 "a.out": true, 97 } 98 99 var cleanExt = map[string]bool{ 100 ".5": true, 101 ".6": true, 102 ".8": true, 103 ".a": true, 104 ".o": true, 105 ".so": true, 106 } 107 108 func clean(p *Package) { 109 if cleaned[p] { 110 return 111 } 112 cleaned[p] = true 113 114 if p.Dir == "" { 115 errorf("can't load package: %v", p.Error) 116 return 117 } 118 dirs, err := ioutil.ReadDir(p.Dir) 119 if err != nil { 120 errorf("go clean %s: %v", p.Dir, err) 121 return 122 } 123 124 var b builder 125 b.print = fmt.Print 126 127 packageFile := map[string]bool{} 128 if p.Name != "main" { 129 // Record which files are not in package main. 130 // The others are. 131 keep := func(list []string) { 132 for _, f := range list { 133 packageFile[f] = true 134 } 135 } 136 keep(p.GoFiles) 137 keep(p.CgoFiles) 138 keep(p.TestGoFiles) 139 keep(p.XTestGoFiles) 140 } 141 142 _, elem := filepath.Split(p.Dir) 143 var allRemove []string 144 145 // Remove dir-named executable only if this is package main. 146 if p.Name == "main" { 147 allRemove = append(allRemove, 148 elem, 149 elem+".exe", 150 ) 151 } 152 153 // Remove package test executables. 154 allRemove = append(allRemove, 155 elem+".test", 156 elem+".test.exe", 157 ) 158 159 // Remove a potential executable for each .go file in the directory that 160 // is not part of the directory's package. 161 for _, dir := range dirs { 162 name := dir.Name() 163 if packageFile[name] { 164 continue 165 } 166 if !dir.IsDir() && strings.HasSuffix(name, ".go") { 167 // TODO(adg,rsc): check that this .go file is actually 168 // in "package main", and therefore capable of building 169 // to an executable file. 170 base := name[:len(name)-len(".go")] 171 allRemove = append(allRemove, base, base+".exe") 172 } 173 } 174 175 if buildN || buildX { 176 b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " ")) 177 } 178 179 toRemove := map[string]bool{} 180 for _, name := range allRemove { 181 toRemove[name] = true 182 } 183 for _, dir := range dirs { 184 name := dir.Name() 185 if dir.IsDir() { 186 // TODO: Remove once Makefiles are forgotten. 187 if cleanDir[name] { 188 if buildN || buildX { 189 b.showcmd(p.Dir, "rm -r %s", name) 190 if buildN { 191 continue 192 } 193 } 194 if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil { 195 errorf("go clean: %v", err) 196 } 197 } 198 continue 199 } 200 201 if buildN { 202 continue 203 } 204 205 if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] { 206 removeFile(filepath.Join(p.Dir, name)) 207 } 208 } 209 210 if cleanI && p.target != "" { 211 if buildN || buildX { 212 b.showcmd("", "rm -f %s", p.target) 213 } 214 if !buildN { 215 removeFile(p.target) 216 } 217 } 218 219 if cleanR { 220 for _, p1 := range p.imports { 221 clean(p1) 222 } 223 } 224 } 225 226 // removeFile tries to remove file f, if error other than file doesn't exist 227 // occurs, it will report the error. 228 func removeFile(f string) { 229 err := os.Remove(f) 230 if err == nil || os.IsNotExist(err) { 231 return 232 } 233 // Windows does not allow deletion of a binary file while it is executing. 234 if toolIsWindows { 235 // Remove lingering ~ file from last attempt. 236 if _, err2 := os.Stat(f + "~"); err2 == nil { 237 os.Remove(f + "~") 238 } 239 // Try to move it out of the way. If the move fails, 240 // which is likely, we'll try again the 241 // next time we do an install of this binary. 242 if err2 := os.Rename(f, f+"~"); err2 == nil { 243 os.Remove(f + "~") 244 return 245 } 246 } 247 errorf("go clean: %v", err) 248 }