Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support individual patch application in %autopatch #1697

Merged
merged 3 commits into from
Jun 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
89 changes: 73 additions & 16 deletions docs/manual/autosetup.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ title: rpm.org - Automating patch application in specs

## %autosetup description

Starting with version 4.11, RPM has a set of new macros to further automate source unpacking and patch application. Previously one had to manually specify each patch to be applied, eg
Starting with version 4.11, RPM has a set of new macros to further
automatesource unpacking and patch application. Previously one had to
manually specify each patch to be applied, eg

```
%prep
Expand All @@ -18,43 +20,97 @@ Starting with version 4.11, RPM has a set of new macros to further automate sour
%patch149
```

This can get rather tedious when the number of patches is large. The new %autosetup macro allows taking care of all this in a single step: the following applies all the patches declared in the spec, ordered by the patch number:
This can get rather tedious when the number of patches is large. The new
`%autosetup` macro allows taking care of all this in a single step: the
following applies all the patches declared in the spec, ordered by the patch
number:

```
%prep
%autosetup
```

In addition to automating plain old "patch" command invocations, %autosetup allows utilizing various version control systems such as git, mercurial (aka hg), quilt and bzr for managing the build directory source. For example this unpacks the vanilla source, initializes a git repository in the build directory and then applies all the patches defined in the spec using individual git apply + commits:
In addition to automating plain old `patch` command invocations, `%autosetup`
allows utilizing various version control systems such as git, mercurial (aka
hg), quilt and bzr for managing the build directory source. For example this
unpacks the vanilla source, initializes a git repository in the build
directory and then applies all the patches defined in the spec using
individual git apply + commits:

```
%autosetup -S git
```

The resulting build directory can be used for bisecting problems introduced in patches, and developing new patches from the build directory is more natural than with gendiff.
The resulting build directory can be used for bisecting problems introduced
in patches, and developing new patches from the build directory is more
natural than with gendiff.

## %autosetup options

Generally %autosetup accepts the same arguments as %setup does. The notable exceptions are

* %autosetup defaults to quiet operation, so -q is not needed or accepted. Use -v to enable verbose source unpacking if needed.
* -N disables automatic patch application if necessary for some reason. If %autosetup is called with -N, the patch-application phase can be manually invoked with %autopatch macro.
* -S<vcs> specifies the VCS to use. Currently supported VCSes are: "git", "hg" (for mercurial), "bzr", "quilt" and "patch", "git_am" (rpm >= 4.12) and "gendiff" (rpm >= 4.14). If -S is omitted, %autosetup defaults to "patch"
* -p<number> argument to control patch prefix stripping (same as -p to %patch)
* -b (for creating patch backups) is accepted but currently ignored - this is not meaningful for a full-blown VCS anyway. If you need backups for gendiff use, use "gendiff" backend.

Note that the exact behavior of -S option depends on the used VCS: for example quilt only controls patches whereas git and mercurial control the entire source repository.
Generally `%autosetup` accepts the same arguments as %setup does. The notable
exceptions are

* `%autosetup` defaults to quiet operation, so `-q` is not needed or accepted.
Use `-v` to enable verbose source unpacking if needed.
* `-N` disables automatic patch application if necessary for some reason. If
`%autosetup` is called with `-N`, the patch-application phase can be
manually invoked with `%autopatch` macro.
* `-S<vcs>` specifies the VCS to use. Currently supported VCSes are: `git`,
`hg` (for mercurial), `bzr`, `quilt`, `patch`, `git_am` (rpm >= 4.12)
and `gendiff` (rpm >= 4.14). If `S` is omitted, `%autosetup` defaults to
`patch`
* `-p<number>` argument to control patch prefix stripping (same as
`-p` to `%patch`)
* `-b` (for creating patch backups) is accepted but currently ignored -
this is not meaningful for a full-blown VCS anyway. If you need backups
for `gendiff` use, use `gendiff` backend.

Note that the exact behavior of `-S` option depends on the used VCS: for
example quilt only controls patches whereas git and mercurial control the
entire source repository.

## %autopatch

Sometimes you need more control than just "apply all", in which case you
can call `%autopatch` directly. By default it simply applies all patches
in the order declared in the spec, but you can additionally control the
range with options, or pass patch numbers as arguments. The supported
options are

