github.com/nilium/gitlab-runner@v12.5.0+incompatible/commands/helpers/file_archiver.go (about)

     1  package helpers
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"sort"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  type fileArchiver struct {
    20  	Paths     []string `long:"path" description:"Add paths to archive"`
    21  	Untracked bool     `long:"untracked" description:"Add git untracked files"`
    22  	Verbose   bool     `long:"verbose" description:"Detailed information"`
    23  
    24  	wd    string
    25  	files map[string]os.FileInfo
    26  }
    27  
    28  func (c *fileArchiver) isChanged(modTime time.Time) bool {
    29  	for _, info := range c.files {
    30  		if modTime.Before(info.ModTime()) {
    31  			return true
    32  		}
    33  	}
    34  	return false
    35  }
    36  
    37  func (c *fileArchiver) isFileChanged(fileName string) bool {
    38  	ai, err := os.Stat(fileName)
    39  	if ai != nil {
    40  		if !c.isChanged(ai.ModTime()) {
    41  			return false
    42  		}
    43  	} else if !os.IsNotExist(err) {
    44  		logrus.Warningln(err)
    45  	}
    46  	return true
    47  }
    48  
    49  func (c *fileArchiver) sortedFiles() []string {
    50  	files := make([]string, len(c.files))
    51  
    52  	i := 0
    53  	for file := range c.files {
    54  		files[i] = file
    55  		i++
    56  	}
    57  
    58  	sort.Strings(files)
    59  	return files
    60  }
    61  
    62  func (c *fileArchiver) add(path string) (err error) {
    63  	// Always use slashes
    64  	path = filepath.ToSlash(path)
    65  
    66  	// Check if file exist
    67  	info, err := os.Lstat(path)
    68  	if err == nil {
    69  		c.files[path] = info
    70  	}
    71  	return
    72  }
    73  
    74  func (c *fileArchiver) process(match string) bool {
    75  	var absolute, relative string
    76  	var err error
    77  
    78  	absolute, err = filepath.Abs(match)
    79  	if err == nil {
    80  		// Let's try to find a real relative path to an absolute from working directory
    81  		relative, err = filepath.Rel(c.wd, absolute)
    82  	}
    83  	if err == nil {
    84  		// Process path only if it lives in our build directory
    85  		if !strings.HasPrefix(relative, ".."+string(filepath.Separator)) {
    86  			err = c.add(relative)
    87  		} else {
    88  			err = errors.New("not supported: outside build directory")
    89  		}
    90  	}
    91  	if err == nil {
    92  		return true
    93  	} else if os.IsNotExist(err) {
    94  		// We hide the error that file doesn't exist
    95  		return false
    96  	}
    97  
    98  	logrus.Warningf("%s: %v", match, err)
    99  	return false
   100  }
   101  
   102  func (c *fileArchiver) processPaths() {
   103  	for _, path := range c.Paths {
   104  		matches, err := filepath.Glob(path)
   105  		if err != nil {
   106  			logrus.Warningf("%s: %v", path, err)
   107  			continue
   108  		}
   109  
   110  		found := 0
   111  
   112  		for _, match := range matches {
   113  			err := filepath.Walk(match, func(path string, info os.FileInfo, err error) error {
   114  				if c.process(path) {
   115  					found++
   116  				}
   117  				return nil
   118  			})
   119  			if err != nil {
   120  				logrus.Warningln("Walking", match, err)
   121  			}
   122  		}
   123  
   124  		if found == 0 {
   125  			logrus.Warningf("%s: no matching files", path)
   126  		} else {
   127  			logrus.Infof("%s: found %d matching files", path, found)
   128  		}
   129  	}
   130  }
   131  
   132  func (c *fileArchiver) processUntracked() {
   133  	if !c.Untracked {
   134  		return
   135  	}
   136  
   137  	found := 0
   138  
   139  	var output bytes.Buffer
   140  	cmd := exec.Command("git", "ls-files", "-o", "-z")
   141  	cmd.Env = os.Environ()
   142  	cmd.Stdout = &output
   143  	cmd.Stderr = os.Stderr
   144  	logrus.Debugln("Executing command:", strings.Join(cmd.Args, " "))
   145  	err := cmd.Run()
   146  	if err == nil {
   147  		reader := bufio.NewReader(&output)
   148  		for {
   149  			line, err := reader.ReadString(0)
   150  			if err == io.EOF {
   151  				break
   152  			} else if err != nil {
   153  				logrus.Warningln(err)
   154  				break
   155  			}
   156  			if c.process(line[:len(line)-1]) {
   157  				found++
   158  			}
   159  		}
   160  
   161  		if found == 0 {
   162  			logrus.Warningf("untracked: no files")
   163  		} else {
   164  			logrus.Infof("untracked: found %d files", found)
   165  		}
   166  	} else {
   167  		logrus.Warningf("untracked: %v", err)
   168  	}
   169  }
   170  
   171  func (c *fileArchiver) enumerate() error {
   172  	wd, err := os.Getwd()
   173  	if err != nil {
   174  		return fmt.Errorf("Failed to get current working directory: %v", err)
   175  	}
   176  
   177  	c.wd = wd
   178  	c.files = make(map[string]os.FileInfo)
   179  
   180  	c.processPaths()
   181  	c.processUntracked()
   182  	return nil
   183  }