devel-importer: handle history rewrite

Imports can have history rewritten because email addresses
can change in OBS and are not recorded as in git commits. This
can be handled via comparing Tree objects and rebasing
new changes ontop.
This commit is contained in:
Adam Majer 2024-09-18 17:17:24 +02:00
parent 9de8cf698f
commit 86df1921e0
2 changed files with 88 additions and 7 deletions

View File

@ -105,7 +105,7 @@ func (e *GitHandler) CloneDevel(gitDir, outName, urlString string) error {
params = append(params, url.String(), outName)
if err != nil {
return fmt.Errorf("error parsing SSH URL. %w", err);
return fmt.Errorf("error parsing SSH URL. %w", err)
}
out, err := e.GitExecWithOutput(gitDir, params...)
if err != nil {
@ -472,6 +472,53 @@ func parseGitBlob(data <-chan byte) ([]byte, error) {
return d, nil
}
func (e *GitHandler) GitParseCommits(cwd string, commitIDs []string) (parsedCommits []commit, err error) {
var done sync.Mutex
done.Lock()
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
parsedCommits = make([]commit, 0, len(commitIDs))
go func() {
defer done.Unlock()
defer close(data_out.ch)
for _, id := range commitIDs {
data_out.Write([]byte(id))
data_out.ch <- '\x00'
c, e := parseGitCommit(data_in.ch)
if e != nil {
err = fmt.Errorf("Error parsing git commit: %w", e)
return
}
parsedCommits = append(parsedCommits, c)
}
}()
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
cmd.Env = []string{
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
"GIT_CONFIG_GLOBAL=/dev/null",
}
cmd.Dir = filepath.Join(e.GitPath, cwd)
cmd.Stdout = &data_in
cmd.Stdin = &data_out
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
if e.DebugLogger {
log.Printf(string(data))
}
return len(data), nil
})
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
}
err = cmd.Run()
done.Lock()
return
}
// TODO: support sub-trees
func (e *GitHandler) GitCatFile(cwd, commitId, filename string) (data []byte, err error) {
var done sync.Mutex

View File

@ -245,20 +245,54 @@ func main() {
out, err = git.GitExecWithOutput(pkgName, "rev-list", head_branch)
if err != nil {
head_branch = "HEAD"
out = git.GitExecWithOutputOrPanic(pkgName, "rev-list", "HEAD")
out = git.GitExecWithOutputOrPanic(pkgName, "rev-list", head_branch)
}
old_revs := strings.Split(out, "\n")
added_revs := []string{}
out = git.GitExecWithOutputOrPanic(pkgName, "rev-list", head_branch, "^factory/factory")
added_revs = strings.Split(out, "\n")
added_rpm_revs := []string{}
added_rpm_revs := old_revs
if slices.Contains(remotes, "rpm") {
out = git.GitExecWithOutputOrPanic(pkgName, "rev-list", head_branch, "^rpm/factory")
added_rpm_revs = strings.Split(out, "\n")
}
if len(added_revs) == len(old_revs) && len(added_rpm_revs) == len(old_revs) {
log.Printf("Something is wrong with rev-ist for (len %d): %s\n", len(added_revs), pkgName)
reposOK = false
// check if we have broken history in OBS and that Tree objects are still matching
newCommits, err := git.GitParseCommits(pkgName, old_revs)
if err != nil {
log.Panicln("failed to parse commitids", err)
}
factoryCommitIDs := common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(pkgName, "rev-list", "factory/factory"), "\n")
factoryCommits, err := git.GitParseCommits(pkgName, factoryCommitIDs)
if err != nil {
log.Panicln("failed to parse factory commits")
}
// find first common trees
found := false
foundMatch:
for i := range newCommits {
for j := range factoryCommits {
if newCommits[i].Tree == factoryCommits[i].Tree {
log.Println("found match", i, "vs", j)
git.GitExecOrPanic(pkgName, "checkout", "-B", "factory", added_revs[j])
if i != 0 {
// chrry pick on top
for commitIndex := i - 1; commitIndex >= 0; i-- {
git.GitExecOrPanic(pkgName, "cherry-pick", factoryCommitIDs[commitIndex])
}
}
found = true
break foundMatch
}
}
}
if !found {
reposOK = false
}
}
}
}
@ -271,13 +305,13 @@ func main() {
args = append(args, develProjectPackages...)
cmd = exec.Command("./git-importer", args...)
out, err = cmd.CombinedOutput()
log.Println(out)
log.Println(string(out))
if err != nil {
log.Panicln("Error returned by importer.", err)
}
if !reposOK {
log.Println("aborting import due to broken repos above...")
log.Panicln("aborting import due to broken repos above...")
}
for _, pkg := range factoryRepos {
@ -289,7 +323,7 @@ func main() {
Organization: org,
}), r.DefaultAuthentication)
if err != nil {
log.Panicln("Error while trying to create fork from pool/", pkg.Name, err)
log.Panicln("Error while trying to create fork from pool", pkg.Name, err)
}
repo := fork.Payload