Skip to content

Commit 6f1b81b

Browse files
committed
wrap: Add support for applying a list of patch files
1 parent 6337e40 commit 6f1b81b

File tree

8 files changed

+178
-1
lines changed

8 files changed

+178
-1
lines changed

docs/markdown/Wrap-dependency-system-manual.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,34 @@ With such wrap file, `find_program('myprog')` will automatically
247247
fallback to use the subproject, assuming it uses
248248
`meson.override_find_program('myprog')`.
249249

250+
## Patch files
251+
252+
*Since: 0.59.0*
253+
254+
A list of local patch files can be provided in the `[patch-files]` section. They
255+
will be applied after the project has been extracted or cloned, and after the
256+
`patch_filename` has been applied. `git` or `patch` command-line tool must be
257+
available.
258+
259+
The `[patch-files]` section is optional and might contain the following keys:
260+
- `strip`: Number of leading components from file names to strip. Defaults to 1
261+
if omitted.
262+
- `patches`: A list of patch filenames relative to `subprojects` directory.
263+
It must be in the python string list format (e.g. `['foo', 'bar']`).
264+
265+
```ini
266+
[wrap-file]
267+
directory = libfoobar-1.0
268+
269+
source_url = https://example.com/foobar-1.0.tar.gz
270+
source_filename = foobar-1.0.tar.gz
271+
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663
272+
273+
[patch-files]
274+
strip = 1
275+
patches = ['0001.patch', '0002.patch']
276+
```
277+
250278
## Using wrapped projects
251279

252280
Wraps provide a convenient way of obtaining a project into your
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## Wrap files can contain a list of patch files to apply
2+
3+
A list of local patch files can be provided by the `.wrap` file and they will be
4+
applied after the subproject has been extracted or cloned from git. This requires
5+
the `patch` or `git` command-line tool.
6+
7+
```ini
8+
[wrap-file]
9+
directory = libfoobar-1.0
10+
11+
source_url = https://example.com/foobar-1.0.tar.gz
12+
source_filename = foobar-1.0.tar.gz
13+
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663
14+
15+
[patch-files]
16+
strip = 1
17+
patches = ['0001.patch', '0002.patch']
18+
```

mesonbuild/wrap/wrap.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@
2727
import configparser
2828
import typing as T
2929
import textwrap
30+
import ast
3031

3132
from pathlib import Path
3233
from . import WrapMode
3334
from .. import coredata
34-
from ..mesonlib import quiet_git, GIT, ProgressBar, MesonException
35+
from ..mesonlib import quiet_git, GIT, ProgressBar, MesonException, Popen_safe
3536
from .. import mesonlib
3637

3738
if T.TYPE_CHECKING:
@@ -51,6 +52,8 @@
5152

5253
ALL_TYPES = ['file', 'git', 'hg', 'svn']
5354

55+
PATCH = shutil.which('patch')
56+
5457
def whitelist_wrapdb(urlstr: str) -> urllib.parse.ParseResult:
5558
""" raises WrapException if not whitelisted subdomain """
5659
url = urllib.parse.urlparse(urlstr)
@@ -96,6 +99,8 @@ def __init__(self, fname: str):
9699
self.values = {} # type: T.Dict[str, str]
97100
self.provided_deps = {} # type: T.Dict[str, T.Optional[str]]
98101
self.provided_programs = [] # type: T.List[str]
102+
self.patches: T.List[str] = []
103+
self.strip = 1
99104
self.basename = os.path.basename(fname)
100105
self.has_wrap = self.basename.endswith('.wrap')
101106
self.name = self.basename[:-5] if self.has_wrap else self.basename
@@ -139,6 +144,7 @@ def parse_wrap(self) -> None:
139144
self.parse_wrap()
140145
return
141146
self.parse_provide_section(config)
147+
self.parse_patch_files_section(config)
142148

143149
def parse_wrap_section(self, config: configparser.ConfigParser) -> None:
144150
if len(config.sections()) < 1:
@@ -171,6 +177,12 @@ def parse_provide_section(self, config: configparser.ConfigParser) -> None:
171177
raise WrapException(m.format(k, self.basename))
172178
self.provided_deps[k] = v
173179

