diff --git a/pkg/srpmproc/process.go b/pkg/srpmproc/process.go index 1383572..76fe57a 100644 --- a/pkg/srpmproc/process.go +++ b/pkg/srpmproc/process.go @@ -855,9 +855,9 @@ func processRPMTagless(pd *data.ProcessData) (*srpmprocpb.ProcessResponse, error // get name-version-release of tagless repo, only if we're not a module repo: if !pd.ModuleMode { - nvrString := getVersionFromSpec(md.Name, localPath, pd.Version) - if nvrString == "" { - return nil, fmt.Errorf("Error using rpm or rpmbuild to build SRPM and determine version info! (tagless mode)") + nvrString, err := getVersionFromSpec(localPath, pd.Version) + if err != nil { + return nil, err } // Set version and release fields we extracted (name|version|release are separated by pipes) @@ -1176,112 +1176,47 @@ func convertMetaData(pkgName string, localRepo string) bool { // - create a "dummy" SRPM (using dummy sources files we use to populate tarballs from lookaside) // - extract RPM version info from that SRPM, and return it // If we are in tagless mode, we need to get a package version somehow! -func getVersionFromSpec(pkgName string, localRepo string, majorVersion int) string { +func getVersionFromSpec(localRepo string, majorVersion int) (string, error) { // Make sure we have "rpm" and "rpmbuild" and "cp" available in our PATH. Otherwise, this won't work: - _, err := exec.LookPath("rpm") + _, err := exec.LookPath("rpmspec") if err != nil { - return "" + return "", fmt.Errorf("Could not find rpmspec program in PATH") } - _, err = exec.LookPath("rpmbuild") + // Read the first file from SPECS/ to get our spec file + // (there should only be one file - we check that it ends in ".spec" just to be sure!) + lsTmp, err := ioutil.ReadDir(fmt.Sprintf("%s/SPECS/", localRepo)) if err != nil { - return "" + return "", err + } + specFile := lsTmp[0].Name() + + if !strings.HasSuffix(specFile, ".spec") { + return "", fmt.Errorf("First file found in SPECS/ is not a .spec file! Check the SPECS/ directory in the repo?") } - _, err = exec.LookPath("cp") - if err != nil { - return "" + // Call the rpmspec binary to extract the version-release info out of it, and tack on ".el" at the end: + cmdArgs := []string{ + "--srpm", + fmt.Sprintf(`--define=dist .el%d`, majorVersion), + "-q", + "--queryformat", + `%{NAME}|%{VERSION}|%{RELEASE}\n`, + fmt.Sprintf("%s/SPECS/%s", localRepo, specFile), } - - // create separate temp folder space to do our RPM work - we don't want to accidentally contaminate the main Git area: - rpmBuildPath := fmt.Sprintf("%s_rpm", localRepo) - os.Mkdir(rpmBuildPath, 0o755) - - // Copy SOURCES/ and SPECS/ into the temp rpmbuild directory recursively - // Yes, we could create or import an elaborate Go-native way to do this, but damnit this is easier: - cmdArgs := strings.Fields(fmt.Sprintf("cp -rp %s/SOURCES %s/SPECS %s/", localRepo, localRepo, rpmBuildPath)) - if err := exec.Command(cmdArgs[0], cmdArgs[1:]...).Run(); err != nil { - log.Println(err) - return "" - } - - // Loop through ..metadata and get the file names we need to make our SRPM: - lookAside, err := os.Open(fmt.Sprintf("%s/.%s.metadata", localRepo, pkgName)) - if err != nil { - log.Println(err) - return "" - } - - // Split file into lines and start processing: - scanner := bufio.NewScanner(lookAside) - scanner.Split(bufio.ScanLines) - - // loop through each line, and: - // - isolate the SOURCES/filename entry - // - write out a dummy file of the same name to rpmBuildPath/SOURCES - for scanner.Scan() { - - // lookaside source is always the 2nd part of the line (after the long SHA sum) - srcFile := strings.Fields(scanner.Text())[1] - - // write a dummy file of the same name into the rpmbuild SOURCES/ directory: - dummyFile, err := os.OpenFile(fmt.Sprintf("%s/%s", rpmBuildPath, srcFile), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) - if err != nil { - return "" - } - writer := bufio.NewWriter(dummyFile) - _, _ = writer.WriteString("This is a dummy lookaside file generated by srpmproc. It is only needed to get a working SRPM and extract version information. Please disregard\n") - writer.Flush() - dummyFile.Close() - } - - lookAside.Close() - - // Now, call rpmbuild to produce the dummy src file: - // Example: rpmbuild --define "_topdir /tmp/srpmproctmp_httpd1988142783_rpm" -bs /tmp/srpmproctmp_httpd1988142783_rpm/SPECS/*.spec - cmd := exec.Command("rpmbuild", fmt.Sprintf(`--define=_topdir %s`, rpmBuildPath), fmt.Sprintf(`--define=dist .el%d`, majorVersion), "-bs", fmt.Sprintf("%s/SPECS/%s.spec", rpmBuildPath, pkgName)) - if err := cmd.Run(); err != nil { - log.Println(err) - return "" - } - - // Read the first file from the SRPMS/ folder in rpmBuildPath. It should be the SRPM that rpmbuild produced above - // (there should only be one file - we check that it ends in ".rpm" just to be sure!) - lsTmp, err := ioutil.ReadDir(fmt.Sprintf("%s/SRPMS/", rpmBuildPath)) - if err != nil { - log.Println(err) - return "" - } - - srpmFile := lsTmp[0].Name() - - if !strings.HasSuffix(srpmFile, ".rpm") { - log.Println("Error, file found in dummy SRPMS directory did not have an .rpm extension! Perhaps rpmbuild didn't produce a proper source RPM?") - return "" - } - - // Call the rpm binary to extract the version-release info out of it, and tack on ".el" at the end: - cmd = exec.Command("rpm", "-qp", "--qf", `%{NAME}|%{VERSION}|%{RELEASE}\n`, fmt.Sprintf("%s/SRPMS/%s", rpmBuildPath, srpmFile)) + cmd := exec.Command("rpmspec", cmdArgs...) nvrTmp, err := cmd.CombinedOutput() if err != nil { - log.Println("Error running rpm command to extract temporary SRPM name-version-release identifiers.") - log.Println("rpmbuild output: ", string(nvrTmp)) - log.Println("rpmbuild command: ", cmd.String()) - return "" + return "", fmt.Errorf("Error running rpmspec command to determine RPM name-version-release identifier. \nCommand attempted: %s \nCommand output: %s", cmd.String(), string(nvrTmp)) } - // Pull first line of the rpm command's output to get the name-version-release number (there should only be 1 line) + // Pull first line of the version output to get the name-version-release number (there should only be 1 line) nvr := string(nvrTmp) nvr = strings.Fields(nvr)[0] - // Clean up: delete the temporary directory - if err := os.RemoveAll(rpmBuildPath); err != nil { - log.Printf("Error cleaning up temporary RPM directory %s . Non-fatal, continuing anyway...\n", rpmBuildPath) - } - // return name-version-release string we derived: - log.Printf("Derived NVR %s from tagless repo via temporary SRPM build\n", nvr) - return nvr + log.Printf("Derived NVR %s from tagless repo via rpmspec command\n", nvr) + return nvr, nil } // We need to loop through the lookaside blob files ("SourcesToIgnore"),