// MakePatchedConfig takes in the path to a remote configuration a stringified version // of the current project and returns an unmarshalled version of the project // with the patch applied func MakePatchedConfig(p *patch.Patch, remoteConfigPath, projectConfig string) ( *Project, error) { // Dereference all the patch data so that we can use it to write temp files err := p.FetchPatchFiles() if err != nil { return nil, err } for _, patchPart := range p.Patches { // we only need to patch the main project and not any other modules if patchPart.ModuleName != "" { continue } // write patch file patchFilePath, err := util.WriteToTempFile(patchPart.PatchSet.Patch) if err != nil { return nil, fmt.Errorf("could not write patch file: %v", err) } defer os.Remove(patchFilePath) // write project configuration configFilePath, err := util.WriteToTempFile(projectConfig) if err != nil { return nil, fmt.Errorf("could not write config file: %v", err) } defer os.Remove(configFilePath) // clean the working directory workingDirectory := filepath.Dir(patchFilePath) localConfigPath := filepath.Join( workingDirectory, remoteConfigPath, ) parentDir := strings.Split( remoteConfigPath, string(os.PathSeparator), )[0] err = os.RemoveAll(filepath.Join(workingDirectory, parentDir)) if err != nil { return nil, err } if err = os.MkdirAll(filepath.Dir(localConfigPath), 0755); err != nil { return nil, err } // rename the temporary config file name to the remote config // file path if we are patching an existing remote config if len(projectConfig) > 0 { if err = os.Rename(configFilePath, localConfigPath); err != nil { return nil, fmt.Errorf("could not rename file '%v' to '%v': %v", configFilePath, localConfigPath, err) } defer os.Remove(localConfigPath) } // selectively apply the patch to the config file patchCommandStrings := []string{ fmt.Sprintf("set -o verbose"), fmt.Sprintf("set -o errexit"), fmt.Sprintf("git apply --whitespace=fix --include=%v < '%v'", remoteConfigPath, patchFilePath), } patchCmd := &command.LocalCommand{ CmdString: strings.Join(patchCommandStrings, "\n"), WorkingDirectory: workingDirectory, Stdout: evergreen.NewInfoLoggingWriter(&evergreen.Logger), Stderr: evergreen.NewErrorLoggingWriter(&evergreen.Logger), ScriptMode: true, } if err = patchCmd.Run(); err != nil { return nil, fmt.Errorf("could not run patch command: %v", err) } // read in the patched config file data, err := ioutil.ReadFile(localConfigPath) if err != nil { return nil, fmt.Errorf("could not read patched config file: %v", err) } project := &Project{} if err = LoadProjectInto(data, p.Project, project); err != nil { return nil, err } return project, nil } return nil, fmt.Errorf("no patch on project") }