Beispiel #1
0
Datei: file.go Projekt: dvln/util
// CopyFileSetPerms copies from src to dst until either EOF is reached
// on src or an error occurs.  It will create the destination file with
// the specified permissions and return the number of bytes written (int64)
// and an error (nil if no error).
// Note: if destination file exists it will be removed by this routine
func CopyFileSetPerms(src, dst string, mode os.FileMode) (int64, error) {
	cleanSrc := filepath.Clean(src)
	cleanDst := filepath.Clean(dst)
	if cleanSrc == cleanDst {
		return 0, nil
	}
	sf, err := os.Open(cleanSrc)
	if err != nil {
		return 0, out.WrapErr(err, "Failed to open source file", 4004)
	}
	defer sf.Close()
	if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) {
		return 0, out.WrapErr(err, "Failed to clean/remove destination file", 4005)
	}
	oldUmask := syscall.Umask(0)
	defer syscall.Umask(oldUmask)
	df, err := os.OpenFile(cleanDst, syscall.O_CREAT|syscall.O_EXCL|syscall.O_APPEND|syscall.O_WRONLY, mode)
	if err != nil {
		return 0, out.WrapErr(err, "Failed to create destination file", 4006)
	}
	defer df.Close()
	bytes, err := io.Copy(df, sf)
	if err != nil {
		return bytes, out.WrapErr(err, "Failed to copy source file to destination", 4007)
	}
	return bytes, nil
}
Beispiel #2
0
// Read will, given an io.Reader, attempt to scan in the codebase contents
// and "fill out" the given Defn structure for you.  What could
// go wrong?  If anything a non-nil error is returned.
func (cb *Defn) Read(r io.Reader) error {
	codebaseMap := make(map[string]interface{})
	decJSON := json.NewDecoder(r)
	err := decJSON.Decode(&codebaseMap)
	if err != nil {
		if serr, ok := err.(*json.SyntaxError); ok {
			return out.WrapErrf(err, 3001, "Failed to decode codebase JSON (Bad Char Offset: %v)", serr.Offset)
		}
		return out.WrapErr(err, "Failed to decode codebase JSON file", 3001)
	}

	config := &mapstructure.DecoderConfig{
		WeaklyTypedInput: true,
		Result:           cb,
	}
	decoder, err := mapstructure.NewDecoder(config)
	if err != nil {
		return out.WrapErr(err, "Failed to prepare codebase file decoder", 3002)
	}

	err = decoder.Decode(codebaseMap)
	if err != nil {
		return out.WrapErr(err, "Failed to decode codebase file contents", 3003)
	}
	// codebase definitions can be reduced in size if the person defining that
	// file uses variables to identify common repo references and such, lets
	// examine those vars and, if any, make sure we "expand" them so the codebase
	// definition is complete.  Write() will "smart" subtitute the vars back.
	if err = cb.expandVarUse(); err != nil {
		return err
	}
	return nil
}
Beispiel #3
0
Datei: file.go Projekt: dvln/util
// CopyFile copies from src to dst until either EOF is reached
// on src or an error occurs. It verifies src exists and remove
// the dst if it exists.
func CopyFile(src, dst string) (int64, error) {
	cleanSrc := filepath.Clean(src)
	cleanDst := filepath.Clean(dst)
	if cleanSrc == cleanDst {
		return 0, nil
	}
	sf, err := os.Open(cleanSrc)
	if err != nil {
		return 0, out.WrapErr(err, "Failed to open source file", 4004)
	}
	defer sf.Close()
	if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) {
		return 0, out.WrapErr(err, "Failed to clean/remove destination file", 4005)
	}
	df, err := os.Create(cleanDst)
	if err != nil {
		return 0, out.WrapErr(err, "Failed to create destination file", 4006)
	}
	defer df.Close()
	bytes, err := io.Copy(df, sf)
	if err != nil {
		return bytes, out.WrapErr(err, "Failed to copy source file to destination", 4007)
	}
	return bytes, nil
}
Beispiel #4
0
Datei: git.go Projekt: dvln/vcs
// GitUpdate performs a git fetch and merge to an existing checkout (ie:
// a git pull).  Params:
//	u (*GitUpdater): git upd struct, gives kind of update needed, stores cmds run
//	rev (Rev): optional; revision to update to (if given only 1 used)
// Returns results (vcs cmds run, output) and any error that may have occurred
func GitUpdate(u *GitUpdater, rev ...Rev) (Resulter, error) {
	// Perform required fetches optionally with pulls as well as handling
	// more specific fetches on single refs (or deletion of refs)... has
	// some handling of mirror/bare clones vs local clones and for std
	// clones can do rebase type pulls (if that section of the routine is
	// reached).

	results := newResults()
	path, _, err := u.Exists(LocalPath)
	if err != nil && path == "" {
		return results, out.WrapErr(err, "Existence check failed on local git clone", 4509)
	}

	if u.refs != nil {
		return gitUpdateRefs(u)
	}
	runOpt := "-C"
	runDir := u.LocalRepoPath()
	var result *Result
	if u.mirror {
		result, err = run(gitTool, runOpt, runDir, "remote", "update", "--prune", u.RemoteRepoName())
	} else {
		result, err = run(gitTool, runOpt, runDir, "fetch", u.RemoteRepoName())
	}
	results.add(result)
	if err != nil {
		return results, err
	}

	bareRepo := false
	gitDir, workTree, err := findGitDirs(runDir)
	if err != nil {
		return nil, err
	}
	if gitDir == runDir && workTree == "" {
		bareRepo = true
	}
	if !u.mirror && !bareRepo { // if not a mirror and a regular clone
		// Try and run a git pull to do the merge|rebase op
		rebaseStr := ""
		switch u.rebase {
		case RebaseFalse:
			rebaseStr = "--rebase=false"
		case RebaseTrue:
			rebaseStr = "--rebase=true"
		case RebasePreserve:
			rebaseStr = "--rebase=preserve"
		default: // likely RebaseUser, meaning don't provide any rebase opt
		}
		var pullResult *Result
		if rev == nil || (rev != nil && rev[0] == "") {
			pullResult, err = run(gitTool, runOpt, runDir, "pull", rebaseStr, u.RemoteRepoName())
		} else { // if user asks for a specific version on pull, use that
			pullResult, err = run(gitTool, runOpt, runDir, "pull", rebaseStr, u.RemoteRepoName(), string(rev[0]))
		}
		results.add(pullResult)
	}
	return results, err
}
Beispiel #5
0
Datei: path.go Projekt: dvln/util
// CreateIfNotExists creates a file or a directory only if it does not already exist.
func CreateIfNotExists(path string, isDir bool) error {
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			if isDir {
				return os.MkdirAll(path, 0755)
			}
			if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
				return out.WrapErr(err, "Failed to make directory path", 4001)
			}
			f, err := os.OpenFile(path, os.O_CREATE, 0755)
			if err != nil {
				return out.WrapErr(err, "Failed to create requested file", 4002)
			}
			f.Close()
		}
	}
	return nil
}
Beispiel #6
0
Datei: path.go Projekt: dvln/util
// Exists checks if given file/dir exists. Note: for more specific checks on a
// file or dir existence see dir.Exists() and file.Exists().
func Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, out.WrapErr(err, "Stat on path failed unexpectedly", 4000)
}
Beispiel #7
0
Datei: git.go Projekt: dvln/vcs
// GitHookInstall is used to install a hook into a git clone, params:
//	h (*GitHookMgr): the hook mgr structure (find location of repo/etc)
//	path (string): where is the hook we wish to install?
//	name (string): what is the "git name" for the hook?
//	link (bool): is hook a symlink to hookPath, or full copy/install?
// Returns full path/name to git hook installed along w/any error seen
func GitHookInstall(h *GitHookMgr, path, name string, link bool) (string, error) {
	repoPath, _, err := h.Exists(LocalPath)
	hookInstallPath := ""
	if err == nil && repoPath != "" { // if the local path exists...
		hookInstallPath = filepath.Join(repoPath, ".git", "hooks", name)
		if isBareRepo(repoPath) {
			hookInstallPath = filepath.Join(repoPath, "hooks", name)
		}
		if there, err := file.Exists(hookInstallPath); err == nil && there {
			err = os.Remove(hookInstallPath)
			if err != nil {
				return "", out.WrapErr(err, "Failed to remove previously installed hook", 4510)
			}
		}
		if there, err := file.Exists(path); err != nil || !there {
			if err != nil {
				return "", out.WrapErr(err, "Hook install failed checking source hook existence", 4511)
			}
			return "", out.NewErrf(4512, "Hook install failed, hook source path does not exist:\n  path: %s", path)
		}
		oldUmask := syscall.Umask(0)
		defer syscall.Umask(oldUmask)
		if link { // if symlink desired, try and create that
			err = os.Symlink(path, hookInstallPath)
			if err != nil {
				err = out.WrapErrf(err, 4513, "Hook install failed, failed to set up symlink:\n  linktgt: %s\n  link: %s\n", path, hookInstallPath)
			}
		} else { // otherwise try and copy in the hook file
			_, err = file.CopyFileSetPerms(path, hookInstallPath, 0775)
			if err != nil {
				err = out.WrapErrf(err, 4514, "Hook install failed, failed to copy hook file:\n  hook source path %s\n  hook install path: %s\n", path, hookInstallPath)
			}
		}
	}
	return hookInstallPath, err
}
Beispiel #8
0
Datei: dir.go Projekt: dvln/util
// FindDirInOrAbove will look for a given directory in or above the given
// starting dir (iit will travese "up" the filesystem and examine parent
// directories to see if they contain the given directory).  If the findDir
// dir is found then the dir it's found in will be returned, else "" (any
// unexpected error will come back in the error return parameter)
func FindDirInOrAbove(startDir string, findDir string) (string, error) {
	fullPath := filepath.Join(startDir, findDir)
	exists, err := Exists(fullPath)
	if err != nil {
		return "", out.WrapErr(err, "Problem checking directory existence", 4003)
	}
	if exists {
		return startDir, nil
	}
	baseDir := filepath.Dir(startDir)
	if baseDir == "." || (len(baseDir) == 1 && baseDir[0] == filepath.Separator) {
		return "", nil
	}
	return FindDirInOrAbove(baseDir, findDir)
}
Beispiel #9
0
Datei: file.go Projekt: dvln/util
// Matches returns true if file matches any of the patterns
// and isn't excluded by any of the subsequent patterns.
func Matches(file string, patterns []string) (bool, error) {
	file = filepath.Clean(file)

	if file == "." {
		// Don't let them exclude everything, kind of silly.
		return false, nil
	}

	patterns, patDirs, _, err := CleanPatterns(patterns)
	if err != nil {
		return false, out.WrapErr(err, "Unable to clean all patterns", 4010)
	}

	return OptimizedMatches(file, patterns, patDirs)
}
Beispiel #10
0
Datei: dir.go Projekt: dvln/util
// Exists checks if given dir exists, if you want to check for a *file*
// use the file.Exists() routine or if you want to check for both file and
// directory use the path.Exists() routine.
func Exists(dir string) (bool, error) {
	exists, err := path.Exists(dir)
	if err != nil {
		// error already wrapped by path.Exists()
		return exists, err
	}
	if exists {
		fileinfo, err := os.Stat(dir)
		if err != nil {
			return false, out.WrapErr(err, "Failed to stat directory, unable to verify existence", 4011)
		}
		if !fileinfo.IsDir() {
			exists = false
			err = out.NewErr("Item is not a directory hence directory existence check failed", 4012)
		}
	}
	return exists, err
}
Beispiel #11
0
// RootDirFind gets the workspaces root dir (if there is one), note that this will
// not use any "cached" values and it will store the result in globs (viper)
// under the "wkspcRootDir" key (you can access that with any upper/lower case
// as viper is case insensitive).
func RootDirFind(path ...string) (string, error) {
	startDir := ""
	var err error
	if path == nil || path[0] == "" {
		startDir, err = os.Getwd()
		if err != nil {
			return "", out.WrapErr(err, "Unable to find the workspace root directory (get current working dir failed)", 4100)
		}
	} else {
		startDir = path[0]
	}
	rootDir, err := dir.FindDirInOrAbove(startDir, globs.GetString("wkspcMetaDirName"))
	if err == nil {
		// Cache the root dir in "globs" (viper) memory if no error
		globs.Set("wkspcRootDir", rootDir)
	}
	return rootDir, err
}
Beispiel #12
0
Datei: file.go Projekt: dvln/util
// Exists checks if given file exists, if you want to check for a directory
// use the dir.Exists() routine or if you want to check for both file and
// directory use the path.Exists() routine.
func Exists(file string) (bool, error) {
	exists, err := path.Exists(file)
	if err != nil {
		// error already wrapped by path.Exists()
		return exists, err
	}
	if exists {
		var fileinfo os.FileInfo
		fileinfo, err = os.Stat(file)
		if err != nil {
			return false, out.WrapErr(err, "Failed to stat file, unable to verify existence", 4013)
		}
		if fileinfo.IsDir() {
			exists = false
			err = out.NewErr("Item is a directory hence the file existence check failed", 4014)
		}
	}
	return exists, err
}
Beispiel #13
0
// Get basically tries to find, get and read a codebase if it can, it
// returns a codebase definition and any error's that may have occurred
func (cb *Defn) Get(codebaseVerSel string) error {
	//eriknow: normally we would do any smart discovery of the code base
	//         definition file here via 'findCodebase()' or something which
	//         would be able to get it via local file (support RCS versioned),
	//         or, more likely, the file is in a git clone with the codebase
	//         definition in it which may also have devline definitions and
	//         possibly code as well
	//         - the name could be a partial or full URL, eg:
	//           "dvln" or "github.com/dvln/dvln" or "http://github.com/dvln/dvln"
	//           or "file:://path/to/somefile.json" or "/path/to/somefile.json" or
	//           might use OS friendly paths like "\path\to\somefile.toml"
	//         - if we think it's in a VCS we need to bring that clone into the
	//           workspace if we have a workspace, if we don't have a workspace
	//           we should bring it into a temp location or into ~/.dvlncfg/codebase/
	//           or something like that (flattened full path?)... we can "smart local clone"
	//           this pkg into the workspace with hard links or whatever if later "get" of it

	// normally Exists() would do this part and try and get us a "real" name for the
	// codebase (full URL/etc... but the name should be simple in the file even if
	// the "full" name is a URL and such)
	fileName := fmt.Sprintf("/Users/brady/.dvlncfg/%s.codebase", codebaseVerSel)
	cbFile, locality, err := cb.Exists(fileName)
	if locality == NonExistent {
		cb.Name = "generated"
		cb.Desc = "Dynamically generated development line"
		return err // note, err may be nil as it's ok for codebase not to exist
	}
	//FIXME: erik: normally we would check and see if locality was 'RemoteURL' as well
	//       and, if so, use the Get() routine to bring it down to our workspace
	//       if we have one and to a tmp location if not (wsroot should be set
	//       in viper if we have a workspace, note that if it's nested it may
	//       be a child workspace root but that should be normal I think, consider)
	fileContents, err := ioutil.ReadFile(cbFile)
	if err != nil {
		msg := fmt.Sprintf("Codebase file \"%s\" read failed\n", cbFile)
		return out.WrapErr(err, msg, 3000)
	}
	err = cb.Read(bytes.NewReader(fileContents))
	return err
}
Beispiel #14
0
Datei: file.go Projekt: dvln/util
// OptimizedMatches is basically the same as fileutils.Matches() but optimized for archive.go.
// It will assume that the inputs have been preprocessed and therefore the function
// doen't need to do as much error checking and clean-up. This was done to avoid
// repeating these steps on each file being checked during the archive process.
// The more generic fileutils.Matches() can't make these assumptions.
func OptimizedMatches(file string, patterns []string, patDirs [][]string) (bool, error) {
	matched := false
	parentPath := filepath.Dir(file)
	parentPathDirs := strings.Split(parentPath, "/")

	for i, pattern := range patterns {
		negative := false

		if exclusion(pattern) {
			negative = true
			pattern = pattern[1:]
		}

		match, err := filepath.Match(pattern, file)
		if err != nil {
			return false, out.WrapErr(err, "Optimized matching, failed to match pattern", 4008)
		}

		if !match && parentPath != "." {
			// Check to see if the pattern matches one of our parent dirs.
			if len(patDirs[i]) <= len(parentPathDirs) {
				match, _ = filepath.Match(strings.Join(patDirs[i], "/"),
					strings.Join(parentPathDirs[:len(patDirs[i])], "/"))
			}
		}

		if match {
			matched = !negative
		}
	}

	if matched {
		out.Debugf("Skipping excluded path: %s", file)
	}
	return matched, nil
}