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  }