* `-v` verbose operation
* `-p<number>` argument to control patch prefix stripping (same as
`-p` to `%patch`, normally passed down from `%autosetup`)
* `-m<number>` Apply patches starting from `<number>` range
* `-M<number>` Apply patches up to `<number>` range

Some examples:

# Apply patches with number >= 100
`%autopatch -m 100`
# Apply patches with number <= 400
`%autopatch -M 400`
# Apply patches 80 to 99
`%autopatch -m 80 -99`
# Apply patches 1, 4 and 6
`%autopatch 1 4 6`

## Automating patch (and source) declarations

While typically patch and source names tend to be descriptive for humans, making automating the declarations impossible, some upstreams (for example bash and vim) provide bugfixes by serially numbered patches. In such cases automation can be taken one step further by programmatically generating the patch declarations as well. As of this writing there are no specific helper macros for performing this, but for example the embedded Lua interpreter can be used for the purpose:
While typically patch and source names tend to be descriptive for humans,
making automating the declarations impossible, some upstreams (for example
bash and vim) provide bugfixes by serially numbered patches. In such cases
automation can be taken one step further by programmatically generating the
patch declarations as well. As of this writing there are no specific helper
macros for performing this, but for example the embedded Lua interpreter can
be used for the purpose:

```
%{lua:for i=1,45 do print(string.format("Patch%u: bash42-%03u\n", i, i)) end}
```


On spec parse, the above expands to as many patch declarations (best inspected with `rpmspec --parse <spec>`):
On spec parse, the above expands to as many patch declarations (best
inspected with `rpmspec --parse <spec>`):

```
Patch1: bash42-001
Expand All @@ -65,4 +121,5 @@ Patch4: bash42-004
Patch45: bash42-045
```

Combined with %autosetup, this can eliminate a very large number of repetitive spec lines, making package maintenance that little bit easier.
Combined with `%autosetup`, this can eliminate a very large number of
repetitive spec lines, making package maintenance that little bit easier.
50 changes: 33 additions & 17 deletions macros.in
Original file line number Diff line number Diff line change
Expand Up @@ -1225,23 +1225,39 @@ else\
print("echo 'Cannot read "..file.."'; exit 1;".."\\n")\
end}

# Automatically apply all patches
# Patches are applied in the order they are listed in the spec file
# not by their number!
# -m<min> Apply patches with number >= min only
# -M<max> Apply patches with number <= max only
%autopatch(vp:m:M:)\
%{lua:\
local options = rpm.expand("%{!-v:-q} %{-p:-p%{-p*}} ")\
local low_limit = tonumber(rpm.expand("%{-m:%{-m*}}"))\
local high_limit = tonumber(rpm.expand("%{-M:%{-M*}}"))\
for i, p in ipairs(patches) do\
local inum = patch_nums[i]\
if ((not low_limit or inum>=low_limit) and (not high_limit or inum<=high_limit)) \
then\
print(rpm.expand("%__apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n")) \
end\
end}
# Apply patches using %autosetup configured SCM.
# Typically used with no arguments to apply all patches in the order
# introduced in the spec, but alternatively can be used to apply indvidual
# patches in arbitrary order by passing them as arguments.
# -v Verbose
# -p<N> Prefix strip (ie patch -p argument)
# -m<min> Apply patches with number >= min only (if no arguments)
# -M<max> Apply patches with number <= max only (if no arguments)
%autopatch(vp:m:M:) %{lua:
if #arg == 0 then
local lo = tonumber(rpm.expand("%{-m:%{-m*}}"))
local hi = tonumber(rpm.expand("%{-M:%{-M*}}"))
for i, n in ipairs(patch_nums) do
if ((not lo or n >= lo) and (not hi or n <= hi)) then
table.insert(arg, n)
end
end
end
local options = rpm.expand("%{!-v:-q} %{-p:-p%{-p*}} ")
local bynum = {}
for i, p in ipairs(patches) do
bynum[patch_nums[i]] = p
end
for i, a in ipairs(arg) do
local p = bynum[a]
if p then
print(rpm.expand("%__apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n"))
else
macros.error({"no such patch "..a})
end
end
}


# One macro to (optionally) do it all.
# -S<scm name> Sets the used patch application style, eg '-S git' enables
Expand Down