Exemplo n.º 1
0
// ensureBuild invokes the build process on the given repository
func ensureBuild(buildStore buildstore.RepoBuildStore, repo *Repo) error {
	configOpt := config.Options{
		Repo:   repo.URI(),
		Subdir: ".",
	}
	toolchainExecOpt := ToolchainExecOpt{ExeMethods: "program"}

	// Config repository if not yet built.
	exists, err := buildstore.BuildDataExistsForCommit(buildStore, repo.CommitID)
	if err != nil {
		return err
	}
	if !exists {
		configCmd := &ConfigCmd{
			Options:          configOpt,
			ToolchainExecOpt: toolchainExecOpt,
			Quiet:            true,
		}
		if err := configCmd.Execute(nil); err != nil {
			return err
		}
	}

	// Always re-make.
	//
	// TODO(sqs): optimize this
	makeCmd := &MakeCmd{
		Options:          configOpt,
		ToolchainExecOpt: toolchainExecOpt,
		Quiet:            true,
	}
	if err := makeCmd.Execute(nil); err != nil {
		return err
	}

	// Always re-import.
	i := &StoreImportCmd{
		ImportOpt: ImportOpt{
			Repo:     repo.CloneURL,
			CommitID: repo.CommitID,
		},
		Quiet: true,
	}
	if err := i.Execute(nil); err != nil {
		return err
	}
	return nil
}
Exemplo n.º 2
0
// CreateMakefile creates the makefiles for the source units in c.
func CreateMakefile(buildDataDir string, buildStore buildstore.RepoBuildStore, vcsType string, c *config.Tree, opt Options) (*makex.Makefile, error) {
	var allRules []makex.Rule
	for i, r := range orderedRuleMakers {
		name := ruleMakerNames[i]
		rules, err := r(c, buildDataDir, allRules, opt)
		if err != nil {
			return nil, fmt.Errorf("rule maker %s: %s", name, err)
		}
		if !opt.NoCache {
			// When cached builds are enabled, we replace all rules whose source unit
			// hasn't changed between commits with a rule that copies the build
			// files stored at the previous commit to the current one.

			// Check to see if a previous build exists.
			var prevCommitID string
			var changedFiles []string
			if revs, err := listLatestCommitIDs(vcsType); err != nil {
				log.Printf("Warning: could not list revisions, rebuilding from scratch: %s, %s", revs, err)
			} else {
				// Skip HEAD, the first revision in the list.
				for i := 1; i < len(revs); i++ {
					if exist, _ := buildstore.BuildDataExistsForCommit(buildStore, revs[i]); !exist {
						continue
					}
					// A build store exists for this commit. Now we need
					// to get all the changed files between this rev and
					// the current rev.
					files, err := filesChangedFromRevToIndex(vcsType, revs[i])
					if err != nil {
						log.Printf("Warning: could not retrieve changed files, rebuilding from scratch: %s %s", files, err)
						break
					}
					changedFiles = files
					prevCommitID = revs[i]
				}
			}
			if prevCommitID != "" {
				// Replace rules.
				for i, rule := range rules {
					r, ok := rule.(interface {
						SourceUnit() *unit.SourceUnit
					})
					if !ok {
						continue
					}
					u := r.SourceUnit()
					if u.ContainsAny(changedFiles) {
						continue
					}

					// The format for p varies based on whether it's prefixed by buildDataDir:
					// if it is, we simply swap the revision in the file name with the
					// previous valid revision. If it isn't, we prefix p with
					// "../[previous-revision]".
					p := strings.Split(rule.Target(), "/")
					if len(p) > 2 &&
						strings.Join(p[0:2], "/") == buildDataDir &&
						len(p[1]) == 40 { // HACK: Mercurial and Git both use 40-char hashes.
						// p is prefixed by "data-dir/vcs-commit-id"
						p[1] = prevCommitID
					} else {
						p = append([]string{"..", prevCommitID}, p...)
					}

					rules[i] = &cachedRule{
						cachedPath: strings.Join(p, "/"),
						target:     rule.Target(),
						unit:       u,
						prereqs:    rule.Prereqs(),
					}
				}
			}
		}
		allRules = append(allRules, rules...)
	}

	// Add an "all" rule at the very beginning.
	allTargets := make([]string, len(allRules))
	for i, rule := range allRules {
		allTargets[i] = rule.Target()
	}
	allRule := &makex.BasicRule{TargetFile: "all", PrereqFiles: allTargets}
	allRules = append([]makex.Rule{allRule}, allRules...)

	// DELETE_ON_ERROR makes it so that the targets for failed recipes are
	// deleted. This lets us do "1> $@" to write to the target file without
	// erroneously satisfying the target if the recipe fails. makex has this
	// behavior by default and does not heed .DELETE_ON_ERROR.
	allRules = append(allRules, &makex.BasicRule{TargetFile: ".DELETE_ON_ERROR"})

	mf := &makex.Makefile{Rules: allRules}

	return mf, nil
}