github.com/jonsyu1/godel@v0.0.0-20171017211503-64567a0cf169/apps/distgo/pkg/imports/imports.go (about)

     1  // Copyright 2016 Palantir Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package imports
    16  
    17  import (
    18  	"go/build"
    19  	"os"
    20  	"path"
    21  	"path/filepath"
    22  	"strings"
    23  
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  // GoFiles is a map from package paths to the names of the buildable .go source files (.go files excluding Cgo and test
    28  // files) in the package.
    29  type GoFiles map[string][]string
    30  
    31  // NewerThan returns true if the modification time of any of the GoFiles is newer than that of the provided file.
    32  func (g GoFiles) NewerThan(fi os.FileInfo) (bool, error) {
    33  	for pkg, files := range g {
    34  		for _, goFile := range files {
    35  			currPath := path.Join(pkg, goFile)
    36  			currFi, err := os.Stat(currPath)
    37  			if err != nil {
    38  				return false, errors.Wrapf(err, "Failed to stat file %v", currPath)
    39  			}
    40  			if currFi.ModTime().After(fi.ModTime()) {
    41  				return true, nil
    42  			}
    43  		}
    44  	}
    45  	return false, nil
    46  }
    47  
    48  // AllFiles returns a map that contains all of the non-standard library Go files that are imported (and thus required to
    49  // build) the specified package (including the package itself). The keys in the returned map are the paths to the
    50  // packages and the values are a slice of the names of the .go source files in the package (excluding Cgo and test
    51  // files).
    52  func AllFiles(pkgPath string) (GoFiles, error) {
    53  	// package name to all non-test Go files in the package
    54  	pkgFiles := make(map[string][]string)
    55  
    56  	absPkgPath, err := filepath.Abs(pkgPath)
    57  	if err != nil {
    58  		return nil, errors.Wrapf(err, "Failed to convert %v to absolute path", pkgPath)
    59  	}
    60  
    61  	pkgsToProcess := []string{
    62  		absPkgPath,
    63  	}
    64  
    65  	for len(pkgsToProcess) > 0 {
    66  		currPkg := pkgsToProcess[0]
    67  		pkgsToProcess = pkgsToProcess[1:]
    68  		if _, ok := pkgFiles[currPkg]; ok {
    69  			continue
    70  		}
    71  
    72  		// parse current package
    73  		pkg, err := build.Import(".", currPkg, build.ImportComment)
    74  		if err != nil {
    75  			return nil, errors.Wrapf(err, "Failed to import package %v", currPkg)
    76  		}
    77  
    78  		// add all files for the current package to output
    79  		pkgFiles[currPkg] = pkg.GoFiles
    80  
    81  		// convert all non-built-in imports into packages and add to packages to process
    82  		for importPath := range pkg.ImportPos {
    83  			if !strings.Contains(importPath, ".") {
    84  				// if import is a standard package, skip
    85  				continue
    86  			}
    87  			importPkg, err := build.Import(importPath, currPkg, build.ImportComment)
    88  			if err != nil {
    89  				return nil, errors.Wrapf(err, "Failed to import package %v using srcDir %v", importPath, currPkg)
    90  			}
    91  			pkgsToProcess = append(pkgsToProcess, importPkg.Dir)
    92  		}
    93  	}
    94  	return GoFiles(pkgFiles), nil
    95  }