180+
def parse_patch_files_section(self, config: configparser.ConfigParser) -> None:
181+
if config.has_section('patch-files'):
182+
values = config['patch-files']
183+
self.patches = ast.literal_eval(values.get('patches', '[]'))
184+
self.strip = int(values.get('strip', self.strip))
185+
174186
def get(self, key: str) -> str:
175187
try:
176188
return self.values[key]
@@ -582,6 +594,30 @@ def apply_patch(self) -> None:
582594
if not os.path.isdir(src_dir):
583595
raise WrapException(f'patch directory does not exists: {patch_dir}')
584596
self.copy_tree(src_dir, self.dirname)
597+
for p in self.wrap.patches:
598+
from ..interpreterbase import FeatureNew
599+
FeatureNew('patch-files section', '0.59.0').use(self.current_subproject)
600+
mlog.log(f'Applying patch {p}')
601+
fname = os.path.join(self.wrap.filesdir, p)
602+
if GIT:
603+
if self.wrap.type == 'git':
604+
# Assume patches are made with `git format-patch`
605+
cmd = [GIT, 'am', fname]
606+
else:
607+
# `git apply` can be used outside of a git repository, but
608+
# when used inside a git repository paths are assumed to be
609+
# relative to root git dir instead of current working dir.
610+
# Override that behaviour by using --work-tree.
611+
cmd = [GIT, '--work-tree', self.dirname, 'apply', fname]
612+
elif PATCH:
613+
cmd = [PATCH, '-f', '-i', fname]
614+
else:
615+
raise WrapException('Missing "git" or "patch" commands to apply patch files')
616+
cmd += ['-p' + str(self.wrap.strip), '--ignore-whitespace']
617+
p, o, e = Popen_safe(cmd, cwd=self.dirname, stderr=subprocess.STDOUT)
618+
if p.returncode != 0:
619+
mlog.log(o.strip())
620+
raise WrapException('Failed to apply patch')
585621

586622
def copy_tree(self, root_src_dir: str, root_dst_dir: str) -> None:
587623
"""

test cases/common/153 wrap file should not failed/meson.build

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ executable('grabprog2', files('src/subprojects/foo/prog2.c'))
1414
subdir('src')
1515

1616
subproject('patchdir')
17+
18+
if find_program('patch', required : false).found() or find_program('git', required : false).found()
19+
exe = subproject('patchfile').get_variable('foo_exe')
20+
test('test_foo', exe)
21+
endif
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
From b79f6cc4a096f6c2888f73b947b652491885896a Mon Sep 17 00:00:00 2001
2+
From: Xavier Claessens <[email protected]>
3+
Date: Fri, 30 Nov 2018 14:13:47 -0500
4+
Subject: [PATCH] Change foo to executable
5+
6+
---
7+
foo.c | 4 ++++
8+
meson.build | 2 +-
9+
2 files changed, 5 insertions(+), 1 deletion(-)
10+
11+
diff --git a/foo.c b/foo.c
12+
index 54f9119..468f033 100644
13+
--- a/foo.c
14+
+++ b/foo.c
15+
@@ -1,3 +1,7 @@
16+
int dummy_func(void) {
17+
return 44;
18+
}
19+
+
20+
+int main(int argc, char *argv[]) {
21+
+ return dummy_func() == 44 ? 0 : 1;
22+
+}
23+
diff --git a/meson.build b/meson.build
24+
index 318e81d..4a281d9 100644
25+
--- a/meson.build
26+
+++ b/meson.build
27+
@@ -1,2 +1,2 @@
28+
project('static lib patchdir', 'c')
29+
-libfoo = static_library('foo', 'foo.c')
30+
+foo_exe = executable('foo', 'foo.c')
31+
--
32+
2.17.1
33+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
From 7001dcc738e5ae7dfa8af20ed582b9a985804f72 Mon Sep 17 00:00:00 2001
2+
From: Xavier Claessens <[email protected]>
3+
Date: Fri, 30 Nov 2018 10:15:33 -0500
4+
Subject: [PATCH 1/2] Change return value to 43
5+
6+
---
7+
foo.c | 2 +-
8+
1 file changed, 1 insertion(+), 1 deletion(-)
9+
10+
diff --git a/foo.c b/foo.c
11+
index 019f2ba..e4577b8 100644
12+
--- a/foo.c
13+
+++ b/foo.c
14+
@@ -1,3 +1,3 @@
15+
int dummy_func(void) {
16+
- return 42;
17+
+ return 43;
18+
}
19+
--
20+
2.17.1
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
From c2da2e490b09f2e251c7f4ef7c1240acee215fec Mon Sep 17 00:00:00 2001
2+
From: Xavier Claessens <[email protected]>
3+
Date: Fri, 30 Nov 2018 10:15:47 -0500
4+
Subject: [PATCH 2/2] Change return value to 44
5+
6+
---
7+
foo.c | 2 +-
8+
1 file changed, 1 insertion(+), 1 deletion(-)
9+
10+
diff --git a/foo.c b/foo.c
11+
index e4577b8..54f9119 100644
12+
--- a/foo.c
13+
+++ b/foo.c
14+
@@ -1,3 +1,3 @@
15+
int dummy_func(void) {
16+
- return 43;
17+
+ return 44;
18+
}
19+
--
20+
2.17.1
21+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[wrap-file]
2+
directory = foo-1.0-patchfile
3+
4+
source_url = http://something.invalid
5+
source_filename = foo-1.0.tar.xz
6+
source_hash = 9ed8f67d75e43d3be161efb6eddf30dd01995a958ca83951ea64234bac8908c1
7+
lead_directory_missing = true
8+
9+
patch_directory = foo-1.0
10+
11+
[patch-files]
12+
patches = ['patchfile/0001-Change-return-value-to-43.patch',
13+
'patchfile/0002-Change-return-value-to-44.patch',
14+
'patchfile/0001-Change-foo-to-executable.patch',
15+
]

0 commit comments

Comments
 (0)