github.com/nak3/source-to-image@v1.1.10-0.20180319140719-2ed55639898d/pkg/ignore/ignore.go (about)

     1  package ignore
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/openshift/source-to-image/pkg/api"
    11  	utilglog "github.com/openshift/source-to-image/pkg/util/glog"
    12  )
    13  
    14  var glog = utilglog.StderrLog
    15  
    16  // DockerIgnorer ignores files based on the contents of the .s2iignore file
    17  type DockerIgnorer struct{}
    18  
    19  // Ignore removes files from the workspace based on the contents of the
    20  // .s2iignore file
    21  func (b *DockerIgnorer) Ignore(config *api.Config) error {
    22  	/*
    23  		 so, to duplicate the .dockerignore capabilities (https://docs.docker.com/reference/builder/#dockerignore-file)
    24  		 we have a flow that follows:
    25  		0) First note, .dockerignore rules are NOT recursive (unlike .gitignore) .. you have to list subdir explicitly
    26  		1) Read in the exclusion patterns
    27  		2) Skip over comments (noted by #)
    28  		3) note overrides (via exclamation sign i.e. !) and reinstate files (don't remove) as needed
    29  		4) leverage Glob matching to build list, as .dockerignore is documented as following filepath.Match / filepath.Glob
    30  		5) del files
    31  		 1 to 4 is in getListOfFilesToIgnore
    32  	*/
    33  	filesToDel, lerr := getListOfFilesToIgnore(config.WorkingSourceDir)
    34  	if lerr != nil {
    35  		return lerr
    36  	}
    37  
    38  	if filesToDel == nil {
    39  		return nil
    40  	}
    41  
    42  	// delete compiled list of files
    43  	for _, fileToDel := range filesToDel {
    44  		glog.V(5).Infof("attempting to remove file %s \n", fileToDel)
    45  		rerr := os.RemoveAll(fileToDel)
    46  		if rerr != nil {
    47  			glog.Errorf("error removing file %s because of %v \n", fileToDel, rerr)
    48  			return rerr
    49  		}
    50  	}
    51  
    52  	return nil
    53  }
    54  
    55  func getListOfFilesToIgnore(workingDir string) (map[string]string, error) {
    56  	path := filepath.Join(workingDir, api.IgnoreFile)
    57  	file, err := os.Open(path)
    58  	if err != nil {
    59  		if !os.IsNotExist(err) {
    60  			glog.Errorf("Ignore processing, problem opening %s because of %v\n", path, err)
    61  			return nil, err
    62  		}
    63  		glog.V(4).Info(".s2iignore file does not exist")
    64  		return nil, nil
    65  	}
    66  	defer file.Close()
    67  
    68  	filesToDel := make(map[string]string)
    69  	scanner := bufio.NewScanner(file)
    70  	for scanner.Scan() {
    71  		filespec := strings.Trim(scanner.Text(), " ")
    72  
    73  		if len(filespec) == 0 {
    74  			continue
    75  		}
    76  
    77  		if strings.HasPrefix(filespec, "#") {
    78  			continue
    79  		}
    80  
    81  		glog.V(4).Infof(".s2iignore lists a file spec of %s \n", filespec)
    82  
    83  		if strings.HasPrefix(filespec, "!") {
    84  			//remove any existing files to del that the override covers
    85  			// and patterns later on that undo this take precedence
    86  
    87  			// first, remove ! ... note, replace ! with */ did not have
    88  			// expected effect with filepath.Match
    89  			filespec = strings.Replace(filespec, "!", "", 1)
    90  
    91  			// iterate through and determine ones to leave in
    92  			dontDel := []string{}
    93  			for candidate := range filesToDel {
    94  				compare := filepath.Join(workingDir, filespec)
    95  				glog.V(5).Infof("For %s  and %s see if it matches the spec  %s which means that we leave in\n", filespec, candidate, compare)
    96  				leaveIn, _ := filepath.Match(compare, candidate)
    97  				if leaveIn {
    98  					glog.V(5).Infof("Not removing %s \n", candidate)
    99  					dontDel = append(dontDel, candidate)
   100  				} else {
   101  					glog.V(5).Infof("No match for %s and %s \n", filespec, candidate)
   102  				}
   103  			}
   104  
   105  			// now remove any matches from files to delete list
   106  			for _, leaveIn := range dontDel {
   107  				delete(filesToDel, leaveIn)
   108  			}
   109  			continue
   110  		}
   111  
   112  		globspec := filepath.Join(workingDir, filespec)
   113  		glog.V(4).Infof("using globspec %s \n", globspec)
   114  		list, gerr := filepath.Glob(globspec)
   115  		if gerr != nil {
   116  			glog.V(4).Infof("Glob failed with %v \n", gerr)
   117  		} else {
   118  			for _, globresult := range list {
   119  				glog.V(5).Infof("Glob result %s \n", globresult)
   120  				filesToDel[globresult] = globresult
   121  
   122  			}
   123  		}
   124  
   125  	}
   126  
   127  	if err := scanner.Err(); err != nil && err != io.EOF {
   128  		glog.Errorf("Problem processing .s2iignore %v \n", err)
   129  		return nil, err
   130  	}
   131  
   132  	return filesToDel, nil
   133  }