예제 #1
0
// VcsExists checks if the directory has a local VCS checkout.
func VcsExists(dep *yaml.Dependency, dest string) bool {
	repo, err := dep.GetRepo(dest)
	if err != nil {
		return false
	}

	return repo.CheckLocal()
}
예제 #2
0
// VcsLastCommit gets the last commit ID from the given dependency.
func VcsLastCommit(dep *yaml.Dependency, vend string) (string, error) {
	cwd := path.Join(vend, dep.Name)
	repo, err := dep.GetRepo(cwd)
	if err != nil {
		return "", err
	}

	if repo.CheckLocal() == false {
		return "", fmt.Errorf("%s is not a VCS repo\n", dep.Name)
	}

	version, err := repo.Version()
	if err != nil {
		return "", err
	}

	return version, nil
}
예제 #3
0
// VcsVersion set the VCS version for a checkout.
func VcsVersion(dep *yaml.Dependency, vend string) error {
	// If there is no refernece configured there is nothing to set.
	if dep.Reference == "" {
		return nil
	}

	cwd := path.Join(vend, dep.Name)

	// When the directory is not empty and has no VCS directory it's
	// a vendored files situation.
	empty, err := isDirectoryEmpty(cwd)
	if err != nil {
		return err
	}
	_, err = v.DetectVcsFromFS(cwd)
	if empty == false && err == v.ErrCannotDetectVCS {
		Warn("%s appears to be a vendored package. Unable to set new version. Consider the '--update-vendored' flag.\n", dep.Name)
	} else {
		repo, err := dep.GetRepo(cwd)
		if err != nil {
			return err
		}

		ver := dep.Reference
		// Referenes in Git can begin with a ^ which is similar to semver.
		// If there is a ^ prefix we assume it's a semver constraint rather than
		// part of the git/VCS commit id.
		if repo.IsReference(ver) && !strings.HasPrefix(ver, "^") {
			Info("Setting version for %s to %s.\n", dep.Name, ver)
		} else {

			// Create the constraing first to make sure it's valid before
			// working on the repo.
			constraint, err := semver.NewConstraint(ver)

			// Make sure the constriant is valid. At this point it's not a valid
			// reference so if it's not a valid constrint we can exit early.
			if err != nil {
				Warn("The reference '%s' is not valid\n", ver)
				return err
			}

			// Get the tags and branches (in that order)
			refs, err := getAllVcsRefs(repo)
			if err != nil {
				return err
			}

			// Convert and filter the list to semver.Version instances
			semvers := getSemVers(refs)

			// Sort semver list
			sort.Sort(sort.Reverse(semver.Collection(semvers)))
			found := false
			for _, v := range semvers {
				if constraint.Check(v) {
					found = true
					// If the constrint passes get the original reference
					ver = v.Original()
					break
				}
			}
			if found {
				Info("Detected semantic version. Setting version for %s to %s.\n", dep.Name, ver)
			} else {
				Warn("Unable to find semantic version for constraint %s %s\n", dep.Name, ver)
			}
		}
		if err := repo.UpdateVersion(ver); err != nil {
			Error("Failed to set version to %s: %s\n", dep.Reference, err)
			return err
		}
	}

	return nil
}
예제 #4
0
// VcsUpdate updates to a particular checkout based on the VCS setting.
func VcsUpdate(dep *yaml.Dependency, vend, home string, force, cache, cacheGopath, skipGopath bool) error {
	Info("Fetching updates for %s.\n", dep.Name)

	if filterArchOs(dep) {
		Info("%s is not used for %s/%s.\n", dep.Name, runtime.GOOS, runtime.GOARCH)
		return nil
	}

	dest := path.Join(vend, dep.Name)
	// If destination doesn't exist we need to perform an initial checkout.
	if _, err := os.Stat(dest); os.IsNotExist(err) {
		if err = VcsGet(dep, dest, home, cache, cacheGopath, skipGopath); err != nil {
			Warn("Unable to checkout %s\n", dep.Name)
			return err
		}
	} else {
		// At this point we have a directory for the package.

		// When the directory is not empty and has no VCS directory it's
		// a vendored files situation.
		empty, err := isDirectoryEmpty(dest)
		if err != nil {
			return err
		}
		_, err = v.DetectVcsFromFS(dest)
		if empty == false && err == v.ErrCannotDetectVCS {
			Warn("%s appears to be a vendored package. Unable to update. Consider the '--update-vendored' flag.\n", dep.Name)
		} else {
			repo, err := dep.GetRepo(dest)

			// Tried to checkout a repo to a path that does not work. Either the
			// type or endpoint has changed. Force is being passed in so the old
			// location can be removed and replaced with the new one.
			// Warning, any changes in the old location will be deleted.
			// TODO: Put dirty checking in on the existing local checkout.
			if (err == v.ErrWrongVCS || err == v.ErrWrongRemote) && force == true {
				var newRemote string
				if len(dep.Repository) > 0 {
					newRemote = dep.Repository
				} else {
					newRemote = "https://" + dep.Name
				}

				Warn("Replacing %s with contents from %s\n", dep.Name, newRemote)
				rerr := os.RemoveAll(dest)
				if rerr != nil {
					return rerr
				}
				if err = VcsGet(dep, dest, home, cache, cacheGopath, skipGopath); err != nil {
					Warn("Unable to checkout %s\n", dep.Name)
					return err
				}
			} else if err != nil {
				return err
			} else {
				// Check if the current version is a tag or commit id. If it is
				// and that version is already checked out we can skip updating
				// which is faster than going out to the Internet to perform
				// an update.
				if dep.Reference != "" {
					version, err := repo.Version()
					if err != nil {
						return err
					}
					ib, err := isBranch(dep.Reference, repo)
					if err != nil {
						return err
					}

					// If the current version equals the ref and it's not a
					// branch it's a tag or commit id so we can skip
					// performing an update.
					if version == dep.Reference && !ib {
						Info("%s is already set to version %s. Skipping update.", dep.Name, dep.Reference)
						return nil
					}
				}

				if err := repo.Update(); err != nil {
					Warn("Download failed.\n")
					return err
				}
			}
		}
	}

	return nil
}
예제 #5
0
// VcsGet figures out how to fetch a dependency, and then gets it.
//
// VcsGet installs into the dest.
func VcsGet(dep *yaml.Dependency, dest, home string, cache, cacheGopath, skipGopath bool) error {

	// When not skipping the $GOPATH look in it for a copy of the package
	if !skipGopath {
		// Check if the $GOPATH has a viable version to use and if so copy to vendor
		gps := Gopaths()
		for _, p := range gps {
			d := filepath.Join(p, "src", dep.Name)
			if _, err := os.Stat(d); err == nil {
				empty, err := isDirectoryEmpty(d)
				if empty || err != nil {
					continue
				}

				repo, err := dep.GetRepo(d)
				if err != nil {
					continue
				}

				// Dirty repos have uncomitted changes.
				if repo.IsDirty() {
					continue
				}

				// Having found a repo we copy it to vendor and update it.
				Debug("Found %s in GOPATH at %s. Copying to %s", dep.Name, d, dest)
				err = copyDir(d, dest)
				if err != nil {
					return err
				}

				// Update the repo in the vendor directory
				Debug("Updating %s, now in the vendor path at %s", dep.Name, dest)
				repo, err = dep.GetRepo(dest)
				if err != nil {
					return err
				}
				err = repo.Update()
				if err != nil {
					return err
				}

				// If there is no reference set on the dep we try to checkout
				// the default branch.
				if dep.Reference == "" {
					db := defaultBranch(repo, home)
					if db != "" {
						err = repo.UpdateVersion(db)
						if err != nil {
							Debug("Attempting to set the version on %s to %s failed. Error %s", dep.Name, db, err)
						}
					}
				}
				return nil
			}
		}
	}

	// When opting in to cache in the GOPATH attempt to do put a copy there.
	if cacheGopath {

		// Since we didn't find an existing copy in the GOPATHs try to clone there.
		gp := Gopath()
		if gp != "" {
			d := filepath.Join(gp, "src", dep.Name)
			if _, err := os.Stat(d); os.IsNotExist(err) {
				// Empty directory so we checkout out the code here.
				Debug("Retrieving %s to %s before copying to vendor", dep.Name, d)
				repo, err := dep.GetRepo(d)
				if err != nil {
					return err
				}
				repo.Get()

				branch := findCurrentBranch(repo)
				if branch != "" {
					// we know the default branch so we can store it in the cache
					var loc string
					if dep.Repository != "" {
						loc = dep.Repository
					} else {
						loc = "https://" + dep.Name
					}
					key, err := cacheCreateKey(loc)
					if err == nil {
						Debug("Saving default branch for %s", repo.Remote())
						c := cacheRepoInfo{DefaultBranch: branch}
						saveCacheRepoData(key, c, home)
					}
				}

				Debug("Copying %s from GOPATH at %s to %s", dep.Name, d, dest)
				err = copyDir(d, dest)
				if err != nil {
					return err
				}

				return nil
			}
		}
	}

	// If opting in to caching attempt to put it in the cache folder
	if cache {
		// Check if the cache has a viable version and try to use that.
		var loc string
		if dep.Repository != "" {
			loc = dep.Repository
		} else {
			loc = "https://" + dep.Name
		}
		key, err := cacheCreateKey(loc)
		if err == nil {
			d := filepath.Join(home, "cache", "src", key)

			repo, err := dep.GetRepo(d)
			if err != nil {
				return err
			}
			// If the directory does not exist this is a first cache.
			if _, err = os.Stat(d); os.IsNotExist(err) {
				Debug("Adding %s to the cache for the first time", dep.Name)
				err = repo.Get()
				if err != nil {
					return err
				}
				branch := findCurrentBranch(repo)
				if branch != "" {
					// we know the default branch so we can store it in the cache
					var loc string
					if dep.Repository != "" {
						loc = dep.Repository
					} else {
						loc = "https://" + dep.Name
					}
					key, err := cacheCreateKey(loc)
					if err == nil {
						Debug("Saving default branch for %s", repo.Remote())
						c := cacheRepoInfo{DefaultBranch: branch}
						err = saveCacheRepoData(key, c, home)
						if err != nil {
							Debug("Error saving %s to cache. Error: %s", repo.Remote(), err)
						}
					}
				}

			} else {
				Debug("Updating %s in the cache", dep.Name)
				err = repo.Update()
				if err != nil {
					return err
				}
			}

			Debug("Copying %s from the cache to %s", dep.Name, dest)
			err = copyDir(d, dest)
			if err != nil {
				return err
			}

			return nil
		} else {
			Warn("Cache key generation error: %s", err)
		}
	}

	// If unable to cache pull directly into the vendor/ directory.
	repo, err := dep.GetRepo(dest)
	if err != nil {
		return err
	}

	gerr := repo.Get()

	// Attempt to cache the default branch
	branch := findCurrentBranch(repo)
	if branch != "" {
		// we know the default branch so we can store it in the cache
		var loc string
		if dep.Repository != "" {
			loc = dep.Repository
		} else {
			loc = "https://" + dep.Name
		}
		key, err := cacheCreateKey(loc)
		if err == nil {
			Debug("Saving default branch for %s", repo.Remote())
			c := cacheRepoInfo{DefaultBranch: branch}
			err = saveCacheRepoData(key, c, home)
			if err != nil {
				Debug("Error saving %s to cache. Error: %s", repo.Remote(), err)
			}
		}
	}

	return gerr
}