github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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  	allRemove := []string{
   141  		elem,
   142  		elem + ".exe",
   143  		elem + ".test",
   144  		elem + ".test.exe",
   145  	}
   146  	for _, dir := range dirs {
   147  		name := dir.Name()
   148  		if packageFile[name] {
   149  			continue
   150  		}
   151  		if !dir.IsDir() && strings.HasSuffix(name, ".go") {
   152  			base := name[:len(name)-len(".go")]
   153  			allRemove = append(allRemove, base, base+".exe")
   154  		}
   155  	}
   156  	if cleanN || cleanX {
   157  		b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
   158  	}
   159  
   160  	toRemove := map[string]bool{}
   161  	for _, name := range allRemove {
   162  		toRemove[name] = true
   163  	}
   164  	for _, dir := range dirs {
   165  		name := dir.Name()
   166  		if dir.IsDir() {
   167  			// TODO: Remove once Makefiles are forgotten.
   168  			if cleanDir[name] {
   169  				if cleanN || cleanX {
   170  					b.showcmd(p.Dir, "rm -r %s", name)
   171  					if cleanN {
   172  						continue
   173  					}
   174  				}
   175  				if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
   176  					errorf("go clean: %v", err)
   177  				}
   178  			}
   179  			continue
   180  		}
   181  
   182  		if cleanN {
   183  			continue
   184  		}
   185  
   186  		if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
   187  			removeFile(filepath.Join(p.Dir, name))
   188  		}
   189  	}
   190  
   191  	if cleanI && p.target != "" {
   192  		if cleanN || cleanX {
   193  			b.showcmd("", "rm -f %s", p.target)
   194  		}
   195  		if !cleanN {
   196  			removeFile(p.target)
   197  		}
   198  	}
   199  
   200  	if cleanI && p.usesSwig() {
   201  		for _, f := range stringList(p.SwigFiles, p.SwigCXXFiles) {
   202  			dir := p.swigDir(&buildContext)
   203  			soname := p.swigSoname(f)
   204  			target := filepath.Join(dir, soname)
   205  			if cleanN || cleanX {
   206  				b.showcmd("", "rm -f %s", target)
   207  			}
   208  			if !cleanN {
   209  				removeFile(target)
   210  			}
   211  		}
   212  	}
   213  
   214  	if cleanR {
   215  		for _, p1 := range p.imports {
   216  			clean(p1)
   217  		}
   218  	}
   219  }
   220  
   221  // removeFile tries to remove file f, if error other than file doesn't exist
   222  // occurs, it will report the error.
   223  func removeFile(f string) {
   224  	if err := os.Remove(f); err != nil && !os.IsNotExist(err) {
   225  		errorf("go clean: %v", err)
   226  	}
   227  }