Ejemplo n.º 1
0
// CheckAndUpdate checks whether we should update Please and does so if needed.
// If it requires an update it will never return, it will either die on failure or on success will exec the new Please.
// Conversely, if an update isn't required it will return. It may adjust the version in the configuration.
// updatesEnabled indicates whether updates are enabled (i.e. not run with --noupdate)
// updateCommand indicates whether an update is specifically requested (due to e.g. `plz update`)
// forceUpdate indicates whether the user passed --force on the command line, in which case we
// will always update even if the version exists.
func CheckAndUpdate(config *core.Configuration, updatesEnabled, updateCommand, forceUpdate bool) {
	if !forceUpdate && !shouldUpdate(config, updatesEnabled, updateCommand) {
		return
	}
	word := describe(config.Please.Version, core.PleaseVersion, true)
	log.Warning("%s to Please version %s (currently %s)", word, config.Please.Version, core.PleaseVersion)

	// Must lock here so that the update process doesn't race when running two instances
	// simultaneously.
	core.AcquireRepoLock()
	defer core.ReleaseRepoLock()

	// If the destination exists and the user passed --force, remove it to force a redownload.
	newDir := core.ExpandHomePath(path.Join(config.Please.Location, config.Please.Version.String()))
	log.Notice("%s", newDir)
	if forceUpdate && core.PathExists(newDir) {
		if err := os.RemoveAll(newDir); err != nil {
			log.Fatalf("Failed to remove existing directory: %s", err)
		}
	}

	// Download it.
	newPlease := downloadAndLinkPlease(config)

	// Now run the new one.
	args := append([]string{newPlease}, os.Args[1:]...)
	log.Info("Executing %s", strings.Join(args, " "))
	if err := syscall.Exec(newPlease, args, os.Environ()); err != nil {
		log.Fatalf("Failed to exec new Please version %s: %s", newPlease, err)
	}
	// Shouldn't ever get here. We should have either exec'd or died above.
	panic("please update failed in an an unexpected and exciting way")
}
Ejemplo n.º 2
0
func newDirCache(config *core.Configuration) *dirCache {
	cache := new(dirCache)
	// Absolute paths are allowed. Relative paths are interpreted relative to the repo root.
	if config.Cache.Dir[0] == '/' {
		cache.Dir = config.Cache.Dir
	} else {
		cache.Dir = path.Join(core.RepoRoot, config.Cache.Dir)
	}
	// Make directory if it doesn't exist.
	if err := os.MkdirAll(cache.Dir, core.DirPermissions); err != nil {
		panic(fmt.Sprintf("Failed to create root cache directory %s: %s", cache.Dir, err))
	}
	// Fire off the cache cleaner process.
	if config.Cache.DirCacheCleaner != "" && config.Cache.DirCacheCleaner != "none" {
		go func() {
			cleaner := core.ExpandHomePath(config.Cache.DirCacheCleaner)
			log.Info("Running cache cleaner: %s --dir %s --high_water_mark %s --low_water_mark %s",
				cleaner, cache.Dir, config.Cache.DirCacheHighWaterMark, config.Cache.DirCacheLowWaterMark)
			if _, err := syscall.ForkExec(cleaner, []string{
				cleaner,
				"--dir", cache.Dir,
				"--high_water_mark", config.Cache.DirCacheHighWaterMark,
				"--low_water_mark", config.Cache.DirCacheLowWaterMark,
			}, nil); err != nil {
				log.Errorf("Failed to start cache cleaner: %s", err)
			}
		}()
	}
	return cache
}
Ejemplo n.º 3
0
// downloadAndLinkPlease downloads a new Please version and links it into place, if needed.
// It returns the new location and dies on failure.
func downloadAndLinkPlease(config *core.Configuration) string {
	config.Please.Location = core.ExpandHomePath(config.Please.Location)
	newPlease := path.Join(config.Please.Location, config.Please.Version.String(), "please")

	if !core.PathExists(newPlease) {
		downloadPlease(config)
	}
	if !verifyNewPlease(newPlease, config.Please.Version.String()) {
		cleanDir(path.Join(config.Please.Location, config.Please.Version.String()))
		log.Fatalf("Not continuing.")
	}
	linkNewPlease(config)
	return newPlease
}
Ejemplo n.º 4
0
// Parses an incoming source label as either a file or a build label.
// Identifies if the file is owned by this package and returns an error if not.
func parseSource(src, packageName string, systemAllowed bool) (core.BuildInput, error) {
	if core.LooksLikeABuildLabel(src) {
		return core.TryParseBuildLabel(src, packageName)
	} else if src == "" {
		return nil, fmt.Errorf("Empty source path (in package %s)", packageName)
	} else if strings.Contains(src, "../") {
		return nil, fmt.Errorf("'%s' (in package %s) is an invalid path; build target paths can't contain ../", src, packageName)
	} else if src[0] == '/' || src[0] == '~' {
		if !systemAllowed {
			return nil, fmt.Errorf("'%s' (in package %s) is an absolute path; that's not allowed.", src, packageName)
		}
		return core.SystemFileLabel{Path: core.ExpandHomePath(src)}, nil
	} else if strings.Contains(src, "/") {
		// Target is in a subdirectory, check nobody else owns that.
		for dir := path.Dir(path.Join(packageName, src)); dir != packageName && dir != "."; dir = path.Dir(dir) {
			if core.IsPackage(dir) {
				return nil, fmt.Errorf("Package %s tries to use file %s, but that belongs to another package (%s).", packageName, src, dir)
			}
		}
	}
	return core.FileLabel{File: src, Package: packageName}, nil
}