Esempio n. 1
0
// followGitSubmodule looks at a .git /file/ and tries to retrieve from inside
// it the gitdir value, which is supposed to indicate the location of the
// corresponding .git /directory/.  Note: the gitdir value should point directly
// to the corresponding .git directory even in the case of nested submodules.
func followGitSubmodule(fs util.FileSystem, gitPath string) (string, error) {
	f, err := os.Open(gitPath)
	if err != nil {
		return "", err
	}
	defer f.Close()

	sc := bufio.NewScanner(f)
	if sc.Scan() {
		s := sc.Text()

		if strings.HasPrefix(s, "gitdir: ") {
			newGitPath := s[8:]

			if !filepath.IsAbs(newGitPath) {
				newGitPath = filepath.Join(filepath.Dir(gitPath), newGitPath)
			}

			fi, err := fs.Stat(newGitPath)
			if err != nil && !os.IsNotExist(err) {
				return "", err
			}
			if os.IsNotExist(err) || !fi.IsDir() {
				return "", fmt.Errorf("gitdir link in .git file %q is invalid", gitPath)
			}
			return newGitPath, nil
		}
	}

	return "", fmt.Errorf("unable to parse .git file %q", gitPath)
}
Esempio n. 2
0
// isValidGitRepository checks to see if there is a git repository in the
// directory and if the repository is valid -- i.e. it has remotes or commits
func isValidGitRepository(fs util.FileSystem, dir string) (bool, error) {
	gitPath := filepath.Join(strings.TrimPrefix(dir, "file://"), ".git")

	fi, err := fs.Stat(gitPath)
	if os.IsNotExist(err) {
		// The directory is not a git repo, no error
		return false, nil
	}
	if err != nil {
		return false, err
	}

	if !fi.IsDir() {
		gitPath, err = followGitSubmodule(fs, gitPath)
		if err != nil {
			return false, err
		}
	}

	// Search the content of the .git directory for content
	directories := [2]string{
		filepath.Join(gitPath, "objects"),
		filepath.Join(gitPath, "refs"),
	}

	// For the directories we search, if the git repo has been used, there will
	// be some file.  We don't just search the base git repository because of the
	// hook samples that are normally generated with `git init`
	isEmpty := true
	for _, dir := range directories {
		err := fs.Walk(dir, func(path string, info os.FileInfo, err error) error {
			// If we find a file, the git directory is "not empty"
			// We're looking for object blobs, and ref files
			if info != nil && !info.IsDir() {
				isEmpty = false
				return filepath.SkipDir
			}

			return err
		})

		if err != nil && err != filepath.SkipDir {
			// There is a .git, but we've encountered an error
			return true, err
		}

		if !isEmpty {
			return true, nil
		}
	}

	// Since we know there's a .git directory, but there is nothing in it, we
	// throw an error
	return true, errors.NewEmptyGitRepositoryError(dir)
}
Esempio n. 3
0
// GuessEntrypoint tries to guess the valid entrypoint from the source code
// repository. The valid entrypoints are defined above (run,start,exec,execute)
func GuessEntrypoint(fs util.FileSystem, sourceDir string) (string, error) {
	files, err := fs.ReadDir(sourceDir)
	if err != nil {
		return "", err
	}
	for _, f := range files {
		if f.IsDir() || !f.Mode().IsRegular() {
			continue
		}
		if isValidEntrypoint(fs, filepath.Join(sourceDir, f.Name())) {
			glog.V(2).Infof("Found valid ENTRYPOINT: %s", f.Name())
			return f.Name(), nil
		}
	}
	return "", errors.New("No valid entrypoint specified")
}
Esempio n. 4
0
// isValidEntrypoint checks if the given file exists and if it is a regular
// file. Valid ENTRYPOINT must be an executable file, so the executable bit must
// be set.
func isValidEntrypoint(fs util.FileSystem, path string) bool {
	stat, err := fs.Stat(path)
	if err != nil {
		return false
	}
	found := false
	for _, pattern := range validEntrypoints {
		if pattern.MatchString(stat.Name()) {
			found = true
			break
		}
	}
	if !found {
		return false
	}
	mode := stat.Mode()
	return mode&0111 != 0
}
Esempio n. 5
0
// ParseFile will see if the input string is a valid file location, where
// file names have a great deal of flexibility and can even match
// expect git clone spec syntax; it also provides details if the file://
// proto was explicitly specified, if we should use OS copy vs. the git
// binary, and if a frag/ref has a bad format
func ParseFile(fs util.FileSystem, source string) (*FileProtoDetails, *URLMods, error) {
	// Checking to see if the user included a "file://" in the call
	protoSpecified := false
	if strings.HasPrefix(source, "file://") && len(source) > 7 {
		protoSpecified = true
	}

	refSpecified := false
	path, ref := "", ""
	if strings.LastIndex(source, "#") != -1 {
		refSpecified = true

		segments := strings.SplitN(source, "#", 2)
		path = segments[0]
		ref = segments[1]
	} else {
		path = source
	}

	// in each valid case, like the prior logic in scm.go did, we'll make the
	// paths absolute and prepend file:// to the path which callers should
	// switch to
	_, err := fs.Stat(strings.TrimPrefix(path, "file://"))
	if err == nil {
		// Is there even a valid .git repository?
		isValidGit, err := isValidGitRepository(fs, path)
		hasGit := false
		if isValidGit {
			hasGit = hasGitBinary()
		}

		if err != nil || !isValidGit || !hasGit {
			details := &FileProtoDetails{
				UseCopy:        true,
				FileExists:     true,
				BadRef:         false,
				ProtoSpecified: protoSpecified,
			}
			mods := &URLMods{
				Scheme: "file",
				Path:   makePathAbsolute(strings.TrimPrefix(path, "file://")),
				Ref:    ref,
			}
			return details, mods, err
		}

		// Check is the #ref is valid
		badRef := refSpecified && !gitSSHURLPathRef.MatchString(ref)

		details := &FileProtoDetails{
			BadRef:         badRef,
			FileExists:     true,
			ProtoSpecified: protoSpecified,
			// this value doesn't really matter, we should not proceed if the git ref is bad
			// but let's fallback to "copy" mode if the ref is invalid.
			UseCopy: badRef,
		}

		mods := &URLMods{
			Scheme: "file",
			Path:   makePathAbsolute(strings.TrimPrefix(path, "file://")),
			Ref:    ref,
		}
		return details, mods, nil
	}

	// File does not exist, return bad
	details := &FileProtoDetails{
		UseCopy:        false,
		FileExists:     false,
		BadRef:         false,
		ProtoSpecified: protoSpecified,
	}
	return details, nil, nil
}