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.
5 // Package clean implements the ``go clean'' command.
17 "cmd/go/internal/base"
18 "cmd/go/internal/cache"
20 "cmd/go/internal/load"
21 "cmd/go/internal/lockedfile"
22 "cmd/go/internal/modfetch"
23 "cmd/go/internal/modload"
24 "cmd/go/internal/work"
27 var CmdClean = &base.Command{
28 UsageLine: "go clean [clean flags] [build flags] [packages]",
29 Short: "remove object files and cached files",
31 Clean removes object files from package source directories.
32 The go command builds most objects in a temporary directory,
33 so go clean is mainly concerned with object files left by other
34 tools or by manual invocations of go build.
36 If a package argument is given or the -i or -r flag is set,
37 clean removes the following files from each of the
38 source directories corresponding to the import paths:
40 _obj/ old object directory, left from Makefiles
41 _test/ old test directory, left from Makefiles
42 _testmain.go old gotest file, left from Makefiles
43 test.out old test log, left from Makefiles
44 build.out old test log, left from Makefiles
45 *.[568ao] object files, left from Makefiles
47 DIR(.exe) from go build
48 DIR.test(.exe) from go test -c
49 MAINFILE(.exe) from go build MAINFILE.go
52 In the list, DIR represents the final path element of the
53 directory, and MAINFILE is the base name of any Go source
54 file in the directory that is not included when building
57 The -i flag causes clean to remove the corresponding installed
58 archive or binary (what 'go install' would create).
60 The -n flag causes clean to print the remove commands it would execute,
63 The -r flag causes clean to be applied recursively to all the
64 dependencies of the packages named by the import paths.
66 The -x flag causes clean to print remove commands as it executes them.
68 The -cache flag causes clean to remove the entire go build cache.
70 The -testcache flag causes clean to expire all test results in the
73 The -modcache flag causes clean to remove the entire module
74 download cache, including unpacked source code of versioned
77 For more about build flags, see 'go help build'.
79 For more about specifying packages, see 'go help packages'.
84 cleanI bool // clean -i flag
85 cleanR bool // clean -r flag
86 cleanCache bool // clean -cache flag
87 cleanModcache bool // clean -modcache flag
88 cleanTestcache bool // clean -testcache flag
93 CmdClean.Run = runClean
95 CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
96 CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
97 CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "")
98 CmdClean.Flag.BoolVar(&cleanModcache, "modcache", false, "")
99 CmdClean.Flag.BoolVar(&cleanTestcache, "testcache", false, "")
101 // -n and -x are important enough to be
102 // mentioned explicitly in the docs but they
103 // are part of the build flags.
105 work.AddBuildFlags(CmdClean, work.DefaultBuildFlags)
108 func runClean(cmd *base.Command, args []string) {
109 // golang.org/issue/29925: only load packages before cleaning if
110 // either the flags and arguments explicitly imply a package,
111 // or no other target (such as a cache) was requested to be cleaned.
112 cleanPkg := len(args) > 0 || cleanI || cleanR
113 if (!modload.Enabled() || modload.HasModRoot()) &&
114 !cleanCache && !cleanModcache && !cleanTestcache {
119 for _, pkg := range load.PackagesAndErrors(args) {
128 dir := cache.DefaultDir()
130 // Remove the cache subdirectories but not the top cache directory.
131 // The top cache directory may have been created with special permissions
132 // and not something that we want to remove. Also, we'd like to preserve
133 // the access log for future analysis, even if the cache is cleared.
134 subdirs, _ := filepath.Glob(filepath.Join(dir, "[0-9a-f][0-9a-f]"))
135 printedErrors := false
136 if len(subdirs) > 0 {
137 if cfg.BuildN || cfg.BuildX {
138 b.Showcmd("", "rm -r %s", strings.Join(subdirs, " "))
140 for _, d := range subdirs {
141 // Only print the first error - there may be many.
142 // This also mimics what os.RemoveAll(dir) would do.
143 if err := os.RemoveAll(d); err != nil && !printedErrors {
145 base.Errorf("go clean -cache: %v", err)
150 logFile := filepath.Join(dir, "log.txt")
151 if err := os.RemoveAll(logFile); err != nil && !printedErrors {
153 base.Errorf("go clean -cache: %v", err)
158 if cleanTestcache && !cleanCache {
159 // Instead of walking through the entire cache looking for test results,
160 // we write a file to the cache indicating that all test results from before
161 // right now are to be ignored.
162 dir := cache.DefaultDir()
164 f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt"))
166 now := time.Now().UnixNano()
167 buf, _ := ioutil.ReadAll(f)
168 prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64)
170 if err = f.Truncate(0); err == nil {
171 if _, err = f.Seek(0, 0); err == nil {
172 _, err = fmt.Fprintf(f, "%d\n", now)
176 if closeErr := f.Close(); err == nil {
181 base.Errorf("go clean -testcache: %v", err)
187 if modfetch.PkgMod == "" {
188 base.Fatalf("go clean -modcache: no module cache")
190 if cfg.BuildN || cfg.BuildX {
191 b.Showcmd("", "rm -rf %s", modfetch.PkgMod)
194 if err := modfetch.RemoveAll(modfetch.PkgMod); err != nil {
195 base.Errorf("go clean -modcache: %v", err)
201 var cleaned = map[*load.Package]bool{}
203 // TODO: These are dregs left by Makefile-based builds.
204 // Eventually, can stop deleting these.
205 var cleanDir = map[string]bool{
210 var cleanFile = map[string]bool{
211 "_testmain.go": true,
217 var cleanExt = map[string]bool{
226 func clean(p *load.Package) {
233 base.Errorf("can't load package: %v", p.Error)
236 dirs, err := ioutil.ReadDir(p.Dir)
238 base.Errorf("go clean %s: %v", p.Dir, err)
245 packageFile := map[string]bool{}
246 if p.Name != "main" {
247 // Record which files are not in package main.
249 keep := func(list []string) {
250 for _, f := range list {
251 packageFile[f] = true
260 _, elem := filepath.Split(p.Dir)
261 var allRemove []string
263 // Remove dir-named executable only if this is package main.
264 if p.Name == "main" {
265 allRemove = append(allRemove,
271 // Remove package test executables.
272 allRemove = append(allRemove,
277 // Remove a potential executable for each .go file in the directory that
278 // is not part of the directory's package.
279 for _, dir := range dirs {
281 if packageFile[name] {
284 if !dir.IsDir() && strings.HasSuffix(name, ".go") {
285 // TODO(adg,rsc): check that this .go file is actually
286 // in "package main", and therefore capable of building
287 // to an executable file.
288 base := name[:len(name)-len(".go")]
289 allRemove = append(allRemove, base, base+".exe")
293 if cfg.BuildN || cfg.BuildX {
294 b.Showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
297 toRemove := map[string]bool{}
298 for _, name := range allRemove {
299 toRemove[name] = true
301 for _, dir := range dirs {
304 // TODO: Remove once Makefiles are forgotten.
306 if cfg.BuildN || cfg.BuildX {
307 b.Showcmd(p.Dir, "rm -r %s", name)
312 if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
313 base.Errorf("go clean: %v", err)
323 if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
324 removeFile(filepath.Join(p.Dir, name))
328 if cleanI && p.Target != "" {
329 if cfg.BuildN || cfg.BuildX {
330 b.Showcmd("", "rm -f %s", p.Target)
338 for _, p1 := range p.Internal.Imports {
344 // removeFile tries to remove file f, if error other than file doesn't exist
345 // occurs, it will report the error.
346 func removeFile(f string) {
348 if err == nil || os.IsNotExist(err) {
351 // Windows does not allow deletion of a binary file while it is executing.
352 if base.ToolIsWindows {
353 // Remove lingering ~ file from last attempt.
354 if _, err2 := os.Stat(f + "~"); err2 == nil {
357 // Try to move it out of the way. If the move fails,
358 // which is likely, we'll try again the
359 // next time we do an install of this binary.
360 if err2 := os.Rename(f, f+"~"); err2 == nil {
365 base.Errorf("go clean: %v", err)