#738 Multiple issues with 'patch' subcommand
Opened by ferdnyc. Modified

I initially reported this in bugzilla against fedpkg, but I suspect the issue, and thus the fix, really lives with rpkg itself. Also, in debugging the first issue I discovered more problems with 'patch' that make me think it hasn't worked in a long time, nor has anyone been using it to notice it's broken.

Problem 1: path issues

The switch to fedpkg prep / fedpkg local extracting and building package sources inside a %{name}-%{version}-build/%{name}-%{version}/ subdirectory broke the fedpkg patch command, which (as implemented in pyrpkg) expects there to be a top-level %{name}-%{version} directory next to the spec file.

To Reproduce: Start with a fedpkg clone of any package (let's use fedpkg itself...), and attempt to create a patch using a fake modified setup.py.edited:

fedpkg clone fedpkg
cd fedpkg
fedpkg prep  # creates the directory fedpkg-1.46-build/fedpkg-1.46/
cp fedpkg-1.46-build/fedpkg-1.46/setup.py \
   fedpkg-1.46-build/fedpkg-1.46/setup.py.edited
fedpkg patch edited

This will output:

Could not execute patch: Expanded source dir not found!

Because the fedpkg patch command still expects the extracted source to be in ./fedpkg-1.46/, not ./fedpkg-1.46-build/fedpkg-1.46.

So, let's move it there:

mv fedpkg-1.46-build/fedpkg-1.46 .
fedpkg patch edited

Problem 2: Attempting to write bytes to a text-mode output file

This time, we get the message:

Could not execute patch: write() argument must be str, not bytes

If we run with debugging (fedpkg -d -v -v patch edited), we get more details:

Creating repo object from /tmp/fedpkg
Initiating a koji session to https://koji.fedoraproject.org/kojihub
Running gendiff fedpkg-1.46 .edited
Could not execute patch: write() argument must be str, not bytes
Traceback (most recent call last):
  File "/usr/bin/fedpkg", line 33, in <module>
    sys.exit(load_entry_point('fedpkg==1.46', 'console_scripts', 'fedpkg')())
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/fedpkg/__main__.py", line 84, in main
    sys.exit(client.args.command())
             ~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/pyrpkg/cli.py", line 2878, in patch
    self.cmd.patch(self.args.suffix, rediff=self.args.rediff)
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/pyrpkg/__init__.py", line 2208, in patch
    open(os.path.join(self.path, outfile), 'w').write(output)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
TypeError: write() argument must be str, not bytes

The output returned from the subprocess.Popen() call that runs the patch utility is a bytes object, not a str, so the output file has to be opened 'wb' to write output into it. This change fixes writing the patch file, but not the previous extracted-sources-path issue:

--- /tmp/pyrpkg_init.orig.py    2025-04-02 03:19:24.828275435 -0400
+++ /tmp/pyrpkg_init.py 2025-04-02 03:22:44.750433198 -0400
@@ -2205,7 +2205,8 @@
             output = ''.join(newhead) + output
         # Write out the patch
-        open(os.path.join(self.path, outfile), 'w').write(output)
+        with open(os.path.join(self.path, outfile), 'wb') as patchout:
+            patchout.write(output)
         # Add it to the index
         # Again this returns a blank line we want to keep quiet

Metadata