From ebb5c4b82caec5160544fdbb2d539fd1b5a3abfb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
Date: Thu, 5 Oct 2023 16:59:22 +0200
Subject: [PATCH 2/5] *pkg import: Undo rpmautospec processing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes https://pagure.io/fedpkg/issue/527
Depends-on: https://pagure.io/fedora-infra/rpmautospec/pull-request/312
Signed-off-by: Miro HronĨok <miro@hroncok.cz>
---
pyrpkg/__init__.py | 22 ++++++-------
pyrpkg/utils.py | 77 ++++++++++++++++++++++++++++++++++++++++------
2 files changed, 78 insertions(+), 21 deletions(-)
diff --git a/pyrpkg/__init__.py b/pyrpkg/__init__.py
index b257fec..f562e71 100644
--- a/pyrpkg/__init__.py
+++ b/pyrpkg/__init__.py
@@ -53,7 +53,7 @@ from pyrpkg.sources import SourcesFile
from pyrpkg.spec import SpecFile
from pyrpkg.utils import (cached_property, extract_srpm, find_me,
is_file_tracked, is_lookaside_eligible_file,
- log_result, spec_file_processed_by_rpmautospec)
+ log_result, spec_file_undo_rpmautospec)
from .gitignore import GitIgnore
@@ -1473,16 +1473,6 @@ class Commands(object):
uploadfiles.append(file)
else:
files.append(file)
-
- # Check all specfiles in SRPM. At this point (the 'import' command can run under
- # the dist-git repo without any specfiles - right after initialization) we are
- # not able determine which the main specfile is.
- if file.endswith('.spec') and not file.startswith('.') \
- and not self.allow_pre_generated_srpm \
- and spec_file_processed_by_rpmautospec(file, target_dir):
- raise rpkgError('SRPM was processed by rpmautospec '
- '(specfile "{}" was analyzed)'.format(file))
-
finally:
shutil.rmtree(target_dir)
@@ -2081,6 +2071,16 @@ class Commands(object):
os.chdir(oldpath)
raise rpkgError("Got an error from rpm2cpio: %s" % err)
+ # Undo rpmautospec from all the spec files.
+ # At this point (the 'import' command can run under the dist-git repo
+ # without any specfiles - right after initialization) we are
+ # not able determine which the main specfile is.
+ if not self.allow_pre_generated_srpm:
+ for file in files:
+ if file.endswith('.spec') and not file.startswith('.'):
+ if spec_file_undo_rpmautospec(file):
+ self.log.debug("rpmautospec processing removed from {0}".format(file))
+
# And finally add all the files we know about (and our stock files)
for file in ('.gitignore', 'sources'):
if not os.path.exists(file):
diff --git a/pyrpkg/utils.py b/pyrpkg/utils.py
index 3337bdb..f3c8b25 100644
--- a/pyrpkg/utils.py
+++ b/pyrpkg/utils.py
@@ -336,22 +336,79 @@ def is_lookaside_eligible_file(file_name, dir_path=None):
return encoding == "binary"
-def spec_file_processed_by_rpmautospec(file_name, dir_path=None):
+def _replace_lines(lines, startline, endline, replacement_lines=None, strip_endline=False):
+ replacement_lines = replacement_lines or []
+ try:
+ start = lines.index(startline)
+ end = lines.index(endline, start)
+ except ValueError:
+ # if both are missing, nothing to do, all good
+ # if only one of them is present, we better not touch it
+ return lines, False
+ else:
+ # rpmautospec adds an empty line after the end
+ # we want to remove it, but only if it is actually empty
+ if strip_endline and lines[end+1] == "\n":
+ end += 1
+ lines = lines[:start] + replacement_lines + lines[end+1:]
+ return lines, True
+
+
+def spec_file_undo_rpmautospec(file_name, dir_path=None):
+ """
+ Given a path to specfile, undo changes generated by rpmautospec.
+ Iff there is something to undo, the specfile will be overwritten.
+
+ Namely:
+
+ 1. Removes everything between the following lines:
+ ## START: Set by rpmautospec
+ ## END: Set by rpmautospec
+ 2. Replaces everything between the following lines with %autochangelog:
+ ## START: Generated by rpmautospec
+ ## END: Generated by rpmautospec
+
+ Both of the steps only happen once. If the specfile contains multiple such sections,
+ only the first one is removed/replaced.
+
+ The saved spec file is not guaranteed to be bit-by-bit identical with the original
+ spec file used as an input to rpmautospec.
+ However, subsequent repeated conversions there and back should be quite stable.
+
+ The return value says whether the specfile was overwritten.
+ """
file_path = os.path.join(dir_path or "", file_name)
try:
- contents = open(file_path).readlines()
+ with open(file_path) as f:
+ contents = f.readlines()
except Exception:
- # if we can't read it, let's assume the answer is "no".
+ # if we can't read it, let's do nothing
return False
- # Check for the %autorelease header prepended to the file
- if any('START: Set by rpmautospec' in line for line in contents[:10]):
+ # remove the generated macro section near the beginning of the specfile
+ contents, was_removed = _replace_lines(
+ contents,
+ '## START: Set by rpmautospec\n',
+ '## END: Set by rpmautospec\n',
+ strip_endline=True)
+
+ # replace the generated changelog with %autochangelog
+ # note that this does not generally produce content identical to the original
+ # e.g. the macro could have been conditionalized or in curly brackets
+ # most importantly, the %changelog section might have been omitted entirely
+ # however, this should be Good Enough for most of us
+ contents, was_replaced = _replace_lines(
+ contents,
+ '## START: Generated by rpmautospec\n',
+ '## END: Generated by rpmautospec\n',
+ ['%autochangelog\n'])
+
+ # finally, replace the spec if needed
+ # if we cannot write it, better blow up
+ if was_removed or was_replaced:
+ with open(file_path, 'w') as f:
+ f.writelines(contents)
return True
- # It seems that currently there's no mechanism to detect
- # %autochangelog processing. But most packages would use both
- # %autochangelog and %autorelease together, so we should catch
- # most cases by checking for %autorelease only.
- # https://pagure.io/fedora-infra/rpmautospec/issue/269
return False
--
2.41.0