Sat Oct 12 17:38:16 2019 UTC ()
pkgtools/url2pkg: rename type Url2Pkg to Globals


(rillig)
diff -r1.20 -r1.21 pkgsrc/pkgtools/url2pkg/files/url2pkg.py
diff -r1.19 -r1.20 pkgsrc/pkgtools/url2pkg/files/url2pkg_test.py

cvs diff -r1.20 -r1.21 pkgsrc/pkgtools/url2pkg/files/url2pkg.py (switch to unified diff)

--- pkgsrc/pkgtools/url2pkg/files/url2pkg.py 2019/10/12 17:28:44 1.20
+++ pkgsrc/pkgtools/url2pkg/files/url2pkg.py 2019/10/12 17:38:16 1.21
@@ -1,995 +1,995 @@ @@ -1,995 +1,995 @@
1#! @PYTHONBIN@ 1#! @PYTHONBIN@
2# $NetBSD: url2pkg.py,v 1.20 2019/10/12 17:28:44 rillig Exp $ 2# $NetBSD: url2pkg.py,v 1.21 2019/10/12 17:38:16 rillig Exp $
3 3
4# Copyright (c) 2019 The NetBSD Foundation, Inc. 4# Copyright (c) 2019 The NetBSD Foundation, Inc.
5# All rights reserved. 5# All rights reserved.
6# 6#
7# This code is derived from software contributed to The NetBSD Foundation 7# This code is derived from software contributed to The NetBSD Foundation
8# by Roland Illig. 8# by Roland Illig.
9# 9#
10# Redistribution and use in source and binary forms, with or without 10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions 11# modification, are permitted provided that the following conditions
12# are met: 12# are met:
13# 1. Redistributions of source code must retain the above copyright 13# 1. Redistributions of source code must retain the above copyright
14# notice, this list of conditions and the following disclaimer. 14# notice, this list of conditions and the following disclaimer.
15# 2. Redistributions in binary form must reproduce the above copyright 15# 2. Redistributions in binary form must reproduce the above copyright
16# notice, this list of conditions and the following disclaimer in the 16# notice, this list of conditions and the following disclaimer in the
17# documentation and/or other materials provided with the distribution. 17# documentation and/or other materials provided with the distribution.
18# 18#
19# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29# POSSIBILITY OF SUCH DAMAGE. 29# POSSIBILITY OF SUCH DAMAGE.
30 30
31 31
32# Overview 32# Overview
33# 33#
34# The url2pkg program gets a URL and produces a pkgsrc package from it, 34# The url2pkg program gets a URL and produces a pkgsrc package from it,
35# filling in several defaults in order to reduce the amount of manual work. 35# filling in several defaults in order to reduce the amount of manual work.
36# 36#
37# This happens in two phases. Phase 1 is done by the Generator and generates 37# This happens in two phases. Phase 1 is done by the Generator and generates
38# an initial Makefile, just enough to download the distfile. Phase 2 then 38# an initial Makefile, just enough to download the distfile. Phase 2 then
39# takes the generated Makefile and applies various adjustments for different 39# takes the generated Makefile and applies various adjustments for different
40# types of packages, such as Perl or Python modules. This is done by the 40# types of packages, such as Perl or Python modules. This is done by the
41# Adjuster class. 41# Adjuster class.
42 42
43 43
44import getopt 44import getopt
45import os 45import os
46import re 46import re
47import subprocess 47import subprocess
48import sys 48import sys
49from pathlib import Path 49from pathlib import Path
50from typing import Any, Callable, Dict, List, NamedTuple, Optional, Tuple, Union 50from typing import Any, Callable, Dict, List, NamedTuple, Optional, Tuple, Union
51 51
52 52
53class Var(NamedTuple): 53class Var(NamedTuple):
54 """ An abstract variable assignment for the package Makefile. """ 54 """ An abstract variable assignment for the package Makefile. """
55 name: str 55 name: str
56 op: str 56 op: str
57 value: str 57 value: str
58 58
59 59
60class Varassign(NamedTuple): 60class Varassign(NamedTuple):
61 """ A variable assignment including layout information. """ 61 """ A variable assignment including layout information. """
62 index: int 62 index: int
63 varname: str 63 varname: str
64 op: str 64 op: str
65 indent: str 65 indent: str
66 value: str 66 value: str
67 space_after_value: str 67 space_after_value: str
68 comment: str 68 comment: str
69 69
70 70
71class Url2Pkg: 71class Globals:
72 make: str 72 make: str
73 libdir: str 73 libdir: str
74 perl5: str 74 perl5: str
75 pkgsrcdir: Union[Path, Any] 75 pkgsrcdir: Union[Path, Any]
76 pythonbin: str 76 pythonbin: str
77 editor: str 77 editor: str
78 pkgdir: Union[Path, Any] 78 pkgdir: Union[Path, Any]
79 out: Any 79 out: Any
80 err: Any 80 err: Any
81 verbose: bool 81 verbose: bool
82 82
83 def __init__(self): 83 def __init__(self):
84 self.make = os.getenv('MAKE') or '@MAKE@' 84 self.make = os.getenv('MAKE') or '@MAKE@'
85 self.libdir = '@LIBDIR@' 85 self.libdir = '@LIBDIR@'
86 self.perl5 = '@PERL5@' 86 self.perl5 = '@PERL5@'
87 self.pkgsrcdir = Path(os.getenv('PKGSRCDIR') or '@PKGSRCDIR@') 87 self.pkgsrcdir = Path(os.getenv('PKGSRCDIR') or '@PKGSRCDIR@')
88 self.pythonbin = '@PYTHONBIN@' 88 self.pythonbin = '@PYTHONBIN@'
89 self.editor = os.getenv('PKGEDITOR') or os.getenv('EDITOR') or 'vi' 89 self.editor = os.getenv('PKGEDITOR') or os.getenv('EDITOR') or 'vi'
90 90
91 # the following are overridden in tests 91 # the following are overridden in tests
92 self.pkgdir = Path('.') 92 self.pkgdir = Path('.')
93 self.out = sys.stdout 93 self.out = sys.stdout
94 self.err = sys.stderr 94 self.err = sys.stderr
95 95
96 self.verbose = False 96 self.verbose = False
97 97
98 def debug(self, fmt: str, *args): 98 def debug(self, fmt: str, *args):
99 if self.verbose: 99 if self.verbose:
100 msg = fmt.format(*map(repr, args)) if len(args) else fmt 100 msg = fmt.format(*map(repr, args)) if len(args) else fmt
101 self.err.write(f'url2pkg: {msg}\n') 101 self.err.write(f'url2pkg: {msg}\n')
102 102
103 def find_package(self, pkgbase: str) -> str: 103 def find_package(self, pkgbase: str) -> str:
104 candidates = list(self.pkgsrcdir.glob(f'*/{pkgbase}')) 104 candidates = list(self.pkgsrcdir.glob(f'*/{pkgbase}'))
105 self.debug('candidates for package {0} are {1}', pkgbase, candidates) 105 self.debug('candidates for package {0} are {1}', pkgbase, candidates)
106 if len(candidates) != 1: 106 if len(candidates) != 1:
107 return '' 107 return ''
108 return str(candidates[0]).replace(str(self.pkgsrcdir), '../..') 108 return str(candidates[0]).replace(str(self.pkgsrcdir), '../..')
109 109
110 def bmake(self, *args: str) -> None: 110 def bmake(self, *args: str) -> None:
111 self.debug('running bmake {0} in {1}', args, str(self.pkgdir)) 111 self.debug('running bmake {0} in {1}', args, str(self.pkgdir))
112 subprocess.check_call([self.make, *args], cwd=self.pkgdir) 112 subprocess.check_call([self.make, *args], cwd=self.pkgdir)
113 113
114 def show_var(self, varname: str) -> str: 114 def show_var(self, varname: str) -> str:
115 output = subprocess.check_output((self.make, 'show-var', 'VARNAME=' + varname)) 115 output = subprocess.check_output((self.make, 'show-var', 'VARNAME=' + varname))
116 return output.decode('utf-8').strip() 116 return output.decode('utf-8').strip()
117 117
118 118
119class Lines: 119class Lines:
120 """ 120 """
121 A list of lines with high-level methods for manipulating variable 121 A list of lines with high-level methods for manipulating variable
122 assignments. 122 assignments.
123 """ 123 """
124 lines: List[str] 124 lines: List[str]
125 125
126 def __init__(self, *lines: str) -> None: 126 def __init__(self, *lines: str) -> None:
127 self.lines = [] 127 self.lines = []
128 for line in lines: 128 for line in lines:
129 self.add(line) 129 self.add(line)
130 130
131 @classmethod 131 @classmethod
132 def read_from(cls, src: Union[Path, Any]) -> 'Lines': 132 def read_from(cls, src: Union[Path, Any]) -> 'Lines':
133 return Lines(*src.read_text().splitlines()) 133 return Lines(*src.read_text().splitlines())
134 134
135 def write_to(self, dst: Union[Path, Any]): 135 def write_to(self, dst: Union[Path, Any]):
136 tmp = dst.with_name(f'{dst.name}.tmp') 136 tmp = dst.with_name(f'{dst.name}.tmp')
137 with tmp.open('w') as f: 137 with tmp.open('w') as f:
138 f.writelines(line + '\n' for line in self.lines) 138 f.writelines(line + '\n' for line in self.lines)
139 tmp.replace(dst) 139 tmp.replace(dst)
140 140
141 def all_varassigns(self, varname: str) -> List[Varassign]: 141 def all_varassigns(self, varname: str) -> List[Varassign]:
142 varassigns = [] 142 varassigns = []
143 for (i, line) in enumerate(self.lines): 143 for (i, line) in enumerate(self.lines):
144 pattern = r'''(?x) 144 pattern = r'''(?x)
145 ^ 145 ^
146 ([#]?[\w+\-]+?) # varname 146 ([#]?[\w+\-]+?) # varname
147 ([!+:?]?=) # op 147 ([!+:?]?=) # op
148 ([ \t]*) # indent 148 ([ \t]*) # indent
149 ([^#\\]*?) # value 149 ([^#\\]*?) # value
150 (\s*) # space_after_value 150 (\s*) # space_after_value
151 ([#].*|) # comment 151 ([#].*|) # comment
152 $ 152 $
153 ''' 153 '''
154 m = re.search(pattern, line) 154 m = re.search(pattern, line)
155 if m and m[1].lstrip('#') == varname.lstrip('#'): 155 if m and m[1].lstrip('#') == varname.lstrip('#'):
156 varassigns.append(Varassign(i, *m.groups())) 156 varassigns.append(Varassign(i, *m.groups()))
157 return varassigns 157 return varassigns
158 158
159 def unique_varassign(self, varname: str) -> Optional[Varassign]: 159 def unique_varassign(self, varname: str) -> Optional[Varassign]:
160 varassigns = self.all_varassigns(varname) 160 varassigns = self.all_varassigns(varname)
161 return varassigns[0] if len(varassigns) == 1 else None 161 return varassigns[0] if len(varassigns) == 1 else None
162 162
163 def get(self, varname: str) -> str: 163 def get(self, varname: str) -> str:
164 """ 164 """
165 Returns the value from the only variable assignment, or an empty 165 Returns the value from the only variable assignment, or an empty
166 string. 166 string.
167 """ 167 """
168 varassign = self.unique_varassign(varname) 168 varassign = self.unique_varassign(varname)
169 return varassign.value if varassign is not None and varassign.varname == varname else '' 169 return varassign.value if varassign is not None and varassign.varname == varname else ''
170 170
171 def index(self, pattern: str) -> int: 171 def index(self, pattern: str) -> int:
172 """ Returns the first index where the pattern is found, or -1. """ 172 """ Returns the first index where the pattern is found, or -1. """
173 for (i, line) in enumerate(self.lines): 173 for (i, line) in enumerate(self.lines):
174 if re.search(pattern, line): 174 if re.search(pattern, line):
175 return i 175 return i
176 return -1 176 return -1
177 177
178 def add(self, *lines: str): 178 def add(self, *lines: str):
179 for line in lines: 179 for line in lines:
180 assert type(line) == str, type(line) 180 assert type(line) == str, type(line)
181 self.lines.append(line) 181 self.lines.append(line)
182 182
183 def add_vars(self, *vars: Var): 183 def add_vars(self, *vars: Var):
184 """ 184 """
185 Appends the given variable assignments to the lines, aligning the 185 Appends the given variable assignments to the lines, aligning the
186 variable values vertically. 186 variable values vertically.
187 """ 187 """
188 188
189 relevant_vars = [var for var in vars if var.value != ''] 189 relevant_vars = [var for var in vars if var.value != '']
190 if not relevant_vars: 190 if not relevant_vars:
191 return 191 return
192 192
193 width = 0 193 width = 0
194 for var in relevant_vars: 194 for var in relevant_vars:
195 name_op_len = (len(var.name) + len(var.op) + len('\t') + 7) // 8 * 8 195 name_op_len = (len(var.name) + len(var.op) + len('\t') + 7) // 8 * 8
196 width = max(width, name_op_len) 196 width = max(width, name_op_len)
197 197
198 for var in relevant_vars: 198 for var in relevant_vars:
199 tabs = (width - len(var.name) - len(var.op) + 7) // 8 199 tabs = (width - len(var.name) - len(var.op) + 7) // 8
200 self.add(var.name + var.op + '\t' * tabs + var.value) 200 self.add(var.name + var.op + '\t' * tabs + var.value)
201 self.add('') 201 self.add('')
202 202
203 def set(self, varname: str, new_value: str) -> bool: 203 def set(self, varname: str, new_value: str) -> bool:
204 """ Updates the value of an existing variable in the lines. """ 204 """ Updates the value of an existing variable in the lines. """
205 205
206 varassign = self.unique_varassign(varname) 206 varassign = self.unique_varassign(varname)
207 if varassign is not None: 207 if varassign is not None:
208 self.lines[varassign.index] = varname + varassign.op + varassign.indent + new_value 208 self.lines[varassign.index] = varname + varassign.op + varassign.indent + new_value
209 return varassign is not None 209 return varassign is not None
210 210
211 def append(self, varname: str, value: str) -> bool: 211 def append(self, varname: str, value: str) -> bool:
212 """ Appends to the value of an existing variable in the lines. """ 212 """ Appends to the value of an existing variable in the lines. """
213 varassign = self.unique_varassign(varname) 213 varassign = self.unique_varassign(varname)
214 if varassign is None or value == '': 214 if varassign is None or value == '':
215 return False 215 return False
216 216
217 before = ' ' if re.search(r'\S$', varassign.value) else '' 217 before = ' ' if re.search(r'\S$', varassign.value) else ''
218 after = '' if varassign.comment == '' else ' ' 218 after = '' if varassign.comment == '' else ' '
219 self.lines[varassign.index] = \ 219 self.lines[varassign.index] = \
220 f'{varassign.varname}{varassign.op}{varassign.indent}' \ 220 f'{varassign.varname}{varassign.op}{varassign.indent}' \
221 f'{varassign.value}{before}{value}{after}{varassign.comment}' 221 f'{varassign.value}{before}{value}{after}{varassign.comment}'
222 return True 222 return True
223 223
224 def remove(self, varname: str) -> bool: 224 def remove(self, varname: str) -> bool:
225 """ Removes the unique variable assignment. """ 225 """ Removes the unique variable assignment. """
226 varassign = self.unique_varassign(varname) 226 varassign = self.unique_varassign(varname)
227 if varassign is not None: 227 if varassign is not None:
228 self.lines.pop(varassign.index) 228 self.lines.pop(varassign.index)
229 return varassign is not None 229 return varassign is not None
230 230
231 def remove_if(self, varname: str, expected_value: str) -> bool: 231 def remove_if(self, varname: str, expected_value: str) -> bool:
232 """ Removes a variable assignment if its value is the expected one. """ 232 """ Removes a variable assignment if its value is the expected one. """
233 for varassign in self.all_varassigns(varname): 233 for varassign in self.all_varassigns(varname):
234 if varassign.value == expected_value: 234 if varassign.value == expected_value:
235 self.lines.pop(varassign.index) 235 self.lines.pop(varassign.index)
236 return True 236 return True
237 return False 237 return False
238 238
239 239
240class Generator: 240class Generator:
241 """ Generates the initial package Makefile. """ 241 """ Generates the initial package Makefile. """
242 url: str 242 url: str
243 master_sites: str 243 master_sites: str
244 distfile: str 244 distfile: str
245 homepage: str 245 homepage: str
246 extract_sufx: str 246 extract_sufx: str
247 categories: str 247 categories: str
248 github_project: str 248 github_project: str
249 github_tag: str 249 github_tag: str
250 github_release: str 250 github_release: str
251 dist_subdir: str 251 dist_subdir: str
252 pkgname_prefix: str 252 pkgname_prefix: str
253 pkgname_transform: str 253 pkgname_transform: str
254 maintainer: str 254 maintainer: str
255 distname: str 255 distname: str
256 pkgname: str 256 pkgname: str
257 257
258 def __init__(self, url: str) -> None: 258 def __init__(self, url: str) -> None:
259 self.url = url 259 self.url = url
260 self.master_sites = '' 260 self.master_sites = ''
261 self.distfile = '' 261 self.distfile = ''
262 self.homepage = '' 262 self.homepage = ''
263 self.extract_sufx = '' 263 self.extract_sufx = ''
264 self.categories = '' 264 self.categories = ''
265 self.github_project = '' 265 self.github_project = ''
266 self.github_tag = '' 266 self.github_tag = ''
267 self.github_release = '' 267 self.github_release = ''
268 self.dist_subdir = '' 268 self.dist_subdir = ''
269 self.pkgname_prefix = '' 269 self.pkgname_prefix = ''
270 self.pkgname_transform = '' 270 self.pkgname_transform = ''
271 self.maintainer = '' 271 self.maintainer = ''
272 self.distname = '' 272 self.distname = ''
273 self.pkgname = '' 273 self.pkgname = ''
274 274
275 def foreach_site_from_sites_mk(self, action: Callable[[str, str], None]): 275 def foreach_site_from_sites_mk(self, action: Callable[[str, str], None]):
276 if self.master_sites != '': 276 if self.master_sites != '':
277 return 277 return
278 278
279 varname = '' 279 varname = ''
280 with open('../../mk/fetch/sites.mk') as sites_mk: 280 with open('../../mk/fetch/sites.mk') as sites_mk:
281 for line in sites_mk: 281 for line in sites_mk:
282 m = re.search(r'^(MASTER_SITE_.*)\+=', line) 282 m = re.search(r'^(MASTER_SITE_.*)\+=', line)
283 if m: 283 if m:
284 varname = m[1] 284 varname = m[1]
285 continue 285 continue
286 286
287 m = re.search(r'^\t(.*?)(?:\s+\\)?$', line) 287 m = re.search(r'^\t(.*?)(?:\s+\\)?$', line)
288 if m: 288 if m:
289 action(varname, m[1]) 289 action(varname, m[1])
290 290
291 def adjust_site_from_sites_mk(self, varname: str, site_url: str): 291 def adjust_site_from_sites_mk(self, varname: str, site_url: str):
292 292
293 url_noproto = re.sub(r'^\w+://', '', self.url) 293 url_noproto = re.sub(r'^\w+://', '', self.url)
294 site_url_noproto = re.sub(r'^\w+://', '', site_url) 294 site_url_noproto = re.sub(r'^\w+://', '', site_url)
295 295
296 if not url_noproto.startswith(site_url_noproto): 296 if not url_noproto.startswith(site_url_noproto):
297 return 297 return
298 298
299 rest = url_noproto[len(site_url_noproto):] 299 rest = url_noproto[len(site_url_noproto):]
300 if '/' not in rest: 300 if '/' not in rest:
301 self.master_sites = f'${{{varname}}}' 301 self.master_sites = f'${{{varname}}}'
302 self.distfile = rest 302 self.distfile = rest
303 self.homepage = '# TODO' 303 self.homepage = '# TODO'
304 return 304 return
305 305
306 subdir, self.distfile = re.search(r'^(.*/)(.*)$', rest).groups() 306 subdir, self.distfile = re.search(r'^(.*/)(.*)$', rest).groups()
307 307
308 self.master_sites = f'${{{varname}:={subdir}}}' 308 self.master_sites = f'${{{varname}:={subdir}}}'
309 if varname == 'MASTER_SITE_GNU': 309 if varname == 'MASTER_SITE_GNU':
310 self.homepage = f'https://www.gnu.org/software/{subdir}' 310 self.homepage = f'https://www.gnu.org/software/{subdir}'
311 else: 311 else:
312 self.homepage = self.url[:-len(self.distfile)] + ' # TODO: check' 312 self.homepage = self.url[:-len(self.distfile)] + ' # TODO: check'
313 313
314 if varname == 'MASTER_SITE_R_CRAN': 314 if varname == 'MASTER_SITE_R_CRAN':
315 sys.exit('url2pkg: to create R packages, use pkgtools/R2pkg instead') 315 sys.exit('url2pkg: to create R packages, use pkgtools/R2pkg instead')
316 316
317 def adjust_site_SourceForge(self): 317 def adjust_site_SourceForge(self):
318 pattern = r'''(?x) 318 pattern = r'''(?x)
319 ^ 319 ^
320 https?://downloads\.sourceforge\.net/(?:project|sourceforge)/ 320 https?://downloads\.sourceforge\.net/(?:project|sourceforge)/
321 ([^/?]+)/ # project name 321 ([^/?]+)/ # project name
322 ((?:[^/?]+/)*) # subdirectories 322 ((?:[^/?]+/)*) # subdirectories
323 ([^/?]+) # filename 323 ([^/?]+) # filename
324 (?:\?.*)? # query parameters 324 (?:\?.*)? # query parameters
325 $ 325 $
326 ''' 326 '''
327 m = re.search(pattern, self.url) 327 m = re.search(pattern, self.url)
328 if not m: 328 if not m:
329 return 329 return
330 330
331 project, subdir, filename = m.groups() 331 project, subdir, filename = m.groups()
332 self.master_sites = f'${{MASTER_SITE_SOURCEFORGE:={project}/{subdir}}}' 332 self.master_sites = f'${{MASTER_SITE_SOURCEFORGE:={project}/{subdir}}}'
333 self.homepage = f'https://{project}.sourceforge.net/' 333 self.homepage = f'https://{project}.sourceforge.net/'
334 self.distfile = filename 334 self.distfile = filename
335 335
336 def adjust_site_GitHub_archive(self): 336 def adjust_site_GitHub_archive(self):
337 pattern = r'''(?x) 337 pattern = r'''(?x)
338 ^ 338 ^
339 https://github\.com/ 339 https://github\.com/
340 (.+)/ # org 340 (.+)/ # org
341 (.+)/archive/ # proj 341 (.+)/archive/ # proj
342 (.+) # tag 342 (.+) # tag
343 (\.tar\.gz|\.zip) # ext 343 (\.tar\.gz|\.zip) # ext
344 $ 344 $
345 ''' 345 '''
346 m = re.search(pattern, self.url) 346 m = re.search(pattern, self.url)
347 if not m: 347 if not m:
348 return 348 return
349 349
350 org, proj, tag, ext = m.groups() 350 org, proj, tag, ext = m.groups()
351 351
352 self.github_project = proj 352 self.github_project = proj
353 self.github_tag = tag 353 self.github_tag = tag
354 self.master_sites = f'${{MASTER_SITE_GITHUB:={org}/}}' 354 self.master_sites = f'${{MASTER_SITE_GITHUB:={org}/}}'
355 self.homepage = f'https://github.com/{org}/{proj}/' 355 self.homepage = f'https://github.com/{org}/{proj}/'
356 if proj not in tag: 356 if proj not in tag:
357 self.pkgname_prefix = '${GITHUB_PROJECT}-' 357 self.pkgname_prefix = '${GITHUB_PROJECT}-'
358 self.dist_subdir = '${GITHUB_PROJECT}' 358 self.dist_subdir = '${GITHUB_PROJECT}'
359 self.distfile = tag + ext 359 self.distfile = tag + ext
360 360
361 def adjust_site_GitHub_release(self): 361 def adjust_site_GitHub_release(self):
362 pattern = r'''(?x) 362 pattern = r'''(?x)
363 ^https://github\.com/ 363 ^https://github\.com/
364 (.+)/ # org 364 (.+)/ # org
365 (.+)/ # proj  365 (.+)/ # proj
366 releases/download/ 366 releases/download/
367 (.+)/ # tag 367 (.+)/ # tag
368 (.+) # base 368 (.+) # base
369 (\.tar\.gz|\.zip)$ # ext 369 (\.tar\.gz|\.zip)$ # ext
370 ''' 370 '''
371 m = re.search(pattern, self.url) 371 m = re.search(pattern, self.url)
372 if not m: 372 if not m:
373 return 373 return
374 374
375 org, proj, tag, base, ext = m.groups() 375 org, proj, tag, base, ext = m.groups()
376 376
377 self.github_project = proj 377 self.github_project = proj
378 self.master_sites = f'${{MASTER_SITE_GITHUB:={org}/}}' 378 self.master_sites = f'${{MASTER_SITE_GITHUB:={org}/}}'
379 self.homepage = f'https://github.com/{org}/{proj}/' 379 self.homepage = f'https://github.com/{org}/{proj}/'
380 if proj not in base: 380 if proj not in base:
381 self.github_project = proj 381 self.github_project = proj
382 self.dist_subdir = '${GITHUB_PROJECT}' 382 self.dist_subdir = '${GITHUB_PROJECT}'
383 self.github_release = '${DISTNAME}' if tag == base else tag 383 self.github_release = '${DISTNAME}' if tag == base else tag
384 self.distfile = base + ext 384 self.distfile = base + ext
385 385
386 def adjust_site_other(self): 386 def adjust_site_other(self):
387 if self.master_sites != '': 387 if self.master_sites != '':
388 return 388 return
389 389
390 base_url, self.distfile = re.search(r'^(.*/)(.*)$', self.url).groups() 390 base_url, self.distfile = re.search(r'^(.*/)(.*)$', self.url).groups()
391 391
392 self.master_sites = base_url 392 self.master_sites = base_url
393 self.homepage = base_url 393 self.homepage = base_url
394 394
395 def adjust_everything_else(self): 395 def adjust_everything_else(self):
396 m = re.search(r'^(.*?)((?:\.tar)?\.\w+)$', self.distfile) 396 m = re.search(r'^(.*?)((?:\.tar)?\.\w+)$', self.distfile)
397 if m: 397 if m:
398 distname, extract_sufx = m.groups() 398 distname, extract_sufx = m.groups()
399 else: 399 else:
400 distname, extract_sufx = self.distfile, '# none' 400 distname, extract_sufx = self.distfile, '# none'
401 self.distname = distname 401 self.distname = distname
402 402
403 if re.search(r'^v\d+\.', distname): 403 if re.search(r'^v\d+\.', distname):
404 self.pkgname_transform = ':S,^v,,' 404 self.pkgname_transform = ':S,^v,,'
405 elif re.search(r'-v\d+\.', distname) and not re.search(r'-v.*-v\d+\.', distname): 405 elif re.search(r'-v\d+\.', distname) and not re.search(r'-v.*-v\d+\.', distname):
406 self.pkgname_transform = ':S,-v,-,' 406 self.pkgname_transform = ':S,-v,-,'
407 407
408 main_category = Path.cwd().parts[-2] 408 main_category = Path.cwd().parts[-2]
409 self.categories = main_category \ 409 self.categories = main_category \
410 if main_category not in ('local', 'wip') \ 410 if main_category not in ('local', 'wip') \
411 else '# TODO: add primary category' 411 else '# TODO: add primary category'
412 412
413 if extract_sufx in ('.tar.gz', '.gem'): 413 if extract_sufx in ('.tar.gz', '.gem'):
414 extract_sufx = '' 414 extract_sufx = ''
415 self.extract_sufx = extract_sufx 415 self.extract_sufx = extract_sufx
416 416
417 self.pkgname = '' if self.pkgname_prefix == '' and self.pkgname_transform == '' \ 417 self.pkgname = '' if self.pkgname_prefix == '' and self.pkgname_transform == '' \
418 else f'{self.pkgname_prefix}${{DISTNAME{self.pkgname_transform}}}' 418 else f'{self.pkgname_prefix}${{DISTNAME{self.pkgname_transform}}}'
419 419
420 self.maintainer = \ 420 self.maintainer = \
421 os.getenv('PKGMAINTAINER') or os.getenv('REPLYTO') \ 421 os.getenv('PKGMAINTAINER') or os.getenv('REPLYTO') \
422 or 'INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org' 422 or 'INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org'
423 423
424 def generate_lines(self) -> Lines: 424 def generate_lines(self) -> Lines:
425 lines = Lines() 425 lines = Lines()
426 lines.add('# $''NetBSD$') 426 lines.add('# $''NetBSD$')
427 lines.add('') 427 lines.add('')
428 428
429 lines.add_vars( 429 lines.add_vars(
430 Var('GITHUB_PROJECT', '=', self.github_project), 430 Var('GITHUB_PROJECT', '=', self.github_project),
431 Var('GITHUB_TAG', '=', self.github_tag), 431 Var('GITHUB_TAG', '=', self.github_tag),
432 Var('DISTNAME', '=', self.distname), 432 Var('DISTNAME', '=', self.distname),
433 Var('PKGNAME', '=', self.pkgname), 433 Var('PKGNAME', '=', self.pkgname),
434 Var('CATEGORIES', '=', self.categories), 434 Var('CATEGORIES', '=', self.categories),
435 Var('MASTER_SITES', '=', self.master_sites), 435 Var('MASTER_SITES', '=', self.master_sites),
436 Var('GITHUB_RELEASE', '=', self.github_release), 436 Var('GITHUB_RELEASE', '=', self.github_release),
437 Var('EXTRACT_SUFX', '=', self.extract_sufx), 437 Var('EXTRACT_SUFX', '=', self.extract_sufx),
438 Var('DIST_SUBDIR', '=', self.dist_subdir), 438 Var('DIST_SUBDIR', '=', self.dist_subdir),
439 ) 439 )
440 440
441 lines.add_vars( 441 lines.add_vars(
442 Var('MAINTAINER', '=', self.maintainer), 442 Var('MAINTAINER', '=', self.maintainer),
443 Var('HOMEPAGE', '=', self.homepage), 443 Var('HOMEPAGE', '=', self.homepage),
444 Var('COMMENT', '=', 'TODO: Short description of the package'), 444 Var('COMMENT', '=', 'TODO: Short description of the package'),
445 Var('#LICENSE', '=', '# TODO: (see mk/license.mk)'), 445 Var('#LICENSE', '=', '# TODO: (see mk/license.mk)'),
446 ) 446 )
447 447
448 lines.add('# url2pkg-marker (please do not remove this line.)') 448 lines.add('# url2pkg-marker (please do not remove this line.)')
449 lines.add('.include "../../mk/bsd.pkg.mk"') 449 lines.add('.include "../../mk/bsd.pkg.mk"')
450 450
451 return lines 451 return lines
452 452
453 def generate_Makefile(self) -> Lines: 453 def generate_Makefile(self) -> Lines:
454 self.adjust_site_SourceForge() 454 self.adjust_site_SourceForge()
455 self.adjust_site_GitHub_archive() 455 self.adjust_site_GitHub_archive()
456 self.adjust_site_GitHub_release() 456 self.adjust_site_GitHub_release()
457 self.foreach_site_from_sites_mk(self.adjust_site_from_sites_mk) 457 self.foreach_site_from_sites_mk(self.adjust_site_from_sites_mk)
458 self.adjust_site_other() 458 self.adjust_site_other()
459 self.adjust_everything_else() 459 self.adjust_everything_else()
460 return self.generate_lines() 460 return self.generate_lines()
461 461
462 def generate_package(self, up: Url2Pkg) -> Lines: 462 def generate_package(self, g: Globals) -> Lines:
463 pkgdir = up.pkgdir 463 pkgdir = g.pkgdir
464 makefile = pkgdir / 'Makefile' 464 makefile = pkgdir / 'Makefile'
465 descr = pkgdir / 'DESCR' 465 descr = pkgdir / 'DESCR'
466 plist = pkgdir / 'PLIST' 466 plist = pkgdir / 'PLIST'
467 467
468 initial_lines = self.generate_Makefile() 468 initial_lines = self.generate_Makefile()
469 469
470 try: 470 try:
471 makefile.replace(f'{makefile}.url2pkg~') 471 makefile.replace(f'{makefile}.url2pkg~')
472 except OSError: 472 except OSError:
473 pass 473 pass
474 initial_lines.write_to(makefile) 474 initial_lines.write_to(makefile)
475 plist.is_file() or Lines('@comment $''NetBSD$').write_to(plist) 475 plist.is_file() or Lines('@comment $''NetBSD$').write_to(plist)
476 descr.is_file() or Lines().write_to(descr) 476 descr.is_file() or Lines().write_to(descr)
477 477
478 subprocess.check_call([up.editor, makefile]) 478 subprocess.check_call([g.editor, makefile])
479 479
480 up.bmake('clean', 'distinfo', 'extract') 480 g.bmake('clean', 'distinfo', 'extract')
481 481
482 return initial_lines 482 return initial_lines
483 483
484 484
485class Adjuster: 485class Adjuster:
486 """ 486 """
487 After the distfile has been downloaded and extracted, the 487 After the distfile has been downloaded and extracted, the
488 adjust_* methods of this class inspect the extracted files 488 adjust_* methods of this class inspect the extracted files
489 and adjust the variable definitions in the package Makefile. 489 and adjust the variable definitions in the package Makefile.
490 """ 490 """
491 up: Url2Pkg 491 g: Globals
492 url: str 492 url: str
493 initial_lines: Lines 493 initial_lines: Lines
494 494
495 # the absolute pathname to the working directory, containing 495 # the absolute pathname to the working directory, containing
496 # the extracted distfiles. 496 # the extracted distfiles.
497 abs_wrkdir: Union[Path, Any] 497 abs_wrkdir: Union[Path, Any]
498 498
499 # the absolute pathname to a subdirectory of abs_wrkdir, typically 499 # the absolute pathname to a subdirectory of abs_wrkdir, typically
500 # containing package-provided Makefiles or configure scripts. 500 # containing package-provided Makefiles or configure scripts.
501 abs_wrksrc: Union[Path, Any] 501 abs_wrksrc: Union[Path, Any]
502 502
503 # the regular files and directories relative to abs_wrksrc. 503 # the regular files and directories relative to abs_wrksrc.
504 wrksrc_files: List[str] 504 wrksrc_files: List[str]
505 wrksrc_dirs: List[str] 505 wrksrc_dirs: List[str]
506 506
507 """ 507 """
508 The following variables may be set by the adjust_* subroutines and 508 The following variables may be set by the adjust_* subroutines and
509 will later appear in the package Makefile: 509 will later appear in the package Makefile:
510 """ 510 """
511 511
512 # categories for the package, in addition to the usual 512 # categories for the package, in addition to the usual
513 # parent directory. 513 # parent directory.
514 categories: List[str] 514 categories: List[str]
515 515
516 # the dependencies of the package, in the form 516 # the dependencies of the package, in the form
517 # "package>=version:../../category/package". 517 # "package>=version:../../category/package".
518 depends: List[str] 518 depends: List[str]
519 build_depends: List[str] 519 build_depends: List[str]
520 test_depends: List[str] 520 test_depends: List[str]
521 521
522 # .include, interleaved with BUILDLINK3_API_DEPENDS. 522 # .include, interleaved with BUILDLINK3_API_DEPENDS.
523 # These lines are added at the bottom of the Makefile. 523 # These lines are added at the bottom of the Makefile.
524 bl3_lines: List[str] 524 bl3_lines: List[str]
525 525
526 # a list of pathnames relative to the package directory. 526 # a list of pathnames relative to the package directory.
527 # All these files will be included at the bottom of the Makefile. 527 # All these files will be included at the bottom of the Makefile.
528 includes: List[str] 528 includes: List[str]
529 529
530 # a list of variable assignments that will make up the fourth 530 # a list of variable assignments that will make up the fourth
531 # paragraph of the package Makefile, where the build configuration 531 # paragraph of the package Makefile, where the build configuration
532 # takes place. 532 # takes place.
533 build_vars: List[Var] 533 build_vars: List[Var]
534 534
535 # similar to the @build_vars, but separated by an empty line in 535 # similar to the @build_vars, but separated by an empty line in
536 # the Makefile, thereby forming the fifth paragraph. 536 # the Makefile, thereby forming the fifth paragraph.
537 extra_vars: List[Var] 537 extra_vars: List[Var]
538 538
539 # variables from the initial Makefile whose values are replaced 539 # variables from the initial Makefile whose values are replaced
540 update_vars: Dict[str, str] 540 update_vars: Dict[str, str]
541 541
542 # these are inserted below the second paragraph in the Makefile. 542 # these are inserted below the second paragraph in the Makefile.
543 todos: List[str] 543 todos: List[str]
544 544
545 # the package name is based on DISTNAME and modified by 545 # the package name is based on DISTNAME and modified by
546 # pkgname_prefix and pkgname_transform. 546 # pkgname_prefix and pkgname_transform.
547 pkgname_prefix: str # example: ${PYPKGPREFIX}- 547 pkgname_prefix: str # example: ${PYPKGPREFIX}-
548 pkgname_transform: str # example: :S,-v,-, 548 pkgname_transform: str # example: :S,-v,-,
549 549
550 # all lines of the package Makefile, for direct modification. 550 # all lines of the package Makefile, for direct modification.
551 makefile_lines: Lines 551 makefile_lines: Lines
552 552
553 regenerate_distinfo: bool 553 regenerate_distinfo: bool
554 554
555 def __init__(self, up: Url2Pkg, url: str, initial_lines: Lines): 555 def __init__(self, g: Globals, url: str, initial_lines: Lines):
556 self.up = up 556 self.g = g
557 self.url = url 557 self.url = url
558 self.initial_lines = initial_lines 558 self.initial_lines = initial_lines
559 self.abs_wrkdir = Path('') 559 self.abs_wrkdir = Path('')
560 self.abs_wrksrc = Path('') 560 self.abs_wrksrc = Path('')
561 self.wrksrc_files = [] 561 self.wrksrc_files = []
562 self.wrksrc_dirs = [] 562 self.wrksrc_dirs = []
563 self.categories = [] 563 self.categories = []
564 self.depends = [] 564 self.depends = []
565 self.build_depends = [] 565 self.build_depends = []
566 self.test_depends = [] 566 self.test_depends = []
567 self.bl3_lines = [] 567 self.bl3_lines = []
568 self.includes = [] 568 self.includes = []
569 self.build_vars = [] 569 self.build_vars = []
570 self.extra_vars = [] 570 self.extra_vars = []
571 self.update_vars = {} 571 self.update_vars = {}
572 self.todos = [] 572 self.todos = []
573 self.pkgname_prefix = '' 573 self.pkgname_prefix = ''
574 self.pkgname_transform = '' 574 self.pkgname_transform = ''
575 self.makefile_lines = Lines() 575 self.makefile_lines = Lines()
576 self.regenerate_distinfo = False 576 self.regenerate_distinfo = False
577 577
578 def add_dependency(self, kind: str, pkgbase: str, constraint: str, dep_dir: str) -> None: 578 def add_dependency(self, kind: str, pkgbase: str, constraint: str, dep_dir: str) -> None:
579 """ add_dependency('DEPENDS', 'package', '>=1', '../../category/package') """ 579 """ add_dependency('DEPENDS', 'package', '>=1', '../../category/package') """
580 580
581 self.up.debug('add_dependency: {0} {1} {2} {3}', kind, pkgbase, constraint, dep_dir) 581 self.g.debug('add_dependency: {0} {1} {2} {3}', kind, pkgbase, constraint, dep_dir)
582 582
583 def bl3_identifier(): 583 def bl3_identifier():
584 try: 584 try:
585 with open(dep_dir + '/buildlink3.mk') as f: 585 with open(dep_dir + '/buildlink3.mk') as f:
586 for line in f: 586 for line in f:
587 m = re.search(r'^BUILDLINK_TREE\+=\s*(\S+)$', line) 587 m = re.search(r'^BUILDLINK_TREE\+=\s*(\S+)$', line)
588 if m: 588 if m:
589 return m[1] 589 return m[1]
590 except OSError: 590 except OSError:
591 pass 591 pass
592 return '' 592 return ''
593 593
594 if dep_dir != '': 594 if dep_dir != '':
595 pkgid = bl3_identifier() 595 pkgid = bl3_identifier()
596 if pkgid != '': 596 if pkgid != '':
597 if kind == 'BUILD_DEPENDS': 597 if kind == 'BUILD_DEPENDS':
598 self.bl3_lines.append(f'BUILDLINK_DEPENDS.{pkgid}+=\tbuild') 598 self.bl3_lines.append(f'BUILDLINK_DEPENDS.{pkgid}+=\tbuild')
599 self.bl3_lines.append(f'BUILDLINK_API_DEPENDS.{pkgid}+=\t{pkgid}{constraint}') 599 self.bl3_lines.append(f'BUILDLINK_API_DEPENDS.{pkgid}+=\t{pkgid}{constraint}')
600 self.bl3_lines.append(f'.include "{dep_dir}/buildlink3.mk"') 600 self.bl3_lines.append(f'.include "{dep_dir}/buildlink3.mk"')
601 return 601 return
602 602
603 value = f'{pkgbase}{constraint}:{dep_dir}' \ 603 value = f'{pkgbase}{constraint}:{dep_dir}' \
604 if dep_dir != '' and os.path.isfile(f'{dep_dir}/Makefile') \ 604 if dep_dir != '' and os.path.isfile(f'{dep_dir}/Makefile') \
605 else f'# TODO: {pkgbase}{constraint}' 605 else f'# TODO: {pkgbase}{constraint}'
606 606
607 if kind == 'DEPENDS': 607 if kind == 'DEPENDS':
608 self.depends.append(value) 608 self.depends.append(value)
609 elif kind == 'BUILD_DEPENDS': 609 elif kind == 'BUILD_DEPENDS':
610 self.build_depends.append(value) 610 self.build_depends.append(value)
611 elif kind == 'TEST_DEPENDS': 611 elif kind == 'TEST_DEPENDS':
612 self.test_depends.append(value) 612 self.test_depends.append(value)
613 else: 613 else:
614 self.todos.append(f'dependency {kind} {value}') 614 self.todos.append(f'dependency {kind} {value}')
615 615
616 def read_dependencies(self, cmd: str, env: Dict[str, str], cwd: Union[Path, Any], pkgname_prefix: str) -> None: 616 def read_dependencies(self, cmd: str, env: Dict[str, str], cwd: Union[Path, Any], pkgname_prefix: str) -> None:
617 effective_env = dict(os.environ) 617 effective_env = dict(os.environ)
618 effective_env.update(env) 618 effective_env.update(env)
619 619
620 self.up.debug('reading dependencies: cd {0} && env {1} {2}', str(cwd), env, cmd) 620 self.g.debug('reading dependencies: cd {0} && env {1} {2}', str(cwd), env, cmd)
621 output: bytes = subprocess.check_output(args=cmd, shell=True, env=effective_env, cwd=cwd) 621 output: bytes = subprocess.check_output(args=cmd, shell=True, env=effective_env, cwd=cwd)
622 622
623 dep_lines: List[Tuple[str, str, str, str]] = [] 623 dep_lines: List[Tuple[str, str, str, str]] = []
624 for line in output.decode('utf-8').splitlines(): 624 for line in output.decode('utf-8').splitlines():
625 # example: DEPENDS pkgbase>=1.2.3:../../category/pkgbase 625 # example: DEPENDS pkgbase>=1.2.3:../../category/pkgbase
626 m = re.search(r'^(\w+)\t([^\s:>]+)(>[^\s:]+|)(?::(\.\./\.\./\S+))?$', line) 626 m = re.search(r'^(\w+)\t([^\s:>]+)(>[^\s:]+|)(?::(\.\./\.\./\S+))?$', line)
627 if m: 627 if m:
628 dep_lines.append((m[1], m[2], m[3] or '>=0', m[4] or '')) 628 dep_lines.append((m[1], m[2], m[3] or '>=0', m[4] or ''))
629 continue 629 continue
630 630
631 # example: var VARNAME value # possibly with comment 631 # example: var VARNAME value # possibly with comment
632 m = re.search(r'^var\t(\S+)\t(.+)$', line) 632 m = re.search(r'^var\t(\S+)\t(.+)$', line)
633 if m: 633 if m:
634 self.update_vars[m[1]] = m[2] 634 self.update_vars[m[1]] = m[2]
635 continue 635 continue
636 636
637 if line != '': 637 if line != '':
638 self.up.debug('unknown dependency line: {0}', line) 638 self.g.debug('unknown dependency line: {0}', line)
639 639
640 for dep_line in dep_lines: 640 for dep_line in dep_lines:
641 kind, pkgbase, constraint, dep_dir = dep_line 641 kind, pkgbase, constraint, dep_dir = dep_line
642 642
643 if dep_dir == '' and pkgname_prefix != '': 643 if dep_dir == '' and pkgname_prefix != '':
644 dep_dir = self.up.find_package(pkgname_prefix + pkgbase) 644 dep_dir = self.g.find_package(pkgname_prefix + pkgbase)
645 if dep_dir != '': 645 if dep_dir != '':
646 pkgbase = pkgname_prefix + pkgbase 646 pkgbase = pkgname_prefix + pkgbase
647 if dep_dir == '': 647 if dep_dir == '':
648 dep_dir = self.up.find_package(pkgbase) 648 dep_dir = self.g.find_package(pkgbase)
649 649
650 self.add_dependency(kind, pkgbase, constraint, dep_dir) 650 self.add_dependency(kind, pkgbase, constraint, dep_dir)
651 651
652 def wrksrc_open(self, relative_pathname: str): 652 def wrksrc_open(self, relative_pathname: str):
653 return (self.abs_wrksrc / relative_pathname).open() 653 return (self.abs_wrksrc / relative_pathname).open()
654 654
655 def wrksrc_find(self, what: Union[str, Callable[[str], bool]]) -> List[str]: 655 def wrksrc_find(self, what: Union[str, Callable[[str], bool]]) -> List[str]:
656 def search(f): 656 def search(f):
657 return re.search(what, f) if type(what) == str else what(f) 657 return re.search(what, f) if type(what) == str else what(f)
658 658
659 return list(sorted(filter(search, self.wrksrc_files))) 659 return list(sorted(filter(search, self.wrksrc_files)))
660 660
661 def wrksrc_grep(self, filename: str, pattern: str) -> List[Union[str, List[str]]]: 661 def wrksrc_grep(self, filename: str, pattern: str) -> List[Union[str, List[str]]]:
662 with self.wrksrc_open(filename) as f: 662 with self.wrksrc_open(filename) as f:
663 matches = [] 663 matches = []
664 for line in f: 664 for line in f:
665 line = line.rstrip('\n') 665 line = line.rstrip('\n')
666 m = re.search(pattern, line) 666 m = re.search(pattern, line)
667 if m: 667 if m:
668 groups = list(m.groups()) 668 groups = list(m.groups())
669 matches.append(groups if groups else line) 669 matches.append(groups if groups else line)
670 return matches 670 return matches
671 671
672 def wrksrc_isdir(self, relative_pathname: str) -> bool: 672 def wrksrc_isdir(self, relative_pathname: str) -> bool:
673 return (self.abs_wrksrc / relative_pathname).is_dir() 673 return (self.abs_wrksrc / relative_pathname).is_dir()
674 674
675 def wrksrc_isfile(self, relative_pathname: str) -> bool: 675 def wrksrc_isfile(self, relative_pathname: str) -> bool:
676 return (self.abs_wrksrc / relative_pathname).is_file() 676 return (self.abs_wrksrc / relative_pathname).is_file()
677 677
678 def adjust_configure(self): 678 def adjust_configure(self):
679 if not self.wrksrc_isfile('configure'): 679 if not self.wrksrc_isfile('configure'):
680 return 680 return
681 681
682 configures = self.wrksrc_find(r'(^|/)configure$') 682 configures = self.wrksrc_find(r'(^|/)configure$')
683 if configures: 683 if configures:
684 gnu = any(self.wrksrc_grep(configure, r'\b(Free Software Foundation|autoconf)\b') 684 gnu = any(self.wrksrc_grep(configure, r'\b(Free Software Foundation|autoconf)\b')
685 for configure in configures) 685 for configure in configures)
686 varname = 'GNU_CONFIGURE' if gnu else 'HAS_CONFIGURE' 686 varname = 'GNU_CONFIGURE' if gnu else 'HAS_CONFIGURE'
687 self.build_vars.append(Var(varname, '=', 'yes')) 687 self.build_vars.append(Var(varname, '=', 'yes'))
688 688
689 def adjust_cmake(self): 689 def adjust_cmake(self):
690 if self.wrksrc_isfile('CMakeLists.txt'): 690 if self.wrksrc_isfile('CMakeLists.txt'):
691 self.build_vars.append(Var('USE_CMAKE', '=', 'yes')) 691 self.build_vars.append(Var('USE_CMAKE', '=', 'yes'))
692 692
693 def adjust_meson(self): 693 def adjust_meson(self):
694 if self.wrksrc_isfile('meson.build'): 694 if self.wrksrc_isfile('meson.build'):
695 self.includes.append('../../devel/meson/build.mk') 695 self.includes.append('../../devel/meson/build.mk')
696 696
697 def adjust_gconf2_schemas(self): 697 def adjust_gconf2_schemas(self):
698 gconf2_files = self.wrksrc_find(r'\.schemas(\.in)*$') 698 gconf2_files = self.wrksrc_find(r'\.schemas(\.in)*$')
699 if gconf2_files: 699 if gconf2_files:
700 self.includes.append('../../devel/GConf/schemas.mk') 700 self.includes.append('../../devel/GConf/schemas.mk')
701 701
702 for f in gconf2_files: 702 for f in gconf2_files:
703 self.extra_vars.append(Var('GCONF_SCHEMAS', '+=', re.sub(r'(\.in)+$', '', f))) 703 self.extra_vars.append(Var('GCONF_SCHEMAS', '+=', re.sub(r'(\.in)+$', '', f)))
704 704
705 def adjust_libtool(self): 705 def adjust_libtool(self):
706 if self.wrksrc_isfile('ltconfig') or self.wrksrc_isfile('ltmain.sh'): 706 if self.wrksrc_isfile('ltconfig') or self.wrksrc_isfile('ltmain.sh'):
707 self.build_vars.append(Var('USE_LIBTOOL', '=', 'yes')) 707 self.build_vars.append(Var('USE_LIBTOOL', '=', 'yes'))
708 708
709 if self.wrksrc_isdir('libltdl'): 709 if self.wrksrc_isdir('libltdl'):
710 self.includes.append('../../devel/libltdl/convenience.mk') 710 self.includes.append('../../devel/libltdl/convenience.mk')
711 711
712 def adjust_perl_module_Build_PL(self): 712 def adjust_perl_module_Build_PL(self):
713 # Example packages: 713 # Example packages:
714 # devel/p5-Algorithm-CheckDigits 714 # devel/p5-Algorithm-CheckDigits
715 715
716 cmd = f'{self.up.perl5} -I{self.up.libdir} -I. Build.PL' 716 cmd = f'{self.g.perl5} -I{self.g.libdir} -I. Build.PL'
717 self.read_dependencies(cmd, {}, self.abs_wrksrc, '') 717 self.read_dependencies(cmd, {}, self.abs_wrksrc, '')
718 self.build_vars.append(Var('PERL5_MODULE_TYPE', '=', 'Module::Build')) 718 self.build_vars.append(Var('PERL5_MODULE_TYPE', '=', 'Module::Build'))
719 719
720 def adjust_perl_module_Makefile_PL(self): 720 def adjust_perl_module_Makefile_PL(self):
721 # Example packages: 721 # Example packages:
722 # devel/p5-Algorithm-Diff (no dependencies) 722 # devel/p5-Algorithm-Diff (no dependencies)
723 # devel/p5-Carp-Assert-More (dependencies without version numbers) 723 # devel/p5-Carp-Assert-More (dependencies without version numbers)
724 # www/p5-HTML-Quoted (dependency with version number) 724 # www/p5-HTML-Quoted (dependency with version number)
725 725
726 # To avoid fix_up_makefile error for p5-HTML-Quoted, generate Makefile first. 726 # To avoid fix_up_makefile error for p5-HTML-Quoted, generate Makefile first.
727 cmd1 = f'{self.up.perl5} -I. Makefile.PL </dev/null 1>&0 2>&0' 727 cmd1 = f'{self.g.perl5} -I. Makefile.PL </dev/null 1>&0 2>&0'
728 subprocess.call(cmd1, shell=True, cwd=self.abs_wrksrc) 728 subprocess.call(cmd1, shell=True, cwd=self.abs_wrksrc)
729 729
730 cmd2 = f'{self.up.perl5} -I{self.up.libdir} -I. Makefile.PL' 730 cmd2 = f'{self.g.perl5} -I{self.g.libdir} -I. Makefile.PL'
731 self.read_dependencies(cmd2, {}, self.abs_wrksrc, '') 731 self.read_dependencies(cmd2, {}, self.abs_wrksrc, '')
732 732
733 def adjust_perl_module_homepage(self): 733 def adjust_perl_module_homepage(self):
734 if '${MASTER_SITE_PERL_CPAN:' not in self.makefile_lines.get('MASTER_SITES'): 734 if '${MASTER_SITE_PERL_CPAN:' not in self.makefile_lines.get('MASTER_SITES'):
735 return 735 return
736 736
737 homepage = self.makefile_lines.get('HOMEPAGE') 737 homepage = self.makefile_lines.get('HOMEPAGE')
738 if homepage == '' or not self.url.startswith(homepage): 738 if homepage == '' or not self.url.startswith(homepage):
739 return 739 return
740 740
741 distname = self.makefile_lines.get('DISTNAME') 741 distname = self.makefile_lines.get('DISTNAME')
742 module_name = re.sub(r'-v?[0-9].*', '', distname).replace('-', '::') 742 module_name = re.sub(r'-v?[0-9].*', '', distname).replace('-', '::')
743 self.makefile_lines.set('HOMEPAGE', f'https://metacpan.org/pod/{module_name}') 743 self.makefile_lines.set('HOMEPAGE', f'https://metacpan.org/pod/{module_name}')
744 744
745 def adjust_perl_module(self): 745 def adjust_perl_module(self):
746 if self.wrksrc_isfile('Build.PL'): 746 if self.wrksrc_isfile('Build.PL'):
747 self.adjust_perl_module_Build_PL() 747 self.adjust_perl_module_Build_PL()
748 elif self.wrksrc_isfile('Makefile.PL'): 748 elif self.wrksrc_isfile('Makefile.PL'):
749 self.adjust_perl_module_Makefile_PL() 749 self.adjust_perl_module_Makefile_PL()
750 else: 750 else:
751 return 751 return
752 752
753 distname = self.makefile_lines.get('DISTNAME') 753 distname = self.makefile_lines.get('DISTNAME')
754 packlist = re.sub(r'-v?[0-9].*', '', distname).replace('-', '/') 754 packlist = re.sub(r'-v?[0-9].*', '', distname).replace('-', '/')
755 self.build_vars.append(Var('PERL5_PACKLIST', '=', f'auto/{packlist}/.packlist')) 755 self.build_vars.append(Var('PERL5_PACKLIST', '=', f'auto/{packlist}/.packlist'))
756 self.includes.append('../../lang/perl5/module.mk') 756 self.includes.append('../../lang/perl5/module.mk')
757 self.pkgname_prefix = 'p5-' 757 self.pkgname_prefix = 'p5-'
758 self.categories.append('perl5') 758 self.categories.append('perl5')
759 self.adjust_perl_module_homepage() 759 self.adjust_perl_module_homepage()
760 760
761 try: 761 try:
762 (self.up.pkgdir / 'PLIST').unlink() 762 (self.g.pkgdir / 'PLIST').unlink()
763 except OSError: 763 except OSError:
764 pass 764 pass
765 765
766 def adjust_python_module(self): 766 def adjust_python_module(self):
767 # Example packages: 767 # Example packages:
768 # devel/py-ZopeComponent (dependencies, test dependencies) 768 # devel/py-ZopeComponent (dependencies, test dependencies)
769 # devel/py-gflags (uses distutils.core instead of setuptools; BSD license) 769 # devel/py-gflags (uses distutils.core instead of setuptools; BSD license)
770 # devel/py-gcovr (uses setuptools; BSD license) 770 # devel/py-gcovr (uses setuptools; BSD license)
771 771
772 if not self.wrksrc_isfile('setup.py'): 772 if not self.wrksrc_isfile('setup.py'):
773 return 773 return
774 774
775 cmd = f'{self.up.pythonbin} setup.py build' 775 cmd = f'{self.g.pythonbin} setup.py build'
776 env = { 776 env = {
777 'PYTHONDONTWRITEBYTECODE': 'x', 777 'PYTHONDONTWRITEBYTECODE': 'x',
778 'PYTHONPATH': self.up.libdir 778 'PYTHONPATH': self.g.libdir
779 } 779 }
780 self.read_dependencies(cmd, env, self.abs_wrksrc, 'py-') 780 self.read_dependencies(cmd, env, self.abs_wrksrc, 'py-')
781 781
782 self.pkgname_prefix = '${PYPKGPREFIX}-' 782 self.pkgname_prefix = '${PYPKGPREFIX}-'
783 self.categories.append('python') 783 self.categories.append('python')
784 self.includes.append('../../lang/python/egg.mk') 784 self.includes.append('../../lang/python/egg.mk')
785 785
786 def adjust_cargo(self): 786 def adjust_cargo(self):
787 if not self.wrksrc_isfile('Cargo.lock'): 787 if not self.wrksrc_isfile('Cargo.lock'):
788 return 788 return
789 789
790 # "checksum cargo-package-name cargo-package-version 790 # "checksum cargo-package-name cargo-package-version
791 for (name, version) in self.wrksrc_grep('Cargo.lock', r'^"checksum\s(\S+)\s(\S+)'): 791 for (name, version) in self.wrksrc_grep('Cargo.lock', r'^"checksum\s(\S+)\s(\S+)'):
792 self.build_vars.append(Var('CARGO_CRATE_DEPENDS', '+=', f'{name}-{version}')) 792 self.build_vars.append(Var('CARGO_CRATE_DEPENDS', '+=', f'{name}-{version}'))
793 793
794 self.includes.append('../../lang/rust/cargo.mk') 794 self.includes.append('../../lang/rust/cargo.mk')
795 795
796 def adjust_pkg_config(self): 796 def adjust_pkg_config(self):
797 def relevant(filename: str) -> bool: 797 def relevant(filename: str) -> bool:
798 return filename.endswith('.pc.in') and not filename.endswith('-uninstalled.pc.in') 798 return filename.endswith('.pc.in') and not filename.endswith('-uninstalled.pc.in')
799 799
800 pkg_config_files = self.wrksrc_find(relevant) 800 pkg_config_files = self.wrksrc_find(relevant)
801 801
802 if pkg_config_files: 802 if pkg_config_files:
803 self.build_vars.append(Var('USE_TOOLS', '+=', 'pkg-config')) 803 self.build_vars.append(Var('USE_TOOLS', '+=', 'pkg-config'))
804 for f in pkg_config_files: 804 for f in pkg_config_files:
805 self.extra_vars.append(Var('PKGCONFIG_OVERRIDE', '+=', f)) 805 self.extra_vars.append(Var('PKGCONFIG_OVERRIDE', '+=', f))
806 806
807 def adjust_po(self): 807 def adjust_po(self):
808 if self.wrksrc_find(r'\.(g?mo|po)$'): 808 if self.wrksrc_find(r'\.(g?mo|po)$'):
809 self.build_vars.append(Var('USE_PKGLOCALEDIR', '=', 'yes')) 809 self.build_vars.append(Var('USE_PKGLOCALEDIR', '=', 'yes'))
810 810
811 def adjust_use_languages(self): 811 def adjust_use_languages(self):
812 languages = [] 812 languages = []
813 813
814 if self.wrksrc_find(r'\.(c|xs)$'): 814 if self.wrksrc_find(r'\.(c|xs)$'):
815 languages.append('c') 815 languages.append('c')
816 if self.wrksrc_find(r'\.(cpp|c\+\+|cxx|cc|C)$'): 816 if self.wrksrc_find(r'\.(cpp|c\+\+|cxx|cc|C)$'):
817 languages.append('c++') 817 languages.append('c++')
818 if self.wrksrc_find(r'\.f$'): 818 if self.wrksrc_find(r'\.f$'):
819 languages.append('fortran') 819 languages.append('fortran')
820 820
821 use_languages = ' '.join(languages) 821 use_languages = ' '.join(languages)
822 if use_languages == '': 822 if use_languages == '':
823 use_languages = '# none' 823 use_languages = '# none'
824 if use_languages != 'c': 824 if use_languages != 'c':
825 self.build_vars.append(Var('USE_LANGUAGES', '=', use_languages)) 825 self.build_vars.append(Var('USE_LANGUAGES', '=', use_languages))
826 826
827 def determine_wrksrc(self): 827 def determine_wrksrc(self):
828 """ 828 """
829 Sets abs_wrksrc depending on abs_wrkdir and the files found there. 829 Sets abs_wrksrc depending on abs_wrkdir and the files found there.
830 """ 830 """
831 831
832 def relevant(f: Union[Path, Any]) -> bool: 832 def relevant(f: Union[Path, Any]) -> bool:
833 return f.is_dir() and not f.name.startswith('.') 833 return f.is_dir() and not f.name.startswith('.')
834 834
835 subdirs = [f.name for f in self.abs_wrkdir.glob('*') if relevant(f)] 835 subdirs = [f.name for f in self.abs_wrkdir.glob('*') if relevant(f)]
836 836
837 if len(subdirs) == 1: 837 if len(subdirs) == 1:
838 if subdirs[0] != self.makefile_lines.get('DISTNAME'): 838 if subdirs[0] != self.makefile_lines.get('DISTNAME'):
839 self.build_vars.append(Var('WRKSRC', '=', '${WRKDIR}/' + subdirs[0])) 839 self.build_vars.append(Var('WRKSRC', '=', '${WRKDIR}/' + subdirs[0]))
840 self.abs_wrksrc = self.abs_wrkdir / subdirs[0] 840 self.abs_wrksrc = self.abs_wrkdir / subdirs[0]
841 elif len(subdirs) == 0: 841 elif len(subdirs) == 0:
842 self.build_vars.append(Var('WRKSRC', '=', '${WRKDIR}')) 842 self.build_vars.append(Var('WRKSRC', '=', '${WRKDIR}'))
843 self.abs_wrksrc = self.abs_wrkdir 843 self.abs_wrksrc = self.abs_wrkdir
844 else: 844 else:
845 choices = ' '.join(subdirs) 845 choices = ' '.join(subdirs)
846 wrksrc = f'${{WRKDIR}} # TODO: one of {choices}, or leave it as-is' 846 wrksrc = f'${{WRKDIR}} # TODO: one of {choices}, or leave it as-is'
847 self.build_vars.append(Var('WRKSRC', '=', wrksrc)) 847 self.build_vars.append(Var('WRKSRC', '=', wrksrc))
848 self.abs_wrksrc = self.abs_wrkdir 848 self.abs_wrksrc = self.abs_wrkdir
849 849
850 def adjust_lines_python_module(self, lines: Lines): 850 def adjust_lines_python_module(self, lines: Lines):
851 851
852 initial_lines = self.initial_lines # as generated by url2pkg 852 initial_lines = self.initial_lines # as generated by url2pkg
853 edited_lines = self.makefile_lines # as edited by the package developer 853 edited_lines = self.makefile_lines # as edited by the package developer
854 854
855 if 'python' not in lines.get('CATEGORIES'): 855 if 'python' not in lines.get('CATEGORIES'):
856 return 856 return
857 if lines.get('GITHUB_PROJECT') == '': 857 if lines.get('GITHUB_PROJECT') == '':
858 return 858 return
859 859
860 # don't risk to overwrite any changes made by the package developer. 860 # don't risk to overwrite any changes made by the package developer.
861 if edited_lines.lines != initial_lines.lines: 861 if edited_lines.lines != initial_lines.lines:
862 lines.lines.insert(-2, '# TODO: Migrate MASTER_SITES to MASTER_SITE_PYPI') 862 lines.lines.insert(-2, '# TODO: Migrate MASTER_SITES to MASTER_SITE_PYPI')
863 return 863 return
864 864
865 pkgbase = initial_lines.get('GITHUB_PROJECT') 865 pkgbase = initial_lines.get('GITHUB_PROJECT')
866 pkgbase1 = pkgbase[:1] if pkgbase != '' else '' 866 pkgbase1 = pkgbase[:1] if pkgbase != '' else ''
867 pkgversion_norev = re.sub(r'^v', '', initial_lines.get('DISTNAME')) 867 pkgversion_norev = re.sub(r'^v', '', initial_lines.get('DISTNAME'))
868 868
869 tx_lines = Lines(*self.makefile_lines.lines) 869 tx_lines = Lines(*self.makefile_lines.lines)
870 if not (tx_lines.remove('GITHUB_PROJECT') 870 if not (tx_lines.remove('GITHUB_PROJECT')
871 and tx_lines.set('DISTNAME', f'{pkgbase}-{pkgversion_norev}') 871 and tx_lines.set('DISTNAME', f'{pkgbase}-{pkgversion_norev}')
872 and tx_lines.set('PKGNAME', '${PYPKGPREFIX}-${DISTNAME}') 872 and tx_lines.set('PKGNAME', '${PYPKGPREFIX}-${DISTNAME}')
873 and tx_lines.set('MASTER_SITES', f'${{MASTER_SITE_PYPI:={pkgbase1}/{pkgbase}/}}') 873 and tx_lines.set('MASTER_SITES', f'${{MASTER_SITE_PYPI:={pkgbase1}/{pkgbase}/}}')
874 and tx_lines.remove('DIST_SUBDIR')): 874 and tx_lines.remove('DIST_SUBDIR')):
875 return 875 return
876 876
877 tx_lines.remove_if('GITHUB_TAG', initial_lines.get('DISTNAME')) 877 tx_lines.remove_if('GITHUB_TAG', initial_lines.get('DISTNAME'))
878 tx_lines.remove_if('EXTRACT_SUFX', '.zip') 878 tx_lines.remove_if('EXTRACT_SUFX', '.zip')
879 879
880 up = self.up 880 g = self.g
881 try_mk = up.pkgdir / 'try-pypi.mk' 881 try_mk = g.pkgdir / 'try-pypi.mk'
882 tx_lines.write_to(try_mk) 882 tx_lines.write_to(try_mk)
883 args = [up.make, '-f', str(try_mk), 'distinfo'] 883 args = [g.make, '-f', str(try_mk), 'distinfo']
884 up.debug('running {0} to try PyPI', args) 884 g.debug('running {0} to try PyPI', args)
885 fetch_ok = subprocess.call(args, cwd=up.pkgdir) == 0 885 fetch_ok = subprocess.call(args, cwd=g.pkgdir) == 0
886 try_mk.unlink() 886 try_mk.unlink()
887 if not fetch_ok: 887 if not fetch_ok:
888 return 888 return
889 889
890 lines.lines = tx_lines.lines 890 lines.lines = tx_lines.lines
891 self.regenerate_distinfo = True 891 self.regenerate_distinfo = True
892 892
893 def generate_lines(self) -> Lines: 893 def generate_lines(self) -> Lines:
894 marker_index = self.makefile_lines.index(r'^# url2pkg-marker') 894 marker_index = self.makefile_lines.index(r'^# url2pkg-marker')
895 if marker_index == -1: 895 if marker_index == -1:
896 sys.exit('error: didn\'t find the url2pkg marker in the Makefile.') 896 sys.exit('error: didn\'t find the url2pkg marker in the Makefile.')
897 897
898 lines = Lines(*self.makefile_lines.lines[: marker_index]) 898 lines = Lines(*self.makefile_lines.lines[: marker_index])
899 899
900 if lines.get('PKGNAME') == '' and \ 900 if lines.get('PKGNAME') == '' and \
901 (self.pkgname_prefix != '' or self.pkgname_transform != ''): 901 (self.pkgname_prefix != '' or self.pkgname_transform != ''):
902 distname_index = lines.index(r'^DISTNAME=(\t+)') 902 distname_index = lines.index(r'^DISTNAME=(\t+)')
903 if distname_index != -1: 903 if distname_index != -1:
904 pkgname_line = f'PKGNAME=\t{self.pkgname_prefix}${{DISTNAME{self.pkgname_transform}}}' 904 pkgname_line = f'PKGNAME=\t{self.pkgname_prefix}${{DISTNAME{self.pkgname_transform}}}'
905 lines.lines.insert(distname_index + 1, pkgname_line) 905 lines.lines.insert(distname_index + 1, pkgname_line)
906 906
907 if self.todos: 907 if self.todos:
908 for todo in self.todos: 908 for todo in self.todos:
909 lines.add('# TODO: ' + todo) 909 lines.add('# TODO: ' + todo)
910 lines.add('') 910 lines.add('')
911 911
912 depend_vars = [] 912 depend_vars = []
913 depend_vars.extend(Var('BUILD_DEPENDS', '+=', d) for d in self.build_depends) 913 depend_vars.extend(Var('BUILD_DEPENDS', '+=', d) for d in self.build_depends)
914 depend_vars.extend(Var('DEPENDS', '+=', d) for d in self.depends) 914 depend_vars.extend(Var('DEPENDS', '+=', d) for d in self.depends)
915 depend_vars.extend(Var('TEST_DEPENDS', '+=', d) for d in self.test_depends) 915 depend_vars.extend(Var('TEST_DEPENDS', '+=', d) for d in self.test_depends)
916 lines.add_vars(*depend_vars) 916 lines.add_vars(*depend_vars)
917 917
918 lines.add_vars(*self.build_vars) 918 lines.add_vars(*self.build_vars)
919 lines.add_vars(*self.extra_vars) 919 lines.add_vars(*self.extra_vars)
920 920
921 lines.add(*self.bl3_lines) 921 lines.add(*self.bl3_lines)
922 lines.add(*(f'.include "{include}"' for include in self.includes)) 922 lines.add(*(f'.include "{include}"' for include in self.includes))
923 923
924 lines.add(*self.makefile_lines.lines[marker_index + 1:]) 924 lines.add(*self.makefile_lines.lines[marker_index + 1:])
925 925
926 lines.append('CATEGORIES', ' '.join(self.categories)) 926 lines.append('CATEGORIES', ' '.join(self.categories))
927 927
928 self.adjust_lines_python_module(lines) 928 self.adjust_lines_python_module(lines)
929 929
930 for varname in self.update_vars: 930 for varname in self.update_vars:
931 self.up.debug('update_var {0} {1}', varname, self.update_vars[varname]) 931 self.g.debug('update_var {0} {1}', varname, self.update_vars[varname])
932 lines.set(varname, self.update_vars[varname]) 932 lines.set(varname, self.update_vars[varname])
933 933
934 return lines 934 return lines
935 935
936 def adjust(self): 936 def adjust(self):
937 937
938 def scan(basedir: Union[Path, Any], only: Callable[[Path], bool]) -> List[str]: 938 def scan(basedir: Union[Path, Any], only: Callable[[Path], bool]) -> List[str]:
939 relevant = (f for f in basedir.rglob('*') if only(f)) 939 relevant = (f for f in basedir.rglob('*') if only(f))
940 relative = (str(f.relative_to(basedir)) for f in relevant) 940 relative = (str(f.relative_to(basedir)) for f in relevant)
941 return list(sorted((f for f in relative if not f.startswith('.')))) 941 return list(sorted((f for f in relative if not f.startswith('.'))))
942 942
943 self.up.debug('Adjusting the Makefile') 943 self.g.debug('Adjusting the Makefile')
944 self.makefile_lines = Lines.read_from(self.up.pkgdir / 'Makefile') 944 self.makefile_lines = Lines.read_from(self.g.pkgdir / 'Makefile')
945 945
946 self.abs_wrkdir = Path(self.up.show_var('WRKDIR')) 946 self.abs_wrkdir = Path(self.g.show_var('WRKDIR'))
947 self.determine_wrksrc() 947 self.determine_wrksrc()
948 self.wrksrc_dirs = scan(self.abs_wrksrc, Path.is_dir) 948 self.wrksrc_dirs = scan(self.abs_wrksrc, Path.is_dir)
949 self.wrksrc_files = scan(self.abs_wrksrc, Path.is_file) 949 self.wrksrc_files = scan(self.abs_wrksrc, Path.is_file)
950 950
951 self.adjust_configure() 951 self.adjust_configure()
952 self.adjust_cmake() 952 self.adjust_cmake()
953 self.adjust_meson() 953 self.adjust_meson()
954 self.adjust_gconf2_schemas() 954 self.adjust_gconf2_schemas()
955 self.adjust_libtool() 955 self.adjust_libtool()
956 self.adjust_perl_module() 956 self.adjust_perl_module()
957 self.adjust_python_module() 957 self.adjust_python_module()
958 self.adjust_cargo() 958 self.adjust_cargo()
959 self.adjust_pkg_config() 959 self.adjust_pkg_config()
960 self.adjust_po() 960 self.adjust_po()
961 self.adjust_use_languages() 961 self.adjust_use_languages()
962 962
963 self.generate_lines().write_to(self.up.pkgdir / 'Makefile') 963 self.generate_lines().write_to(self.g.pkgdir / 'Makefile')
964 964
965 if self.regenerate_distinfo: 965 if self.regenerate_distinfo:
966 self.up.bmake('distinfo') 966 self.g.bmake('distinfo')
967 967
968 968
969def main(argv: List[str], up: Url2Pkg): 969def main(argv: List[str], g: Globals):
970 if not os.path.isfile('../../mk/bsd.pkg.mk'): 970 if not os.path.isfile('../../mk/bsd.pkg.mk'):
971 sys.exit(f'{argv[0]}: must be run from a package directory (.../pkgsrc/category/package)') 971 sys.exit(f'{argv[0]}: must be run from a package directory (.../pkgsrc/category/package)')
972 972
973 try: 973 try:
974 opts, args = getopt.getopt(argv[1:], 'v', ['verbose']) 974 opts, args = getopt.getopt(argv[1:], 'v', ['verbose'])
975 for (opt, _) in opts: 975 for (opt, _) in opts:
976 if opt in ('-v', '--verbose'): 976 if opt in ('-v', '--verbose'):
977 up.verbose = True 977 g.verbose = True
978 except getopt.GetoptError: 978 except getopt.GetoptError:
979 sys.exit(f'usage: {argv[0]} [-v|--verbose] [URL]') 979 sys.exit(f'usage: {argv[0]} [-v|--verbose] [URL]')
980 980
981 url = args[0] if args else input('URL: ') 981 url = args[0] if args else input('URL: ')
982 if not re.fullmatch(r'\w+://[!-~]+?/[!-~]+', url): 982 if not re.fullmatch(r'\w+://[!-~]+?/[!-~]+', url):
983 sys.exit(f'url2pkg: invalid URL: {url}') 983 sys.exit(f'url2pkg: invalid URL: {url}')
984 984
985 initial_lines = Generator(url).generate_package(up) 985 initial_lines = Generator(url).generate_package(g)
986 Adjuster(up, url, initial_lines).adjust() 986 Adjuster(g, url, initial_lines).adjust()
987 987
988 up.out.write('\n') 988 g.out.write('\n')
989 up.out.write('Remember to run pkglint when you\'re done.\n') 989 g.out.write('Remember to run pkglint when you\'re done.\n')
990 up.out.write('See ../../doc/pkgsrc.txt to get some help.\n') 990 g.out.write('See ../../doc/pkgsrc.txt to get some help.\n')
991 up.out.write('\n') 991 g.out.write('\n')
992 992
993 993
994if __name__ == '__main__': 994if __name__ == '__main__':
995 main(sys.argv, Url2Pkg()) 995 main(sys.argv, Globals())

cvs diff -r1.19 -r1.20 pkgsrc/pkgtools/url2pkg/files/url2pkg_test.py (switch to unified diff)

--- pkgsrc/pkgtools/url2pkg/files/url2pkg_test.py 2019/10/12 17:28:44 1.19
+++ pkgsrc/pkgtools/url2pkg/files/url2pkg_test.py 2019/10/12 17:38:16 1.20
@@ -1,1451 +1,1451 @@ @@ -1,1451 +1,1451 @@
1# $NetBSD: url2pkg_test.py,v 1.19 2019/10/12 17:28:44 rillig Exp $ 1# $NetBSD: url2pkg_test.py,v 1.20 2019/10/12 17:38:16 rillig Exp $
2 2
3import pytest 3import pytest
4from url2pkg import * 4from url2pkg import *
5 5
6mkcvsid = '# $''NetBSD$' 6mkcvsid = '# $''NetBSD$'
7up: Url2Pkg 7g: Globals
8prev_dir = Path.cwd() 8prev_dir = Path.cwd()
9 9
10 10
11def setup_function(_): 11def setup_function(_):
12 global up 12 global g
13 13
14 up = Url2Pkg() 14 g = Globals()
15 os.chdir(up.pkgsrcdir / 'pkgtools' / 'url2pkg') 15 os.chdir(g.pkgsrcdir / 'pkgtools' / 'url2pkg')
16 16
17 class Wr: 17 class Wr:
18 def __init__(self) -> None: 18 def __init__(self) -> None:
19 self.buf = '' 19 self.buf = ''
20 20
21 def write(self, s: str): 21 def write(self, s: str):
22 self.buf += s 22 self.buf += s
23 23
24 def written(self) -> List[str]: 24 def written(self) -> List[str]:
25 result = self.buf 25 result = self.buf
26 self.buf = '' 26 self.buf = ''
27 return result.splitlines() 27 return result.splitlines()
28 28
29 up.out = Wr() 29 g.out = Wr()
30 up.err = Wr() 30 g.err = Wr()
31 31
32 32
33def teardown_function(_): 33def teardown_function(_):
34 os.chdir(prev_dir) 34 os.chdir(prev_dir)
35 assert up.out.written() == [] 35 assert g.out.written() == []
36 assert up.err.written() == [] 36 assert g.err.written() == []
37 37
38 38
39def str_vars(vars: List[Var]) -> List[str]: 39def str_vars(vars: List[Var]) -> List[str]:
40 def to_string(var): 40 def to_string(var):
41 return var.name + var.op + var.value 41 return var.name + var.op + var.value
42 42
43 return list(map(to_string, vars)) 43 return list(map(to_string, vars))
44 44
45 45
46def str_varassigns(varassigns: List[Varassign]) -> List[str]: 46def str_varassigns(varassigns: List[Varassign]) -> List[str]:
47 def to_string(v: Varassign) -> str: 47 def to_string(v: Varassign) -> str:
48 return f'{v.varname}{v.op}{v.indent}' \ 48 return f'{v.varname}{v.op}{v.indent}' \
49 f'{v.value}{v.space_after_value}{v.comment}' 49 f'{v.value}{v.space_after_value}{v.comment}'
50 50
51 return list(map(to_string, varassigns)) 51 return list(map(to_string, varassigns))
52 52
53 53
54def detab(lines: Lines) -> List[str]: 54def detab(lines: Lines) -> List[str]:
55 """ Replaces tabs with the appropriate amount of spaces. """ 55 """ Replaces tabs with the appropriate amount of spaces. """
56 56
57 def detab_line(line: str) -> str: 57 def detab_line(line: str) -> str:
58 detabbed = [] 58 detabbed = []
59 for ch in line: 59 for ch in line:
60 if ch == '\t': 60 if ch == '\t':
61 detabbed.append(' '[:8 - len(detabbed) % 8]) 61 detabbed.append(' '[:8 - len(detabbed) % 8])
62 else: 62 else:
63 detabbed.append(ch) 63 detabbed.append(ch)
64 return ''.join(detabbed) 64 return ''.join(detabbed)
65 65
66 return list(map(detab_line, lines.lines)) 66 return list(map(detab_line, lines.lines))
67 67
68 68
69def test_Url2Pkg_debug(): 69def test_Global_debug():
70 up.verbose = True 70 g.verbose = True
71 71
72 up.debug('plain message') 72 g.debug('plain message')
73 up.debug('list {0}', [1, 2, 3]) 73 g.debug('list {0}', [1, 2, 3])
74 up.debug('tuple {0}', (1, 2, 3)) 74 g.debug('tuple {0}', (1, 2, 3))
75 up.debug('cwd {0} env {1} cmd {2}', 'directory', {'VAR': 'value'}, 'command') 75 g.debug('cwd {0} env {1} cmd {2}', 'directory', {'VAR': 'value'}, 'command')
76 76
77 assert up.err.written() == [ 77 assert g.err.written() == [
78 'url2pkg: plain message', 78 'url2pkg: plain message',
79 'url2pkg: list [1, 2, 3]', 79 'url2pkg: list [1, 2, 3]',
80 'url2pkg: tuple (1, 2, 3)', 80 'url2pkg: tuple (1, 2, 3)',
81 'url2pkg: cwd \'directory\' env {\'VAR\': \'value\'} cmd \'command\'', 81 'url2pkg: cwd \'directory\' env {\'VAR\': \'value\'} cmd \'command\'',
82 ] 82 ]
83 83
84 84
85def test_Url2Pkg_bmake(): 85def test_Global_bmake():
86 up.verbose = True 86 g.verbose = True
87 up.make = 'echo' 87 g.make = 'echo'
88 88
89 up.bmake('hello', 'world') 89 g.bmake('hello', 'world')
90 90
91 assert up.err.written() == [ 91 assert g.err.written() == [
92 'url2pkg: running bmake (\'hello\', \'world\') in \'.\'', 92 'url2pkg: running bmake (\'hello\', \'world\') in \'.\'',
93 ] 93 ]
94 94
95 95
96def test_Lines__write_and_read(tmp_path: Path): 96def test_Lines__write_and_read(tmp_path: Path):
97 example = tmp_path / 'example' 97 example = tmp_path / 'example'
98 98
99 lines = Lines('1', '2', '3') 99 lines = Lines('1', '2', '3')
100 100
101 lines.write_to(example) 101 lines.write_to(example)
102 102
103 assert example.read_text() == '1\n2\n3\n' 103 assert example.read_text() == '1\n2\n3\n'
104 104
105 back = Lines.read_from(example) 105 back = Lines.read_from(example)
106 106
107 assert back.lines == ['1', '2', '3'] 107 assert back.lines == ['1', '2', '3']
108 108
109 109
110def test_Lines_all_varassigns(): 110def test_Lines_all_varassigns():
111 lines = Lines( 111 lines = Lines(
112 'OTHER=\tvalue', # unrelated variable name 112 'OTHER=\tvalue', # unrelated variable name
113 'VAR=\tvalue', 113 'VAR=\tvalue',
114 'VAR=value', # no space between operator and value 114 'VAR=value', # no space between operator and value
115 'VAR=\t# only comment', 115 'VAR=\t# only comment',
116 '#VAR=\t# commented variable assignment', 116 '#VAR=\t# commented variable assignment',
117 '#VAR=', 117 '#VAR=',
118 '# VAR=', # This is a regular comment 118 '# VAR=', # This is a regular comment
119 ) 119 )
120 120
121 assert str_varassigns(lines.all_varassigns('VAR')) == [ 121 assert str_varassigns(lines.all_varassigns('VAR')) == [
122 'VAR=\tvalue', 122 'VAR=\tvalue',
123 'VAR=value', 123 'VAR=value',
124 'VAR=\t# only comment', 124 'VAR=\t# only comment',
125 '#VAR=\t# commented variable assignment', 125 '#VAR=\t# commented variable assignment',
126 '#VAR=', 126 '#VAR=',
127 ] 127 ]
128 128
129 129
130def test_Lines_unique_varassign(): 130def test_Lines_unique_varassign():
131 lines = Lines( 131 lines = Lines(
132 'UNIQUE=\tunique', 132 'UNIQUE=\tunique',
133 'REPEATED=\tfirst', 133 'REPEATED=\tfirst',
134 'REPEATED+=\tlast', 134 'REPEATED+=\tlast',
135 ) 135 )
136 136
137 assert lines.unique_varassign('UNIQUE') is not None 137 assert lines.unique_varassign('UNIQUE') is not None
138 assert lines.unique_varassign('REPEATED') is None 138 assert lines.unique_varassign('REPEATED') is None
139 139
140 140
141def test_Lines_get(): 141def test_Lines_get():
142 lines = Lines( 142 lines = Lines(
143 'VAR=value', 143 'VAR=value',
144 'VAR=\tvalue # comment', 144 'VAR=\tvalue # comment',
145 'UNIQUE=\tunique', 145 'UNIQUE=\tunique',
146 '#COMMENTED=\tvalue', 146 '#COMMENTED=\tvalue',
147 ) 147 )
148 148
149 assert lines.get('VAR') == '' # too many values 149 assert lines.get('VAR') == '' # too many values
150 assert lines.get('ENOENT') == '' # not found 150 assert lines.get('ENOENT') == '' # not found
151 assert lines.get('UNIQUE') == 'unique' 151 assert lines.get('UNIQUE') == 'unique'
152 assert lines.get('COMMENTED') == '' # commented out 152 assert lines.get('COMMENTED') == '' # commented out
153 153
154 154
155def test_Lines_index(): 155def test_Lines_index():
156 lines = Lines('1', '2', '345') 156 lines = Lines('1', '2', '345')
157 157
158 assert lines.index('1') == 0 158 assert lines.index('1') == 0
159 assert lines.index('2') == 1 159 assert lines.index('2') == 1
160 assert lines.index('345') == 2 160 assert lines.index('345') == 2
161 assert lines.index('4') == 2 161 assert lines.index('4') == 2
162 162
163 assert lines.index(r'^(\d\d)\d$') == 2 163 assert lines.index(r'^(\d\d)\d$') == 2
164 assert lines.index(r'^\d\s\d$') == -1 164 assert lines.index(r'^\d\s\d$') == -1
165 assert lines.index(r'(\d)') == 0 165 assert lines.index(r'(\d)') == 0
166 166
167 167
168def test_Lines_add(): 168def test_Lines_add():
169 lines = Lines() 169 lines = Lines()
170 170
171 lines.add('') 171 lines.add('')
172 172
173 # Adding variables might also be supported one day. 173 # Adding variables might also be supported one day.
174 with pytest.raises(AssertionError): 174 with pytest.raises(AssertionError):
175 lines.add(Var('VAR', '=', 'value')) 175 lines.add(Var('VAR', '=', 'value'))
176 176
177 with pytest.raises(AssertionError): 177 with pytest.raises(AssertionError):
178 lines.add(1) 178 lines.add(1)
179 179
180 180
181def test_Lines_add_vars__simple(): 181def test_Lines_add_vars__simple():
182 lines = Lines() 182 lines = Lines()
183 183
184 lines.add_vars( 184 lines.add_vars(
185 Var('1', '=', 'one'), 185 Var('1', '=', 'one'),
186 Var('6', '=', 'six'), 186 Var('6', '=', 'six'),
187 ) 187 )
188 188
189 assert lines.lines == [ 189 assert lines.lines == [
190 '1=\tone', 190 '1=\tone',
191 '6=\tsix', 191 '6=\tsix',
192 '', 192 '',
193 ] 193 ]
194 194
195 195
196def test_Lines_add_vars__alignment(): 196def test_Lines_add_vars__alignment():
197 lines = Lines() 197 lines = Lines()
198 198
199 lines.add_vars( 199 lines.add_vars(
200 Var('short', '=', 'value'), 200 Var('short', '=', 'value'),
201 Var('long_name', '=', 'value # comment'), 201 Var('long_name', '=', 'value # comment'),
202 ) 202 )
203 203
204 assert lines.lines == [ 204 assert lines.lines == [
205 'short=\t\tvalue', 205 'short=\t\tvalue',
206 'long_name=\tvalue # comment', 206 'long_name=\tvalue # comment',
207 '', 207 '',
208 ] 208 ]
209 209
210 210
211def test_Lines_add_vars__operators(): 211def test_Lines_add_vars__operators():
212 lines = Lines() 212 lines = Lines()
213 213
214 lines.add_vars(Var('123456', '=', 'value')) 214 lines.add_vars(Var('123456', '=', 'value'))
215 lines.add_vars(Var('1234567', '=', 'value')) 215 lines.add_vars(Var('1234567', '=', 'value'))
216 lines.add_vars(Var('123456', '+=', 'value')) 216 lines.add_vars(Var('123456', '+=', 'value'))
217 217
218 assert lines.lines == [ 218 assert lines.lines == [
219 '123456=\tvalue', 219 '123456=\tvalue',
220 '', 220 '',
221 '1234567=\tvalue', 221 '1234567=\tvalue',
222 '', 222 '',
223 '123456+=\tvalue', 223 '123456+=\tvalue',
224 '', 224 '',
225 ] 225 ]
226 226
227 227
228def test_Lines_add_vars__empty(): 228def test_Lines_add_vars__empty():
229 lines = Lines('# initial') 229 lines = Lines('# initial')
230 230
231 lines.add_vars() 231 lines.add_vars()
232 232
233 # No empty line is added. 233 # No empty line is added.
234 assert lines.lines == ['# initial'] 234 assert lines.lines == ['# initial']
235 235
236 236
237def test_Lines_set__replace_comment(): 237def test_Lines_set__replace_comment():
238 lines = Lines('LICENSE=\t# TODO: see mk/license.mk') 238 lines = Lines('LICENSE=\t# TODO: see mk/license.mk')
239 239
240 assert lines.set('LICENSE', '${PERL5_LICENSE}') 240 assert lines.set('LICENSE', '${PERL5_LICENSE}')
241 241
242 assert lines.lines == ['LICENSE=\t${PERL5_LICENSE}'] 242 assert lines.lines == ['LICENSE=\t${PERL5_LICENSE}']
243 243
244 244
245def test_Lines_set__overwrite_commented_comment_with_comment(): 245def test_Lines_set__overwrite_commented_comment_with_comment():
246 lines = Lines('#LICENSE=\t# TODO: see mk/license.mk') 246 lines = Lines('#LICENSE=\t# TODO: see mk/license.mk')
247 247
248 assert lines.set('LICENSE', '${PERL5_LICENSE}') 248 assert lines.set('LICENSE', '${PERL5_LICENSE}')
249 249
250 assert lines.lines == ['LICENSE=\t${PERL5_LICENSE}'] 250 assert lines.lines == ['LICENSE=\t${PERL5_LICENSE}']
251 251
252 252
253def test_Lines_set__not_found(): 253def test_Lines_set__not_found():
254 lines = Lines('OLD_VAR=\told value # old comment') 254 lines = Lines('OLD_VAR=\told value # old comment')
255 255
256 assert not lines.set('NEW_VAR', 'new value') 256 assert not lines.set('NEW_VAR', 'new value')
257 257
258 assert lines.lines == ['OLD_VAR=\told value # old comment'] 258 assert lines.lines == ['OLD_VAR=\told value # old comment']
259 259
260 260
261def test_Lines_append__not_found(): 261def test_Lines_append__not_found():
262 lines = Lines() 262 lines = Lines()
263 263
264 lines.append('VARNAME', 'value') 264 lines.append('VARNAME', 'value')
265 265
266 assert lines.lines == [] 266 assert lines.lines == []
267 267
268 268
269def test_Lines_append__no_value_only_comment(): 269def test_Lines_append__no_value_only_comment():
270 lines = Lines('VARNAME=\t\t\t# none') 270 lines = Lines('VARNAME=\t\t\t# none')
271 271
272 lines.append('VARNAME', 'value') 272 lines.append('VARNAME', 'value')
273 273
274 assert lines.lines == ['VARNAME=\t\t\tvalue # none'] 274 assert lines.lines == ['VARNAME=\t\t\tvalue # none']
275 275
276 276
277def test_Lines_append__value_with_comment(): 277def test_Lines_append__value_with_comment():
278 lines = Lines('VARNAME=\tvalue # comment') 278 lines = Lines('VARNAME=\tvalue # comment')
279 279
280 lines.append('VARNAME', 'appended') 280 lines.append('VARNAME', 'appended')
281 281
282 assert lines.lines == ['VARNAME=\tvalue appended # comment'] 282 assert lines.lines == ['VARNAME=\tvalue appended # comment']
283 283
284 284
285def test_Lines_append__value_without_comment(): 285def test_Lines_append__value_without_comment():
286 lines = Lines('VARNAME+=\tvalue') 286 lines = Lines('VARNAME+=\tvalue')
287 287
288 assert lines.append('VARNAME', 'appended') 288 assert lines.append('VARNAME', 'appended')
289 289
290 assert lines.lines == ['VARNAME+=\tvalue appended'] 290 assert lines.lines == ['VARNAME+=\tvalue appended']
291 291
292 292
293def test_Lines_append__multiple_assignments(): 293def test_Lines_append__multiple_assignments():
294 # When there is more than one assignment for a variable, 294 # When there is more than one assignment for a variable,
295 # it may not be clear which to append to. 295 # it may not be clear which to append to.
296 # The assignments might be in an .if statement. 296 # The assignments might be in an .if statement.
297 # Therefore, rather do nothing. 297 # Therefore, rather do nothing.
298 # Assuming no .if statements, appending to the last one makes sense. 298 # Assuming no .if statements, appending to the last one makes sense.
299 299
300 lines = Lines('VARNAME+=\tvalue1', 'VARNAME+=\tvalue2') 300 lines = Lines('VARNAME+=\tvalue1', 'VARNAME+=\tvalue2')
301 301
302 assert not lines.append('VARNAME', 'appended') 302 assert not lines.append('VARNAME', 'appended')
303 303
304 assert lines.lines == ['VARNAME+=\tvalue1', 'VARNAME+=\tvalue2'] 304 assert lines.lines == ['VARNAME+=\tvalue1', 'VARNAME+=\tvalue2']
305 305
306 306
307def test_Lines_remove__not_found(): 307def test_Lines_remove__not_found():
308 lines = Lines('VAR=\tvalue') 308 lines = Lines('VAR=\tvalue')
309 309
310 assert not lines.remove('VARIABLE') 310 assert not lines.remove('VARIABLE')
311 311
312 assert lines.lines == ['VAR=\tvalue'] 312 assert lines.lines == ['VAR=\tvalue']
313 313
314 314
315def test_Lines_remove__found(): 315def test_Lines_remove__found():
316 lines = Lines('VAR=\tvalue') 316 lines = Lines('VAR=\tvalue')
317 317
318 assert lines.remove('VAR') 318 assert lines.remove('VAR')
319 319
320 assert lines.lines == [] 320 assert lines.lines == []
321 321
322 322
323def test_Lines_remove__found_several_times(): 323def test_Lines_remove__found_several_times():
324 lines = Lines('VAR=\tvalue1', 'VAR=\tvalue2') 324 lines = Lines('VAR=\tvalue1', 'VAR=\tvalue2')
325 325
326 assert not lines.remove('VAR') 326 assert not lines.remove('VAR')
327 327
328 assert lines.lines == ['VAR=\tvalue1', 'VAR=\tvalue2'] 328 assert lines.lines == ['VAR=\tvalue1', 'VAR=\tvalue2']
329 329
330 330
331def test_Lines_remove_if__different_name(): 331def test_Lines_remove_if__different_name():
332 lines = Lines('VAR=\tvalue') 332 lines = Lines('VAR=\tvalue')
333 333
334 assert not lines.remove_if('VARIABLE', 'value') 334 assert not lines.remove_if('VARIABLE', 'value')
335 335
336 assert lines.lines == ['VAR=\tvalue'] 336 assert lines.lines == ['VAR=\tvalue']
337 337
338 338
339def test_Lines_remove_if__different_value(): 339def test_Lines_remove_if__different_value():
340 lines = Lines('VAR=\tvalue') 340 lines = Lines('VAR=\tvalue')
341 341
342 assert not lines.remove_if('VAR', 'something') 342 assert not lines.remove_if('VAR', 'something')
343 343
344 assert lines.lines == ['VAR=\tvalue'] 344 assert lines.lines == ['VAR=\tvalue']
345 345
346 346
347def test_Lines_remove_if__found(): 347def test_Lines_remove_if__found():
348 lines = Lines('VAR=\tvalue') 348 lines = Lines('VAR=\tvalue')
349 349
350 assert lines.remove_if('VAR', 'value') 350 assert lines.remove_if('VAR', 'value')
351 351
352 assert lines.lines == [] 352 assert lines.lines == []
353 353
354 354
355def test_Lines_remove_if__multiple(): 355def test_Lines_remove_if__multiple():
356 lines = Lines('VAR=\tvalue', 'VAR=\tvalue') 356 lines = Lines('VAR=\tvalue', 'VAR=\tvalue')
357 357
358 assert lines.remove_if('VAR', 'value') 358 assert lines.remove_if('VAR', 'value')
359 359
360 assert lines.lines == ['VAR=\tvalue'] 360 assert lines.lines == ['VAR=\tvalue']
361 361
362 assert lines.remove_if('VAR', 'value') 362 assert lines.remove_if('VAR', 'value')
363 363
364 assert lines.lines == [] 364 assert lines.lines == []
365 365
366 366
367def test_Generator_adjust_site_SourceForge(): 367def test_Generator_adjust_site_SourceForge():
368 url = 'http://downloads.sourceforge.net/sourceforge/rfcascade/cascade-1.4.tar.gz' 368 url = 'http://downloads.sourceforge.net/sourceforge/rfcascade/cascade-1.4.tar.gz'
369 369
370 lines = Generator(url).generate_Makefile() 370 lines = Generator(url).generate_Makefile()
371 371
372 assert lines.lines == [ 372 assert lines.lines == [
373 mkcvsid, 373 mkcvsid,
374 '', 374 '',
375 'DISTNAME=\tcascade-1.4', 375 'DISTNAME=\tcascade-1.4',
376 'CATEGORIES=\tpkgtools', 376 'CATEGORIES=\tpkgtools',
377 'MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=rfcascade/}', 377 'MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=rfcascade/}',
378 '', 378 '',
379 'MAINTAINER=\tINSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 379 'MAINTAINER=\tINSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
380 'HOMEPAGE=\thttps://rfcascade.sourceforge.net/', 380 'HOMEPAGE=\thttps://rfcascade.sourceforge.net/',
381 'COMMENT=\tTODO: Short description of the package', 381 'COMMENT=\tTODO: Short description of the package',
382 '#LICENSE=\t# TODO: (see mk/license.mk)', 382 '#LICENSE=\t# TODO: (see mk/license.mk)',
383 '', 383 '',
384 '# url2pkg-marker (please do not remove this line.)', 384 '# url2pkg-marker (please do not remove this line.)',
385 ".include \"../../mk/bsd.pkg.mk\"", 385 ".include \"../../mk/bsd.pkg.mk\"",
386 ] 386 ]
387 387
388 388
389def test_Generator_adjust_site_GitHub_archive(): 389def test_Generator_adjust_site_GitHub_archive():
390 url = 'https://github.com/org/proj/archive/v1.0.0.tar.gz' 390 url = 'https://github.com/org/proj/archive/v1.0.0.tar.gz'
391 391
392 lines = Generator(url).generate_Makefile() 392 lines = Generator(url).generate_Makefile()
393 assert detab(lines) == [ 393 assert detab(lines) == [
394 mkcvsid, 394 mkcvsid,
395 '', 395 '',
396 'GITHUB_PROJECT= proj', 396 'GITHUB_PROJECT= proj',
397 'GITHUB_TAG= v1.0.0', 397 'GITHUB_TAG= v1.0.0',
398 'DISTNAME= v1.0.0', 398 'DISTNAME= v1.0.0',
399 'PKGNAME= ${GITHUB_PROJECT}-${DISTNAME:S,^v,,}', 399 'PKGNAME= ${GITHUB_PROJECT}-${DISTNAME:S,^v,,}',
400 'CATEGORIES= pkgtools', 400 'CATEGORIES= pkgtools',
401 'MASTER_SITES= ${MASTER_SITE_GITHUB:=org/}', 401 'MASTER_SITES= ${MASTER_SITE_GITHUB:=org/}',
402 'DIST_SUBDIR= ${GITHUB_PROJECT}', 402 'DIST_SUBDIR= ${GITHUB_PROJECT}',
403 '', 403 '',
404 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 404 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
405 'HOMEPAGE= https://github.com/org/proj/', 405 'HOMEPAGE= https://github.com/org/proj/',
406 'COMMENT= TODO: Short description of the package', 406 'COMMENT= TODO: Short description of the package',
407 '#LICENSE= # TODO: (see mk/license.mk)', 407 '#LICENSE= # TODO: (see mk/license.mk)',
408 '', 408 '',
409 '# url2pkg-marker (please do not remove this line.)', 409 '# url2pkg-marker (please do not remove this line.)',
410 ".include \"../../mk/bsd.pkg.mk\"", 410 ".include \"../../mk/bsd.pkg.mk\"",
411 ] 411 ]
412 412
413 413
414def test_Generator_adjust_site_GitHub_release__containing_project_name(): 414def test_Generator_adjust_site_GitHub_release__containing_project_name():
415 url = 'https://github.com/org/proj/releases/download/1.0.0/proj.zip' 415 url = 'https://github.com/org/proj/releases/download/1.0.0/proj.zip'
416 416
417 lines = Generator(url).generate_Makefile() 417 lines = Generator(url).generate_Makefile()
418 418
419 assert detab(lines) == [ 419 assert detab(lines) == [
420 mkcvsid, 420 mkcvsid,
421 '', 421 '',
422 'GITHUB_PROJECT= proj', 422 'GITHUB_PROJECT= proj',
423 'DISTNAME= proj', 423 'DISTNAME= proj',
424 'CATEGORIES= pkgtools', 424 'CATEGORIES= pkgtools',
425 'MASTER_SITES= ${MASTER_SITE_GITHUB:=org/}', 425 'MASTER_SITES= ${MASTER_SITE_GITHUB:=org/}',
426 'GITHUB_RELEASE= 1.0.0', 426 'GITHUB_RELEASE= 1.0.0',
427 'EXTRACT_SUFX= .zip', 427 'EXTRACT_SUFX= .zip',
428 '', 428 '',
429 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 429 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
430 'HOMEPAGE= https://github.com/org/proj/', 430 'HOMEPAGE= https://github.com/org/proj/',
431 'COMMENT= TODO: Short description of the package', 431 'COMMENT= TODO: Short description of the package',
432 '#LICENSE= # TODO: (see mk/license.mk)', 432 '#LICENSE= # TODO: (see mk/license.mk)',
433 '', 433 '',
434 '# url2pkg-marker (please do not remove this line.)', 434 '# url2pkg-marker (please do not remove this line.)',
435 ".include \"../../mk/bsd.pkg.mk\"" 435 ".include \"../../mk/bsd.pkg.mk\""
436 ] 436 ]
437 437
438 438
439def test_Generator_adjust_site_GitHub_release__not_containing_project_name(): 439def test_Generator_adjust_site_GitHub_release__not_containing_project_name():
440 url = 'https://github.com/org/proj/releases/download/1.0.0/data.zip' 440 url = 'https://github.com/org/proj/releases/download/1.0.0/data.zip'
441 441
442 lines = Generator(url).generate_Makefile() 442 lines = Generator(url).generate_Makefile()
443 443
444 assert detab(lines) == [ 444 assert detab(lines) == [
445 mkcvsid, 445 mkcvsid,
446 '', 446 '',
447 'GITHUB_PROJECT= proj', 447 'GITHUB_PROJECT= proj',
448 'DISTNAME= data', 448 'DISTNAME= data',
449 'CATEGORIES= pkgtools', 449 'CATEGORIES= pkgtools',
450 'MASTER_SITES= ${MASTER_SITE_GITHUB:=org/}', 450 'MASTER_SITES= ${MASTER_SITE_GITHUB:=org/}',
451 'GITHUB_RELEASE= 1.0.0', 451 'GITHUB_RELEASE= 1.0.0',
452 'EXTRACT_SUFX= .zip', 452 'EXTRACT_SUFX= .zip',
453 'DIST_SUBDIR= ${GITHUB_PROJECT}', 453 'DIST_SUBDIR= ${GITHUB_PROJECT}',
454 '', 454 '',
455 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 455 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
456 'HOMEPAGE= https://github.com/org/proj/', 456 'HOMEPAGE= https://github.com/org/proj/',
457 'COMMENT= TODO: Short description of the package', 457 'COMMENT= TODO: Short description of the package',
458 '#LICENSE= # TODO: (see mk/license.mk)', 458 '#LICENSE= # TODO: (see mk/license.mk)',
459 '', 459 '',
460 '# url2pkg-marker (please do not remove this line.)', 460 '# url2pkg-marker (please do not remove this line.)',
461 ".include \"../../mk/bsd.pkg.mk\"" 461 ".include \"../../mk/bsd.pkg.mk\""
462 ] 462 ]
463 463
464 464
465def test_Generator_adjust_site_from_sites_mk__with_subdir(): 465def test_Generator_adjust_site_from_sites_mk__with_subdir():
466 url = 'https://files.pythonhosted.org/packages/source/i/irc/irc-11.1.1.zip' 466 url = 'https://files.pythonhosted.org/packages/source/i/irc/irc-11.1.1.zip'
467 generator = Generator(url) 467 generator = Generator(url)
468 468
469 lines = generator.generate_Makefile() 469 lines = generator.generate_Makefile()
470 470
471 assert detab(lines) == [ 471 assert detab(lines) == [
472 mkcvsid, 472 mkcvsid,
473 '', 473 '',
474 'DISTNAME= irc-11.1.1', 474 'DISTNAME= irc-11.1.1',
475 'CATEGORIES= pkgtools', 475 'CATEGORIES= pkgtools',
476 'MASTER_SITES= ${MASTER_SITE_PYPI:=i/irc/}', 476 'MASTER_SITES= ${MASTER_SITE_PYPI:=i/irc/}',
477 'EXTRACT_SUFX= .zip', 477 'EXTRACT_SUFX= .zip',
478 '', 478 '',
479 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 479 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
480 'HOMEPAGE= https://files.pythonhosted.org/packages/source/i/irc/ # TODO: check', 480 'HOMEPAGE= https://files.pythonhosted.org/packages/source/i/irc/ # TODO: check',
481 'COMMENT= TODO: Short description of the package', 481 'COMMENT= TODO: Short description of the package',
482 '#LICENSE= # TODO: (see mk/license.mk)', 482 '#LICENSE= # TODO: (see mk/license.mk)',
483 '', 483 '',
484 '# url2pkg-marker (please do not remove this line.)', 484 '# url2pkg-marker (please do not remove this line.)',
485 '.include "../../mk/bsd.pkg.mk"', 485 '.include "../../mk/bsd.pkg.mk"',
486 ] 486 ]
487 487
488 488
489def test_Generator_adjust_site_from_sites_mk__without_subdir(): 489def test_Generator_adjust_site_from_sites_mk__without_subdir():
490 url = 'https://files.pythonhosted.org/packages/source/irc-11.1.1.zip' 490 url = 'https://files.pythonhosted.org/packages/source/irc-11.1.1.zip'
491 generator = Generator(url) 491 generator = Generator(url)
492 492
493 lines = generator.generate_Makefile() 493 lines = generator.generate_Makefile()
494 494
495 assert detab(lines) == [ 495 assert detab(lines) == [
496 mkcvsid, 496 mkcvsid,
497 '', 497 '',
498 'DISTNAME= irc-11.1.1', 498 'DISTNAME= irc-11.1.1',
499 'CATEGORIES= pkgtools', 499 'CATEGORIES= pkgtools',
500 'MASTER_SITES= ${MASTER_SITE_PYPI}', 500 'MASTER_SITES= ${MASTER_SITE_PYPI}',
501 'EXTRACT_SUFX= .zip', 501 'EXTRACT_SUFX= .zip',
502 '', 502 '',
503 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 503 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
504 'HOMEPAGE= # TODO', 504 'HOMEPAGE= # TODO',
505 'COMMENT= TODO: Short description of the package', 505 'COMMENT= TODO: Short description of the package',
506 '#LICENSE= # TODO: (see mk/license.mk)', 506 '#LICENSE= # TODO: (see mk/license.mk)',
507 '', 507 '',
508 '# url2pkg-marker (please do not remove this line.)', 508 '# url2pkg-marker (please do not remove this line.)',
509 '.include "../../mk/bsd.pkg.mk"', 509 '.include "../../mk/bsd.pkg.mk"',
510 ] 510 ]
511 511
512 512
513def test_Generator_adjust_site_from_sites_mk__GNU(): 513def test_Generator_adjust_site_from_sites_mk__GNU():
514 url = 'https://ftp.gnu.org/pub/gnu/cflow/cflow-1.6.tar.gz' 514 url = 'https://ftp.gnu.org/pub/gnu/cflow/cflow-1.6.tar.gz'
515 generator = Generator(url) 515 generator = Generator(url)
516 516
517 lines = generator.generate_Makefile() 517 lines = generator.generate_Makefile()
518 518
519 assert detab(lines) == [ 519 assert detab(lines) == [
520 mkcvsid, 520 mkcvsid,
521 '', 521 '',
522 'DISTNAME= cflow-1.6', 522 'DISTNAME= cflow-1.6',
523 'CATEGORIES= pkgtools', 523 'CATEGORIES= pkgtools',
524 'MASTER_SITES= ${MASTER_SITE_GNU:=cflow/}', 524 'MASTER_SITES= ${MASTER_SITE_GNU:=cflow/}',
525 '', 525 '',
526 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 526 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
527 'HOMEPAGE= https://www.gnu.org/software/cflow/', 527 'HOMEPAGE= https://www.gnu.org/software/cflow/',
528 'COMMENT= TODO: Short description of the package', 528 'COMMENT= TODO: Short description of the package',
529 '#LICENSE= # TODO: (see mk/license.mk)', 529 '#LICENSE= # TODO: (see mk/license.mk)',
530 '', 530 '',
531 '# url2pkg-marker (please do not remove this line.)', 531 '# url2pkg-marker (please do not remove this line.)',
532 '.include "../../mk/bsd.pkg.mk"', 532 '.include "../../mk/bsd.pkg.mk"',
533 ] 533 ]
534 534
535 535
536def test_Generator_adjust_site_from_sites_mk__R(tmp_path: Path): 536def test_Generator_adjust_site_from_sites_mk__R(tmp_path: Path):
537 up.pkgdir = tmp_path 537 g.pkgdir = tmp_path
538 url = 'http://cran.r-project.org/src/contrib/forecast_8.7.tar.gz' 538 url = 'http://cran.r-project.org/src/contrib/forecast_8.7.tar.gz'
539 generator = Generator(url) 539 generator = Generator(url)
540 540
541 with pytest.raises(SystemExit, match='^url2pkg: to create R packages, use pkgtools/R2pkg instead$'): 541 with pytest.raises(SystemExit, match='^url2pkg: to create R packages, use pkgtools/R2pkg instead$'):
542 generator.generate_Makefile() 542 generator.generate_Makefile()
543 543
544 assert list(tmp_path.glob('*')) == [] 544 assert list(tmp_path.glob('*')) == []
545 545
546 546
547def test_Generator_adjust_site_other__malformed_URL(): 547def test_Generator_adjust_site_other__malformed_URL():
548 # This error is supposed to be handled by the URL check in main. 548 # This error is supposed to be handled by the URL check in main.
549 549
550 error = "'NoneType' object has no attribute 'groups'" 550 error = "'NoneType' object has no attribute 'groups'"
551 with pytest.raises(AttributeError, match=error): 551 with pytest.raises(AttributeError, match=error):
552 Generator('localhost').generate_Makefile() 552 Generator('localhost').generate_Makefile()
553 553
554 554
555def test_Generator_adjust_everything_else__distname_version_with_v(): 555def test_Generator_adjust_everything_else__distname_version_with_v():
556 # Some version numbers have a leading 'v', derived from the Git tag name. 556 # Some version numbers have a leading 'v', derived from the Git tag name.
557 557
558 url = 'https://cpan.example.org/Algorithm-CheckDigits-v1.3.2.tar.gz' 558 url = 'https://cpan.example.org/Algorithm-CheckDigits-v1.3.2.tar.gz'
559 559
560 lines = Generator(url).generate_Makefile() 560 lines = Generator(url).generate_Makefile()
561 561
562 assert detab(lines) == [ 562 assert detab(lines) == [
563 mkcvsid, 563 mkcvsid,
564 '', 564 '',
565 'DISTNAME= Algorithm-CheckDigits-v1.3.2', 565 'DISTNAME= Algorithm-CheckDigits-v1.3.2',
566 'PKGNAME= ${DISTNAME:S,-v,-,}', 566 'PKGNAME= ${DISTNAME:S,-v,-,}',
567 'CATEGORIES= pkgtools', 567 'CATEGORIES= pkgtools',
568 'MASTER_SITES= https://cpan.example.org/', 568 'MASTER_SITES= https://cpan.example.org/',
569 '', 569 '',
570 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 570 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
571 'HOMEPAGE= https://cpan.example.org/', 571 'HOMEPAGE= https://cpan.example.org/',
572 'COMMENT= TODO: Short description of the package', 572 'COMMENT= TODO: Short description of the package',
573 '#LICENSE= # TODO: (see mk/license.mk)', 573 '#LICENSE= # TODO: (see mk/license.mk)',
574 '', 574 '',
575 '# url2pkg-marker (please do not remove this line.)', 575 '# url2pkg-marker (please do not remove this line.)',
576 '.include "../../mk/bsd.pkg.mk"' 576 '.include "../../mk/bsd.pkg.mk"'
577 ] 577 ]
578 578
579 579
580def test_Generator_adjust_everything_else__distfile_without_extension(): 580def test_Generator_adjust_everything_else__distfile_without_extension():
581 url = 'https://example.org/app-2019-10-05' 581 url = 'https://example.org/app-2019-10-05'
582 582
583 lines = Generator(url).generate_Makefile() 583 lines = Generator(url).generate_Makefile()
584 584
585 assert detab(lines) == [ 585 assert detab(lines) == [
586 mkcvsid, 586 mkcvsid,
587 '', 587 '',
588 'DISTNAME= app-2019-10-05', 588 'DISTNAME= app-2019-10-05',
589 'CATEGORIES= pkgtools', 589 'CATEGORIES= pkgtools',
590 'MASTER_SITES= https://example.org/', 590 'MASTER_SITES= https://example.org/',
591 'EXTRACT_SUFX= # none', 591 'EXTRACT_SUFX= # none',
592 '', 592 '',
593 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 593 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
594 'HOMEPAGE= https://example.org/', 594 'HOMEPAGE= https://example.org/',
595 'COMMENT= TODO: Short description of the package', 595 'COMMENT= TODO: Short description of the package',
596 '#LICENSE= # TODO: (see mk/license.mk)', 596 '#LICENSE= # TODO: (see mk/license.mk)',
597 '', 597 '',
598 '# url2pkg-marker (please do not remove this line.)', 598 '# url2pkg-marker (please do not remove this line.)',
599 '.include "../../mk/bsd.pkg.mk"' 599 '.include "../../mk/bsd.pkg.mk"'
600 ] 600 ]
601 601
602 602
603def test_Generator_adjust_everything_else__v8(): 603def test_Generator_adjust_everything_else__v8():
604 generator = Generator('https://example.org/v8-1.0.zip') 604 generator = Generator('https://example.org/v8-1.0.zip')
605 605
606 lines = generator.generate_Makefile() 606 lines = generator.generate_Makefile()
607 607
608 assert detab(lines) == [ 608 assert detab(lines) == [
609 mkcvsid, 609 mkcvsid,
610 '', 610 '',
611 'DISTNAME= v8-1.0', 611 'DISTNAME= v8-1.0',
612 'CATEGORIES= pkgtools', 612 'CATEGORIES= pkgtools',
613 'MASTER_SITES= https://example.org/', 613 'MASTER_SITES= https://example.org/',
614 'EXTRACT_SUFX= .zip', 614 'EXTRACT_SUFX= .zip',
615 '', 615 '',
616 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 616 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
617 'HOMEPAGE= https://example.org/', 617 'HOMEPAGE= https://example.org/',
618 'COMMENT= TODO: Short description of the package', 618 'COMMENT= TODO: Short description of the package',
619 '#LICENSE= # TODO: (see mk/license.mk)', 619 '#LICENSE= # TODO: (see mk/license.mk)',
620 '', 620 '',
621 '# url2pkg-marker (please do not remove this line.)', 621 '# url2pkg-marker (please do not remove this line.)',
622 '.include "../../mk/bsd.pkg.mk"', 622 '.include "../../mk/bsd.pkg.mk"',
623 ] 623 ]
624 624
625 625
626def test_Generator_generate_package(tmp_path: Path): 626def test_Generator_generate_package(tmp_path: Path):
627 url = 'https://ftp.gnu.org/pub/gnu/cflow/cflow-1.6.tar.gz' 627 url = 'https://ftp.gnu.org/pub/gnu/cflow/cflow-1.6.tar.gz'
628 up.editor = 'true' # the shell command 628 g.editor = 'true' # the shell command
629 up.make = 'true' # the shell command 629 g.make = 'true' # the shell command
630 up.pkgdir = tmp_path 630 g.pkgdir = tmp_path
631 631
632 Generator(url).generate_package(up) 632 Generator(url).generate_package(g)
633 633
634 assert (tmp_path / 'DESCR').read_text() == '' 634 assert (tmp_path / 'DESCR').read_text() == ''
635 assert len((tmp_path / 'Makefile').read_text().splitlines()) == 13 635 assert len((tmp_path / 'Makefile').read_text().splitlines()) == 13
636 assert (tmp_path / 'PLIST').read_text() == '@comment $''NetBSD$\n' 636 assert (tmp_path / 'PLIST').read_text() == '@comment $''NetBSD$\n'
637 637
638 # Since bmake is only fake in this test, the distinfo file is not created. 638 # Since bmake is only fake in this test, the distinfo file is not created.
639 expected_files = ['DESCR', 'Makefile', 'PLIST'] 639 expected_files = ['DESCR', 'Makefile', 'PLIST']
640 assert sorted([f.name for f in tmp_path.glob("*")]) == expected_files 640 assert sorted([f.name for f in tmp_path.glob("*")]) == expected_files
641 641
642 642
643def test_Adjuster_read_dependencies(): 643def test_Adjuster_read_dependencies():
644 child_process_output = [ 644 child_process_output = [
645 'DEPENDS\tpackage>=112.0:../../pkgtools/pkglint', 645 'DEPENDS\tpackage>=112.0:../../pkgtools/pkglint',
646 'DEPENDS\tpackage>=120.0:../../pkgtools/x11-links', 646 'DEPENDS\tpackage>=120.0:../../pkgtools/x11-links',
647 'BUILD_DEPENDS\turl2pkg>=1.0', 647 'BUILD_DEPENDS\turl2pkg>=1.0',
648 'BUILD_DEPENDS\tdoes-not-exist>=1.0', 648 'BUILD_DEPENDS\tdoes-not-exist>=1.0',
649 'TEST_DEPENDS\tpkglint', 649 'TEST_DEPENDS\tpkglint',
650 'A line that is not a dependency at all', 650 'A line that is not a dependency at all',
651 '', 651 '',
652 'var\tHOMEPAGE\thttps://homepage.example.org/', 652 'var\tHOMEPAGE\thttps://homepage.example.org/',
653 'var\t#LICENSE\tBSD # TODO: too unspecific', 653 'var\t#LICENSE\tBSD # TODO: too unspecific',
654 '' 654 ''
655 ] 655 ]
656 env = {'URL2PKG_DEPENDENCIES': '\n'.join(child_process_output)} 656 env = {'URL2PKG_DEPENDENCIES': '\n'.join(child_process_output)}
657 cmd = "printf '%s\n' \"$URL2PKG_DEPENDENCIES\"" 657 cmd = "printf '%s\n' \"$URL2PKG_DEPENDENCIES\""
658 658
659 adjuster = Adjuster(up, '', Lines()) 659 adjuster = Adjuster(g, '', Lines())
660 adjuster.read_dependencies(cmd, env, '.', '') 660 adjuster.read_dependencies(cmd, env, '.', '')
661 661
662 assert os.getenv('URL2PKG_DEPENDENCIES') is None 662 assert os.getenv('URL2PKG_DEPENDENCIES') is None
663 assert adjuster.depends == ['package>=112.0:../../pkgtools/pkglint'] 663 assert adjuster.depends == ['package>=112.0:../../pkgtools/pkglint']
664 assert adjuster.bl3_lines == [ 664 assert adjuster.bl3_lines == [
665 'BUILDLINK_API_DEPENDS.x11-links+=\tx11-links>=120.0', 665 'BUILDLINK_API_DEPENDS.x11-links+=\tx11-links>=120.0',
666 ".include \"../../pkgtools/x11-links/buildlink3.mk\"", 666 ".include \"../../pkgtools/x11-links/buildlink3.mk\"",
667 ] 667 ]
668 assert adjuster.build_depends == [ 668 assert adjuster.build_depends == [
669 'url2pkg>=1.0:../../pkgtools/url2pkg', 669 'url2pkg>=1.0:../../pkgtools/url2pkg',
670 '# TODO: does-not-exist>=1.0', 670 '# TODO: does-not-exist>=1.0',
671 ] 671 ]
672 assert adjuster.test_depends == ['pkglint>=0:../../pkgtools/pkglint'] 672 assert adjuster.test_depends == ['pkglint>=0:../../pkgtools/pkglint']
673 assert adjuster.update_vars == { 673 assert adjuster.update_vars == {
674 'HOMEPAGE': 'https://homepage.example.org/', 674 'HOMEPAGE': 'https://homepage.example.org/',
675 '#LICENSE': 'BSD # TODO: too unspecific', 675 '#LICENSE': 'BSD # TODO: too unspecific',
676 } 676 }
677 677
678 678
679def test_Adjuster_read_dependencies__lookup_with_prefix(): 679def test_Adjuster_read_dependencies__lookup_with_prefix():
680 child_process_output = [ 680 child_process_output = [
681 'DEPENDS\tpyobjc-framework-Quartz>=0', 681 'DEPENDS\tpyobjc-framework-Quartz>=0',
682 '' 682 ''
683 ] 683 ]
684 env = {'URL2PKG_DEPENDENCIES': '\n'.join(child_process_output)} 684 env = {'URL2PKG_DEPENDENCIES': '\n'.join(child_process_output)}
685 cmd = "printf '%s\n' \"$URL2PKG_DEPENDENCIES\"" 685 cmd = "printf '%s\n' \"$URL2PKG_DEPENDENCIES\""
686 686
687 adjuster = Adjuster(up, '', Lines()) 687 adjuster = Adjuster(g, '', Lines())
688 adjuster.read_dependencies(cmd, env, '.', 'py-') 688 adjuster.read_dependencies(cmd, env, '.', 'py-')
689 689
690 assert adjuster.depends == [ 690 assert adjuster.depends == [
691 'py-pyobjc-framework-Quartz>=0:../../devel/py-pyobjc-framework-Quartz', 691 'py-pyobjc-framework-Quartz>=0:../../devel/py-pyobjc-framework-Quartz',
692 ] 692 ]
693 693
694 694
695def test_Adjuster_wrksrc_grep(tmp_path: Path): 695def test_Adjuster_wrksrc_grep(tmp_path: Path):
696 adjuster = Adjuster(up, '', Lines()) 696 adjuster = Adjuster(g, '', Lines())
697 adjuster.abs_wrksrc = tmp_path 697 adjuster.abs_wrksrc = tmp_path
698 (tmp_path / 'file').write_text('\n'.join( 698 (tmp_path / 'file').write_text('\n'.join(
699 ('a', 'b', 'c', 'd', 'e', 'abc', 'def', 'ghi') 699 ('a', 'b', 'c', 'd', 'e', 'abc', 'def', 'ghi')
700 )) 700 ))
701 701
702 assert adjuster.wrksrc_grep('file', r'e') == ['e', 'def'] 702 assert adjuster.wrksrc_grep('file', r'e') == ['e', 'def']
703 assert adjuster.wrksrc_grep('file', r'(.)(.)(.)') == [ 703 assert adjuster.wrksrc_grep('file', r'(.)(.)(.)') == [
704 ['a', 'b', 'c'], 704 ['a', 'b', 'c'],
705 ['d', 'e', 'f'], 705 ['d', 'e', 'f'],
706 ['g', 'h', 'i'], 706 ['g', 'h', 'i'],
707 ] 707 ]
708 708
709 709
710def test_Adjuster_generate_adjusted_Makefile_lines(): 710def test_Adjuster_generate_adjusted_Makefile_lines():
711 adjuster = Adjuster(up, 'https://example.org/pkgname-1.0.tar.gz', Lines()) 711 adjuster = Adjuster(g, 'https://example.org/pkgname-1.0.tar.gz', Lines())
712 adjuster.makefile_lines = Lines( 712 adjuster.makefile_lines = Lines(
713 '# before 1', 713 '# before 1',
714 '# before 2', 714 '# before 2',
715 '# url2pkg-marker', 715 '# url2pkg-marker',
716 '# after 1', 716 '# after 1',
717 '# after 2' 717 '# after 2'
718 ) 718 )
719 719
720 lines = adjuster.generate_lines() 720 lines = adjuster.generate_lines()
721 721
722 assert lines.lines == [ 722 assert lines.lines == [
723 '# before 1', 723 '# before 1',
724 '# before 2', 724 '# before 2',
725 '# after 1', 725 '# after 1',
726 '# after 2', 726 '# after 2',
727 ] 727 ]
728 728
729 729
730def test_Adjuster_generate_adjusted_Makefile_lines__dependencies(): 730def test_Adjuster_generate_adjusted_Makefile_lines__dependencies():
731 adjuster = Adjuster(up, 'https://example.org/pkgname-1.0.tar.gz', Lines()) 731 adjuster = Adjuster(g, 'https://example.org/pkgname-1.0.tar.gz', Lines())
732 adjuster.makefile_lines.add( 732 adjuster.makefile_lines.add(
733 mkcvsid, 733 mkcvsid,
734 '', 734 '',
735 '# url2pkg-marker', 735 '# url2pkg-marker',
736 ".include \"../../mk/bsd.pkg.mk\"" 736 ".include \"../../mk/bsd.pkg.mk\""
737 ) 737 )
738 # some dependencies whose directory will not be found 738 # some dependencies whose directory will not be found
739 adjuster.add_dependency('DEPENDS', 'depends', '>=5.0', '../../devel/depends') 739 adjuster.add_dependency('DEPENDS', 'depends', '>=5.0', '../../devel/depends')
740 adjuster.add_dependency('TOOL_DEPENDS', 'tool-depends', '>=6.0', '../../devel/tool-depends') 740 adjuster.add_dependency('TOOL_DEPENDS', 'tool-depends', '>=6.0', '../../devel/tool-depends')
741 adjuster.add_dependency('BUILD_DEPENDS', 'build-depends', '>=7.0', '../../devel/build-depends') 741 adjuster.add_dependency('BUILD_DEPENDS', 'build-depends', '>=7.0', '../../devel/build-depends')
742 adjuster.add_dependency('TEST_DEPENDS', 'test-depends', '>=8.0', '../../devel/test-depends') 742 adjuster.add_dependency('TEST_DEPENDS', 'test-depends', '>=8.0', '../../devel/test-depends')
743 # some dependencies whose directory is explicitly given 743 # some dependencies whose directory is explicitly given
744 adjuster.depends.append('depends>=11.0:../../devel/depends') 744 adjuster.depends.append('depends>=11.0:../../devel/depends')
745 adjuster.build_depends.append('build-depends>=12.0:../../devel/build-depends') 745 adjuster.build_depends.append('build-depends>=12.0:../../devel/build-depends')
746 adjuster.test_depends.append('test-depends>=13.0:../../devel/test-depends') 746 adjuster.test_depends.append('test-depends>=13.0:../../devel/test-depends')
747 747
748 lines = adjuster.generate_lines() 748 lines = adjuster.generate_lines()
749 749
750 assert detab(lines) == [ 750 assert detab(lines) == [
751 mkcvsid, 751 mkcvsid,
752 '', 752 '',
753 '# TODO: dependency TOOL_DEPENDS # TODO: tool-depends>=6.0', 753 '# TODO: dependency TOOL_DEPENDS # TODO: tool-depends>=6.0',
754 '', 754 '',
755 'BUILD_DEPENDS+= # TODO: build-depends>=7.0', 755 'BUILD_DEPENDS+= # TODO: build-depends>=7.0',
756 'BUILD_DEPENDS+= build-depends>=12.0:../../devel/build-depends', 756 'BUILD_DEPENDS+= build-depends>=12.0:../../devel/build-depends',
757 'DEPENDS+= # TODO: depends>=5.0', 757 'DEPENDS+= # TODO: depends>=5.0',
758 'DEPENDS+= depends>=11.0:../../devel/depends', 758 'DEPENDS+= depends>=11.0:../../devel/depends',
759 'TEST_DEPENDS+= # TODO: test-depends>=8.0', 759 'TEST_DEPENDS+= # TODO: test-depends>=8.0',
760 'TEST_DEPENDS+= test-depends>=13.0:../../devel/test-depends', 760 'TEST_DEPENDS+= test-depends>=13.0:../../devel/test-depends',
761 '', 761 '',
762 ".include \"../../mk/bsd.pkg.mk\"" 762 ".include \"../../mk/bsd.pkg.mk\""
763 ] 763 ]
764 764
765 765
766def test_Adjuster_generate_adjusted_Makefile_lines__dont_overwrite_PKGNAME(): 766def test_Adjuster_generate_adjusted_Makefile_lines__dont_overwrite_PKGNAME():
767 adjuster = Adjuster(up, 'https://example.org/pkgname-1.0.tar.gz', Lines()) 767 adjuster = Adjuster(g, 'https://example.org/pkgname-1.0.tar.gz', Lines())
768 adjuster.makefile_lines.add( 768 adjuster.makefile_lines.add(
769 mkcvsid, 769 mkcvsid,
770 'DISTNAME=\tdistname-1.0', 770 'DISTNAME=\tdistname-1.0',
771 'PKGNAME=\tmanually-edited-pkgname-1.0' 771 'PKGNAME=\tmanually-edited-pkgname-1.0'
772 '', 772 '',
773 '# url2pkg-marker', 773 '# url2pkg-marker',
774 ".include \"../../mk/bsd.pkg.mk\"" 774 ".include \"../../mk/bsd.pkg.mk\""
775 ) 775 )
776 776
777 lines = adjuster.generate_lines() 777 lines = adjuster.generate_lines()
778 778
779 assert detab(lines) == [ 779 assert detab(lines) == [
780 mkcvsid, 780 mkcvsid,
781 'DISTNAME= distname-1.0', 781 'DISTNAME= distname-1.0',
782 'PKGNAME= manually-edited-pkgname-1.0', 782 'PKGNAME= manually-edited-pkgname-1.0',
783 ".include \"../../mk/bsd.pkg.mk\"" 783 ".include \"../../mk/bsd.pkg.mk\""
784 ] 784 ]
785 785
786 786
787def test_Adjuster_generate_adjusted_Makefile_lines__add_PKGNAME(): 787def test_Adjuster_generate_adjusted_Makefile_lines__add_PKGNAME():
788 adjuster = Adjuster(up, 'https://example.org/pkgname-1.0.tar.gz', Lines()) 788 adjuster = Adjuster(g, 'https://example.org/pkgname-1.0.tar.gz', Lines())
789 adjuster.makefile_lines.add( 789 adjuster.makefile_lines.add(
790 mkcvsid, 790 mkcvsid,
791 'DISTNAME=\tdistname-1.0', 791 'DISTNAME=\tdistname-1.0',
792 '', 792 '',
793 '# url2pkg-marker', 793 '# url2pkg-marker',
794 ".include \"../../mk/bsd.pkg.mk\"" 794 ".include \"../../mk/bsd.pkg.mk\""
795 ) 795 )
796 796
797 lines = adjuster.generate_lines() 797 lines = adjuster.generate_lines()
798 798
799 assert lines.lines == [ 799 assert lines.lines == [
800 mkcvsid, 800 mkcvsid,
801 'DISTNAME=\tdistname-1.0', 801 'DISTNAME=\tdistname-1.0',
802 '', 802 '',
803 ".include \"../../mk/bsd.pkg.mk\"" 803 ".include \"../../mk/bsd.pkg.mk\""
804 ] 804 ]
805 805
806 806
807def test_Adjuster_generate_adjusted_Makefile_lines__add_PKGNAME_with_prefix(): 807def test_Adjuster_generate_adjusted_Makefile_lines__add_PKGNAME_with_prefix():
808 adjuster = Adjuster(up, 'https://example.org/pkgname-1.0.tar.gz', Lines()) 808 adjuster = Adjuster(g, 'https://example.org/pkgname-1.0.tar.gz', Lines())
809 adjuster.makefile_lines.add( 809 adjuster.makefile_lines.add(
810 mkcvsid, 810 mkcvsid,
811 'DISTNAME=\tdistname-1.0', 811 'DISTNAME=\tdistname-1.0',
812 '', 812 '',
813 '# url2pkg-marker', 813 '# url2pkg-marker',
814 ".include \"../../mk/bsd.pkg.mk\"" 814 ".include \"../../mk/bsd.pkg.mk\""
815 ) 815 )
816 adjuster.pkgname_prefix = '${PYPKGPREFIX}-' 816 adjuster.pkgname_prefix = '${PYPKGPREFIX}-'
817 817
818 lines = adjuster.generate_lines() 818 lines = adjuster.generate_lines()
819 819
820 assert lines.lines == [ 820 assert lines.lines == [
821 mkcvsid, 821 mkcvsid,
822 'DISTNAME=\tdistname-1.0', 822 'DISTNAME=\tdistname-1.0',
823 'PKGNAME=\t${PYPKGPREFIX}-${DISTNAME}', 823 'PKGNAME=\t${PYPKGPREFIX}-${DISTNAME}',
824 '', 824 '',
825 ".include \"../../mk/bsd.pkg.mk\"" 825 ".include \"../../mk/bsd.pkg.mk\""
826 ] 826 ]
827 827
828 828
829def test_Adjuster_add_dependency__buildlink(): 829def test_Adjuster_add_dependency__buildlink():
830 # Note: this test only works because it runs in pkgtools/url2pkg, 830 # Note: this test only works because it runs in pkgtools/url2pkg,
831 # and from there the file ../../devel/libusb/buildlink3.mk is visible. 831 # and from there the file ../../devel/libusb/buildlink3.mk is visible.
832 832
833 adjuster = Adjuster(up, 'https://example.org/distfile-1.0.zip', Lines()) 833 adjuster = Adjuster(g, 'https://example.org/distfile-1.0.zip', Lines())
834 adjuster.makefile_lines.add('# url2pkg-marker') 834 adjuster.makefile_lines.add('# url2pkg-marker')
835 835
836 adjuster.add_dependency('BUILD_DEPENDS', 'libusb', '>=2019', '../../devel/libusb') 836 adjuster.add_dependency('BUILD_DEPENDS', 'libusb', '>=2019', '../../devel/libusb')
837 837
838 lines = adjuster.generate_lines() 838 lines = adjuster.generate_lines()
839 839
840 assert lines.lines == [ 840 assert lines.lines == [
841 'BUILDLINK_DEPENDS.libusb+=\tbuild', 841 'BUILDLINK_DEPENDS.libusb+=\tbuild',
842 'BUILDLINK_API_DEPENDS.libusb+=\tlibusb>=2019', 842 'BUILDLINK_API_DEPENDS.libusb+=\tlibusb>=2019',
843 '.include "../../devel/libusb/buildlink3.mk"', 843 '.include "../../devel/libusb/buildlink3.mk"',
844 ] 844 ]
845 845
846 846
847def test_Adjuster_adjust_cmake(tmp_path: Path): 847def test_Adjuster_adjust_cmake(tmp_path: Path):
848 adjuster = Adjuster(up, '', Lines()) 848 adjuster = Adjuster(g, '', Lines())
849 adjuster.abs_wrksrc = tmp_path 849 adjuster.abs_wrksrc = tmp_path
850 (tmp_path / 'CMakeLists.txt').touch() 850 (tmp_path / 'CMakeLists.txt').touch()
851 851
852 adjuster.adjust_cmake() 852 adjuster.adjust_cmake()
853 853
854 assert str_vars(adjuster.build_vars) == ['USE_CMAKE=yes'] 854 assert str_vars(adjuster.build_vars) == ['USE_CMAKE=yes']
855 855
856 856
857def test_Adjuster_adjust_configure__none(tmp_path: Path): 857def test_Adjuster_adjust_configure__none(tmp_path: Path):
858 adjuster = Adjuster(up, '', Lines()) 858 adjuster = Adjuster(g, '', Lines())
859 adjuster.abs_wrksrc = tmp_path 859 adjuster.abs_wrksrc = tmp_path
860 860
861 adjuster.adjust_configure() 861 adjuster.adjust_configure()
862 862
863 assert adjuster.build_vars == [] 863 assert adjuster.build_vars == []
864 864
865 865
866def test_Adjuster_adjust_configure__GNU(tmp_path: Path): 866def test_Adjuster_adjust_configure__GNU(tmp_path: Path):
867 adjuster = Adjuster(up, '', Lines()) 867 adjuster = Adjuster(g, '', Lines())
868 adjuster.abs_wrksrc = tmp_path 868 adjuster.abs_wrksrc = tmp_path
869 adjuster.wrksrc_files.append('configure') 869 adjuster.wrksrc_files.append('configure')
870 (tmp_path / 'configure').write_text('# Free Software Foundation\n') 870 (tmp_path / 'configure').write_text('# Free Software Foundation\n')
871 871
872 adjuster.adjust_configure() 872 adjuster.adjust_configure()
873 873
874 assert str_vars(adjuster.build_vars) == [ 874 assert str_vars(adjuster.build_vars) == [
875 'GNU_CONFIGURE=yes', 875 'GNU_CONFIGURE=yes',
876 ] 876 ]
877 877
878 878
879def test_Adjuster_adjust_configure__other(tmp_path: Path): 879def test_Adjuster_adjust_configure__other(tmp_path: Path):
880 adjuster = Adjuster(up, '', Lines()) 880 adjuster = Adjuster(g, '', Lines())
881 adjuster.abs_wrksrc = tmp_path 881 adjuster.abs_wrksrc = tmp_path
882 adjuster.wrksrc_files.append('configure') 882 adjuster.wrksrc_files.append('configure')
883 (tmp_path / 'configure').write_text('# A generic configure script\n') 883 (tmp_path / 'configure').write_text('# A generic configure script\n')
884 884
885 adjuster.adjust_configure() 885 adjuster.adjust_configure()
886 886
887 assert str_vars(adjuster.build_vars) == [ 887 assert str_vars(adjuster.build_vars) == [
888 'HAS_CONFIGURE=yes', 888 'HAS_CONFIGURE=yes',
889 ] 889 ]
890 890
891 891
892def test_Adjuster_adjust_cargo__not_found(tmp_path: Path): 892def test_Adjuster_adjust_cargo__not_found(tmp_path: Path):
893 adjuster = Adjuster(up, '', Lines()) 893 adjuster = Adjuster(g, '', Lines())
894 adjuster.abs_wrksrc = tmp_path 894 adjuster.abs_wrksrc = tmp_path
895 895
896 adjuster.adjust_cargo() 896 adjuster.adjust_cargo()
897 897
898 assert str_vars(adjuster.build_vars) == [] 898 assert str_vars(adjuster.build_vars) == []
899 899
900 900
901def test_Adjuster_adjust_cargo__found(tmp_path: Path): 901def test_Adjuster_adjust_cargo__found(tmp_path: Path):
902 adjuster = Adjuster(up, '', Lines()) 902 adjuster = Adjuster(g, '', Lines())
903 adjuster.abs_wrksrc = tmp_path 903 adjuster.abs_wrksrc = tmp_path
904 (tmp_path / 'Cargo.lock').write_text('"checksum cargo-pkg 1.2.3 1234"') 904 (tmp_path / 'Cargo.lock').write_text('"checksum cargo-pkg 1.2.3 1234"')
905 905
906 adjuster.adjust_cargo() 906 adjuster.adjust_cargo()
907 907
908 assert str_vars(adjuster.build_vars) == [ 908 assert str_vars(adjuster.build_vars) == [
909 'CARGO_CRATE_DEPENDS+=cargo-pkg-1.2.3', 909 'CARGO_CRATE_DEPENDS+=cargo-pkg-1.2.3',
910 ] 910 ]
911 911
912 912
913def test_Adjuster_adjust_gconf2(): 913def test_Adjuster_adjust_gconf2():
914 adjuster = Adjuster(up, '', Lines()) 914 adjuster = Adjuster(g, '', Lines())
915 adjuster.wrksrc_files = [ 915 adjuster.wrksrc_files = [
916 'file1.schemas', 916 'file1.schemas',
917 'file2.schemas.in', 917 'file2.schemas.in',
918 'file6.schemas.in.in.in.in.in.in', # realistic maximum is 2 times 918 'file6.schemas.in.in.in.in.in.in', # realistic maximum is 2 times
919 ] 919 ]
920 920
921 adjuster.adjust_gconf2_schemas() 921 adjuster.adjust_gconf2_schemas()
922 922
923 assert adjuster.includes == [ 923 assert adjuster.includes == [
924 '../../devel/GConf/schemas.mk', 924 '../../devel/GConf/schemas.mk',
925 ] 925 ]
926 assert str_vars(adjuster.extra_vars) == [ 926 assert str_vars(adjuster.extra_vars) == [
927 'GCONF_SCHEMAS+=file1.schemas', 927 'GCONF_SCHEMAS+=file1.schemas',
928 'GCONF_SCHEMAS+=file2.schemas', 928 'GCONF_SCHEMAS+=file2.schemas',
929 'GCONF_SCHEMAS+=file6.schemas', 929 'GCONF_SCHEMAS+=file6.schemas',
930 ] 930 ]
931 931
932 932
933def test_Adjuster_adjust_libtool__ltconfig(tmp_path: Path): 933def test_Adjuster_adjust_libtool__ltconfig(tmp_path: Path):
934 adjuster = Adjuster(up, '', Lines()) 934 adjuster = Adjuster(g, '', Lines())
935 adjuster.abs_wrksrc = tmp_path 935 adjuster.abs_wrksrc = tmp_path
936 (tmp_path / 'ltconfig').write_text('') 936 (tmp_path / 'ltconfig').write_text('')
937 937
938 adjuster.adjust_libtool() 938 adjuster.adjust_libtool()
939 939
940 assert str_vars(adjuster.build_vars) == ['USE_LIBTOOL=yes'] 940 assert str_vars(adjuster.build_vars) == ['USE_LIBTOOL=yes']
941 941
942 942
943def test_Adjuster_adjust_libtool__libltdl(tmp_path: Path): 943def test_Adjuster_adjust_libtool__libltdl(tmp_path: Path):
944 adjuster = Adjuster(up, '', Lines()) 944 adjuster = Adjuster(g, '', Lines())
945 adjuster.abs_wrksrc = tmp_path 945 adjuster.abs_wrksrc = tmp_path
946 (tmp_path / 'libltdl').mkdir() 946 (tmp_path / 'libltdl').mkdir()
947 947
948 adjuster.adjust_libtool() 948 adjuster.adjust_libtool()
949 949
950 assert adjuster.includes == [ 950 assert adjuster.includes == [
951 '../../devel/libltdl/convenience.mk', 951 '../../devel/libltdl/convenience.mk',
952 ] 952 ]
953 953
954 954
955def test_Adjuster_adjust_meson(tmp_path: Path): 955def test_Adjuster_adjust_meson(tmp_path: Path):
956 adjuster = Adjuster(up, '', Lines()) 956 adjuster = Adjuster(g, '', Lines())
957 adjuster.abs_wrksrc = tmp_path 957 adjuster.abs_wrksrc = tmp_path
958 (tmp_path / 'meson.build').touch() 958 (tmp_path / 'meson.build').touch()
959 959
960 adjuster.adjust_meson() 960 adjuster.adjust_meson()
961 961
962 assert adjuster.includes == ['../../devel/meson/build.mk'] 962 assert adjuster.includes == ['../../devel/meson/build.mk']
963 963
964 964
965def test_Adjuster_adjust_perl_module_Build_PL(tmp_path: Path): 965def test_Adjuster_adjust_perl_module_Build_PL(tmp_path: Path):
966 up.perl5 = 'echo perl5' 966 g.perl5 = 'echo perl5'
967 up.libdir = '/libdir' 967 g.libdir = '/libdir'
968 up.verbose = True 968 g.verbose = True
969 adjuster = Adjuster(up, '', Lines()) 969 adjuster = Adjuster(g, '', Lines())
970 adjuster.abs_wrksrc = tmp_path 970 adjuster.abs_wrksrc = tmp_path
971 971
972 adjuster.adjust_perl_module_Build_PL() 972 adjuster.adjust_perl_module_Build_PL()
973 973
974 assert str_vars(adjuster.build_vars) == ['PERL5_MODULE_TYPE=Module::Build'] 974 assert str_vars(adjuster.build_vars) == ['PERL5_MODULE_TYPE=Module::Build']
975 assert up.err.written() == [ 975 assert g.err.written() == [
976 f'url2pkg: reading dependencies: cd \'{tmp_path}\' && env {{}} \'echo perl5 -I/libdir -I. Build.PL\'', 976 f'url2pkg: reading dependencies: cd \'{tmp_path}\' && env {{}} \'echo perl5 -I/libdir -I. Build.PL\'',
977 'url2pkg: unknown dependency line: \'perl5 -I/libdir -I. Build.PL\'' 977 'url2pkg: unknown dependency line: \'perl5 -I/libdir -I. Build.PL\''
978 ] 978 ]
979 979
980 980
981def test_Adjuster_adjust_perl_module_Makefile_PL(tmp_path: Path): 981def test_Adjuster_adjust_perl_module_Makefile_PL(tmp_path: Path):
982 up.perl5 = 'echo perl5' 982 g.perl5 = 'echo perl5'
983 up.libdir = '/libdir' 983 g.libdir = '/libdir'
984 up.verbose = True 984 g.verbose = True
985 adjuster = Adjuster(up, '', Lines()) 985 adjuster = Adjuster(g, '', Lines())
986 adjuster.abs_wrksrc = tmp_path 986 adjuster.abs_wrksrc = tmp_path
987 987
988 adjuster.adjust_perl_module_Makefile_PL() 988 adjuster.adjust_perl_module_Makefile_PL()
989 989
990 assert str_vars(adjuster.build_vars) == [] 990 assert str_vars(adjuster.build_vars) == []
991 assert up.err.written() == [ 991 assert g.err.written() == [
992 f'url2pkg: reading dependencies: cd \'{tmp_path}\' && env {{}} \'echo perl5 -I/libdir -I. Makefile.PL\'', 992 f'url2pkg: reading dependencies: cd \'{tmp_path}\' && env {{}} \'echo perl5 -I/libdir -I. Makefile.PL\'',
993 'url2pkg: unknown dependency line: \'perl5 -I/libdir -I. Makefile.PL\'' 993 'url2pkg: unknown dependency line: \'perl5 -I/libdir -I. Makefile.PL\''
994 ] 994 ]
995 995
996 996
997def test_Adjuster_adjust_perl_module_homepage(): 997def test_Adjuster_adjust_perl_module_homepage():
998 adjuster = Adjuster(up, 'https://example.org/Perl-Module-1.0.tar.gz', Lines()) 998 adjuster = Adjuster(g, 'https://example.org/Perl-Module-1.0.tar.gz', Lines())
999 adjuster.makefile_lines.add_vars( 999 adjuster.makefile_lines.add_vars(
1000 Var('DISTNAME', '=', 'Perl-Module-1.0.tar.gz'), 1000 Var('DISTNAME', '=', 'Perl-Module-1.0.tar.gz'),
1001 Var('MASTER_SITES', '=', '${MASTER_SITE_PERL_CPAN:=subdir/}'), 1001 Var('MASTER_SITES', '=', '${MASTER_SITE_PERL_CPAN:=subdir/}'),
1002 Var('HOMEPAGE', '=', 'https://example.org/'), 1002 Var('HOMEPAGE', '=', 'https://example.org/'),
1003 ) 1003 )
1004 1004
1005 adjuster.adjust_perl_module_homepage() 1005 adjuster.adjust_perl_module_homepage()
1006 1006
1007 assert adjuster.makefile_lines.get('HOMEPAGE') == 'https://metacpan.org/pod/Perl::Module' 1007 assert adjuster.makefile_lines.get('HOMEPAGE') == 'https://metacpan.org/pod/Perl::Module'
1008 1008
1009 1009
1010def test_Adjuster_adjust_perl_module__Build_PL(tmp_path: Path): 1010def test_Adjuster_adjust_perl_module__Build_PL(tmp_path: Path):
1011 up.perl5 = 'echo perl5' 1011 g.perl5 = 'echo perl5'
1012 up.pkgdir = tmp_path # for removing the PLIST 1012 g.pkgdir = tmp_path # for removing the PLIST
1013 adjuster = Adjuster(up, 'https://example.org/Perl-Module-1.0.tar.gz', Lines()) 1013 adjuster = Adjuster(g, 'https://example.org/Perl-Module-1.0.tar.gz', Lines())
1014 adjuster.abs_wrksrc = tmp_path 1014 adjuster.abs_wrksrc = tmp_path
1015 adjuster.makefile_lines.add_vars( 1015 adjuster.makefile_lines.add_vars(
1016 Var('DISTNAME', '=', 'Perl-Module-1.0.tar.gz'), 1016 Var('DISTNAME', '=', 'Perl-Module-1.0.tar.gz'),
1017 Var('MASTER_SITES', '=', '${MASTER_SITE_PERL_CPAN:=subdir/}'), 1017 Var('MASTER_SITES', '=', '${MASTER_SITE_PERL_CPAN:=subdir/}'),
1018 Var('HOMEPAGE', '=', 'https://example.org/'), 1018 Var('HOMEPAGE', '=', 'https://example.org/'),
1019 ) 1019 )
1020 adjuster.makefile_lines.add('# url2pkg-marker') 1020 adjuster.makefile_lines.add('# url2pkg-marker')
1021 (tmp_path / 'Build.PL').touch() 1021 (tmp_path / 'Build.PL').touch()
1022 (tmp_path / 'PLIST').touch() 1022 (tmp_path / 'PLIST').touch()
1023 1023
1024 adjuster.adjust_perl_module() 1024 adjuster.adjust_perl_module()
1025 1025
1026 assert detab(adjuster.generate_lines()) == [ 1026 assert detab(adjuster.generate_lines()) == [
1027 'DISTNAME= Perl-Module-1.0.tar.gz', 1027 'DISTNAME= Perl-Module-1.0.tar.gz',
1028 'PKGNAME= p5-${DISTNAME}', 1028 'PKGNAME= p5-${DISTNAME}',
1029 'MASTER_SITES= ${MASTER_SITE_PERL_CPAN:=subdir/}', 1029 'MASTER_SITES= ${MASTER_SITE_PERL_CPAN:=subdir/}',
1030 'HOMEPAGE= https://metacpan.org/pod/Perl::Module', 1030 'HOMEPAGE= https://metacpan.org/pod/Perl::Module',
1031 '', 1031 '',
1032 'PERL5_MODULE_TYPE= Module::Build', 1032 'PERL5_MODULE_TYPE= Module::Build',
1033 'PERL5_PACKLIST= auto/Perl/Module/.packlist', 1033 'PERL5_PACKLIST= auto/Perl/Module/.packlist',
1034 '', 1034 '',
1035 '.include "../../lang/perl5/module.mk"', 1035 '.include "../../lang/perl5/module.mk"',
1036 ] 1036 ]
1037 assert not (tmp_path / 'PLIST').exists() 1037 assert not (tmp_path / 'PLIST').exists()
1038 1038
1039 1039
1040def test_Adjuster_adjust_perl_module__Makefile_PL_without_PLIST(tmp_path: Path): 1040def test_Adjuster_adjust_perl_module__Makefile_PL_without_PLIST(tmp_path: Path):
1041 # For code coverage, when PLIST cannot be unlinked. 1041 # For code coverage, when PLIST cannot be unlinked.
1042 1042
1043 up.perl5 = 'echo perl5' 1043 g.perl5 = 'echo perl5'
1044 up.pkgdir = tmp_path 1044 g.pkgdir = tmp_path
1045 adjuster = Adjuster(up, 'https://example.org/Mod-1.0.tar.gz', Lines()) 1045 adjuster = Adjuster(g, 'https://example.org/Mod-1.0.tar.gz', Lines())
1046 adjuster.abs_wrksrc = tmp_path 1046 adjuster.abs_wrksrc = tmp_path
1047 adjuster.makefile_lines.add_vars( 1047 adjuster.makefile_lines.add_vars(
1048 Var('DISTNAME', '=', 'Mod-1.0.tar.gz'), 1048 Var('DISTNAME', '=', 'Mod-1.0.tar.gz'),
1049 Var('MASTER_SITES', '=', '${MASTER_SITE_PERL_CPAN:=subdir/}'), 1049 Var('MASTER_SITES', '=', '${MASTER_SITE_PERL_CPAN:=subdir/}'),
1050 Var('HOMEPAGE', '=', 'https://example.org/'), 1050 Var('HOMEPAGE', '=', 'https://example.org/'),
1051 ) 1051 )
1052 adjuster.makefile_lines.add('# url2pkg-marker') 1052 adjuster.makefile_lines.add('# url2pkg-marker')
1053 (tmp_path / 'Makefile.PL').touch() 1053 (tmp_path / 'Makefile.PL').touch()
1054 1054
1055 adjuster.adjust_perl_module() 1055 adjuster.adjust_perl_module()
1056 1056
1057 assert not (tmp_path / 'PLIST').exists() 1057 assert not (tmp_path / 'PLIST').exists()
1058 1058
1059 1059
1060def test_Adjuster_adjust_python_module(tmp_path: Path): 1060def test_Adjuster_adjust_python_module(tmp_path: Path):
1061 url = 'https://example.org/Mod-1.0.tar.gz' 1061 url = 'https://example.org/Mod-1.0.tar.gz'
1062 up.pythonbin = 'echo python' 1062 g.pythonbin = 'echo python'
1063 up.pkgdir = tmp_path 1063 g.pkgdir = tmp_path
1064 adjuster = Adjuster(up, url, Lines()) 1064 adjuster = Adjuster(g, url, Lines())
1065 adjuster.abs_wrksrc = tmp_path 1065 adjuster.abs_wrksrc = tmp_path
1066 adjuster.makefile_lines = Generator(url).generate_Makefile() 1066 adjuster.makefile_lines = Generator(url).generate_Makefile()
1067 (tmp_path / 'setup.py').touch() 1067 (tmp_path / 'setup.py').touch()
1068 1068
1069 adjuster.adjust_python_module() 1069 adjuster.adjust_python_module()
1070 1070
1071 assert detab(adjuster.generate_lines()) == [ 1071 assert detab(adjuster.generate_lines()) == [
1072 mkcvsid, 1072 mkcvsid,
1073 '', 1073 '',
1074 'DISTNAME= Mod-1.0', 1074 'DISTNAME= Mod-1.0',
1075 'PKGNAME= ${PYPKGPREFIX}-${DISTNAME}', 1075 'PKGNAME= ${PYPKGPREFIX}-${DISTNAME}',
1076 'CATEGORIES= pkgtools python', 1076 'CATEGORIES= pkgtools python',
1077 'MASTER_SITES= https://example.org/', 1077 'MASTER_SITES= https://example.org/',
1078 '', 1078 '',
1079 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 1079 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
1080 'HOMEPAGE= https://example.org/', 1080 'HOMEPAGE= https://example.org/',
1081 'COMMENT= TODO: Short description of the package', 1081 'COMMENT= TODO: Short description of the package',
1082 '#LICENSE= # TODO: (see mk/license.mk)', 1082 '#LICENSE= # TODO: (see mk/license.mk)',
1083 '', 1083 '',
1084 '.include "../../lang/python/egg.mk"', 1084 '.include "../../lang/python/egg.mk"',
1085 '.include "../../mk/bsd.pkg.mk"', 1085 '.include "../../mk/bsd.pkg.mk"',
1086 ] 1086 ]
1087 1087
1088 1088
1089def test_Adjuster_adjust_po__not_found(): 1089def test_Adjuster_adjust_po__not_found():
1090 adjuster = Adjuster(up, '', Lines()) 1090 adjuster = Adjuster(g, '', Lines())
1091 1091
1092 adjuster.adjust_po() 1092 adjuster.adjust_po()
1093 1093
1094 assert adjuster.build_vars == [] 1094 assert adjuster.build_vars == []
1095 1095
1096 1096
1097def test_Adjuster_adjust_po__mo_found(): 1097def test_Adjuster_adjust_po__mo_found():
1098 adjuster = Adjuster(up, '', Lines()) 1098 adjuster = Adjuster(g, '', Lines())
1099 adjuster.wrksrc_files = ['share/locale/de.mo'] 1099 adjuster.wrksrc_files = ['share/locale/de.mo']
1100 1100
1101 adjuster.adjust_po() 1101 adjuster.adjust_po()
1102 1102
1103 assert str_vars(adjuster.build_vars) == ['USE_PKGLOCALEDIR=yes'] 1103 assert str_vars(adjuster.build_vars) == ['USE_PKGLOCALEDIR=yes']
1104 1104
1105 1105
1106def test_Adjuster_adjust_po__po_found(): 1106def test_Adjuster_adjust_po__po_found():
1107 adjuster = Adjuster(up, '', Lines()) 1107 adjuster = Adjuster(g, '', Lines())
1108 adjuster.wrksrc_files = ['po/de.po'] 1108 adjuster.wrksrc_files = ['po/de.po']
1109 1109
1110 adjuster.adjust_po() 1110 adjuster.adjust_po()
1111 1111
1112 assert str_vars(adjuster.build_vars) == ['USE_PKGLOCALEDIR=yes'] 1112 assert str_vars(adjuster.build_vars) == ['USE_PKGLOCALEDIR=yes']
1113 1113
1114 1114
1115def test_Adjuster_adjust_use_languages__none(): 1115def test_Adjuster_adjust_use_languages__none():
1116 adjuster = Adjuster(up, '', Lines()) 1116 adjuster = Adjuster(g, '', Lines())
1117 1117
1118 adjuster.adjust_use_languages() 1118 adjuster.adjust_use_languages()
1119 1119
1120 assert str_vars(adjuster.build_vars) == ['USE_LANGUAGES=# none'] 1120 assert str_vars(adjuster.build_vars) == ['USE_LANGUAGES=# none']
1121 1121
1122 1122
1123def test_Adjuster_adjust_use_languages__c(): 1123def test_Adjuster_adjust_use_languages__c():
1124 adjuster = Adjuster(up, '', Lines()) 1124 adjuster = Adjuster(g, '', Lines())
1125 adjuster.wrksrc_files = ['main.c'] 1125 adjuster.wrksrc_files = ['main.c']
1126 1126
1127 adjuster.adjust_use_languages() 1127 adjuster.adjust_use_languages()
1128 1128
1129 assert str_vars(adjuster.build_vars) == [] 1129 assert str_vars(adjuster.build_vars) == []
1130 1130
1131 1131
1132def test_Adjuster_adjust_use_languages__c_in_subdir(): 1132def test_Adjuster_adjust_use_languages__c_in_subdir():
1133 adjuster = Adjuster(up, '', Lines()) 1133 adjuster = Adjuster(g, '', Lines())
1134 adjuster.wrksrc_files = ['subdir/main.c'] 1134 adjuster.wrksrc_files = ['subdir/main.c']
1135 1135
1136 adjuster.adjust_use_languages() 1136 adjuster.adjust_use_languages()
1137 1137
1138 assert str_vars(adjuster.build_vars) == [] 1138 assert str_vars(adjuster.build_vars) == []
1139 1139
1140 1140
1141def test_Adjuster_adjust_use_languages__cplusplus_in_subdir(): 1141def test_Adjuster_adjust_use_languages__cplusplus_in_subdir():
1142 adjuster = Adjuster(up, '', Lines()) 1142 adjuster = Adjuster(g, '', Lines())
1143 adjuster.wrksrc_files = ['subdir/main.cpp'] 1143 adjuster.wrksrc_files = ['subdir/main.cpp']
1144 1144
1145 adjuster.adjust_use_languages() 1145 adjuster.adjust_use_languages()
1146 1146
1147 assert str_vars(adjuster.build_vars) == ['USE_LANGUAGES=c++'] 1147 assert str_vars(adjuster.build_vars) == ['USE_LANGUAGES=c++']
1148 1148
1149 1149
1150def test_Adjuster_adjust_use_languages__cplusplus_and_fortran(): 1150def test_Adjuster_adjust_use_languages__cplusplus_and_fortran():
1151 adjuster = Adjuster(up, '', Lines()) 1151 adjuster = Adjuster(g, '', Lines())
1152 adjuster.wrksrc_files = ['subdir/main.cpp', 'main.f'] 1152 adjuster.wrksrc_files = ['subdir/main.cpp', 'main.f']
1153 1153
1154 adjuster.adjust_use_languages() 1154 adjuster.adjust_use_languages()
1155 1155
1156 assert str_vars(adjuster.build_vars) == ['USE_LANGUAGES=c++ fortran'] 1156 assert str_vars(adjuster.build_vars) == ['USE_LANGUAGES=c++ fortran']
1157 1157
1158 1158
1159def test_Adjuster_adjust_pkg_config__none(): 1159def test_Adjuster_adjust_pkg_config__none():
1160 adjuster = Adjuster(up, '', Lines()) 1160 adjuster = Adjuster(g, '', Lines())
1161 1161
1162 adjuster.adjust_pkg_config() 1162 adjuster.adjust_pkg_config()
1163 1163
1164 assert str_vars(adjuster.build_vars) == [] 1164 assert str_vars(adjuster.build_vars) == []
1165 assert str_vars(adjuster.extra_vars) == [] 1165 assert str_vars(adjuster.extra_vars) == []
1166 1166
1167 1167
1168def test_Adjuster_adjust_pkg_config__pc_in(): 1168def test_Adjuster_adjust_pkg_config__pc_in():
1169 adjuster = Adjuster(up, '', Lines()) 1169 adjuster = Adjuster(g, '', Lines())
1170 adjuster.wrksrc_files = ['library.pc.in'] 1170 adjuster.wrksrc_files = ['library.pc.in']
1171 1171
1172 adjuster.adjust_pkg_config() 1172 adjuster.adjust_pkg_config()
1173 1173
1174 assert str_vars(adjuster.build_vars) == ['USE_TOOLS+=pkg-config'] 1174 assert str_vars(adjuster.build_vars) == ['USE_TOOLS+=pkg-config']
1175 assert str_vars(adjuster.extra_vars) == ['PKGCONFIG_OVERRIDE+=library.pc.in'] 1175 assert str_vars(adjuster.extra_vars) == ['PKGCONFIG_OVERRIDE+=library.pc.in']
1176 1176
1177 1177
1178def test_Adjuster_adjust_pkg_config__uninstalled_pc_in(): 1178def test_Adjuster_adjust_pkg_config__uninstalled_pc_in():
1179 adjuster = Adjuster(up, '', Lines()) 1179 adjuster = Adjuster(g, '', Lines())
1180 adjuster.wrksrc_files = ['library-uninstalled.pc.in'] 1180 adjuster.wrksrc_files = ['library-uninstalled.pc.in']
1181 1181
1182 adjuster.adjust_pkg_config() 1182 adjuster.adjust_pkg_config()
1183 1183
1184 assert str_vars(adjuster.build_vars) == [] 1184 assert str_vars(adjuster.build_vars) == []
1185 assert str_vars(adjuster.extra_vars) == [] 1185 assert str_vars(adjuster.extra_vars) == []
1186 1186
1187 1187
1188def test_Adjuster_adjust_pkg_config__both(): 1188def test_Adjuster_adjust_pkg_config__both():
1189 adjuster = Adjuster(up, '', Lines()) 1189 adjuster = Adjuster(g, '', Lines())
1190 adjuster.wrksrc_files = [ 1190 adjuster.wrksrc_files = [
1191 'library.pc.in', 1191 'library.pc.in',
1192 'library-uninstalled.pc.in', 1192 'library-uninstalled.pc.in',
1193 ] 1193 ]
1194 1194
1195 adjuster.adjust_pkg_config() 1195 adjuster.adjust_pkg_config()
1196 1196
1197 assert str_vars(adjuster.build_vars) == ['USE_TOOLS+=pkg-config'] 1197 assert str_vars(adjuster.build_vars) == ['USE_TOOLS+=pkg-config']
1198 assert str_vars(adjuster.extra_vars) == ['PKGCONFIG_OVERRIDE+=library.pc.in'] 1198 assert str_vars(adjuster.extra_vars) == ['PKGCONFIG_OVERRIDE+=library.pc.in']
1199 1199
1200 1200
1201def test_Adjuster_generate_lines(): 1201def test_Adjuster_generate_lines():
1202 url = 'https://dummy.example.org/package-1.0.tar.gz' 1202 url = 'https://dummy.example.org/package-1.0.tar.gz'
1203 adjuster = Adjuster(up, url, Lines()) 1203 adjuster = Adjuster(g, url, Lines())
1204 adjuster.makefile_lines = Generator(url).generate_Makefile() 1204 adjuster.makefile_lines = Generator(url).generate_Makefile()
1205 adjuster.update_vars['HOMEPAGE'] = 'https://example.org/' 1205 adjuster.update_vars['HOMEPAGE'] = 'https://example.org/'
1206 adjuster.update_vars['#LICENSE'] = 'BSD # TODO: too unspecific' 1206 adjuster.update_vars['#LICENSE'] = 'BSD # TODO: too unspecific'
1207 adjuster.depends.append('dependency>=0:../../category/dependency') 1207 adjuster.depends.append('dependency>=0:../../category/dependency')
1208 adjuster.todos.append('Run pkglint') 1208 adjuster.todos.append('Run pkglint')
1209 1209
1210 lines = adjuster.generate_lines() 1210 lines = adjuster.generate_lines()
1211 1211
1212 assert detab(lines) == [ 1212 assert detab(lines) == [
1213 mkcvsid, 1213 mkcvsid,
1214 '', 1214 '',
1215 'DISTNAME= package-1.0', 1215 'DISTNAME= package-1.0',
1216 'CATEGORIES= pkgtools', 1216 'CATEGORIES= pkgtools',
1217 'MASTER_SITES= https://dummy.example.org/', 1217 'MASTER_SITES= https://dummy.example.org/',
1218 '', 1218 '',
1219 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 1219 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
1220 'HOMEPAGE= https://example.org/', 1220 'HOMEPAGE= https://example.org/',
1221 'COMMENT= TODO: Short description of the package', 1221 'COMMENT= TODO: Short description of the package',
1222 '#LICENSE= BSD # TODO: too unspecific', 1222 '#LICENSE= BSD # TODO: too unspecific',
1223 '', 1223 '',
1224 '# TODO: Run pkglint', 1224 '# TODO: Run pkglint',
1225 '', 1225 '',
1226 'DEPENDS+= dependency>=0:../../category/dependency', 1226 'DEPENDS+= dependency>=0:../../category/dependency',
1227 '', 1227 '',
1228 '.include "../../mk/bsd.pkg.mk"', 1228 '.include "../../mk/bsd.pkg.mk"',
1229 ] 1229 ]
1230 1230
1231 1231
1232def test_Adjuster_determine_wrksrc__no_files(tmp_path: Path): 1232def test_Adjuster_determine_wrksrc__no_files(tmp_path: Path):
1233 adjuster = Adjuster(up, '', Lines()) 1233 adjuster = Adjuster(g, '', Lines())
1234 adjuster.abs_wrkdir = tmp_path 1234 adjuster.abs_wrkdir = tmp_path
1235 1235
1236 adjuster.determine_wrksrc() 1236 adjuster.determine_wrksrc()
1237 1237
1238 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir 1238 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir
1239 1239
1240 1240
1241def test_Adjuster_determine_wrksrc__single_dir(tmp_path: Path): 1241def test_Adjuster_determine_wrksrc__single_dir(tmp_path: Path):
1242 adjuster = Adjuster(up, '', Lines()) 1242 adjuster = Adjuster(g, '', Lines())
1243 adjuster.abs_wrkdir = tmp_path 1243 adjuster.abs_wrkdir = tmp_path
1244 (tmp_path / 'subdir').mkdir() 1244 (tmp_path / 'subdir').mkdir()
1245 1245
1246 adjuster.determine_wrksrc() 1246 adjuster.determine_wrksrc()
1247 1247
1248 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir / 'subdir' 1248 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir / 'subdir'
1249 1249
1250 1250
1251def test_Adjuster_determine_wrksrc__distname_dir(tmp_path: Path): 1251def test_Adjuster_determine_wrksrc__distname_dir(tmp_path: Path):
1252 adjuster = Adjuster(up, '', Lines()) 1252 adjuster = Adjuster(g, '', Lines())
1253 adjuster.abs_wrkdir = tmp_path 1253 adjuster.abs_wrkdir = tmp_path
1254 adjuster.makefile_lines.add_vars(Var('DISTNAME', '=', 'distname-1.0')) 1254 adjuster.makefile_lines.add_vars(Var('DISTNAME', '=', 'distname-1.0'))
1255 (tmp_path / 'distname-1.0').mkdir() 1255 (tmp_path / 'distname-1.0').mkdir()
1256 1256
1257 adjuster.determine_wrksrc() 1257 adjuster.determine_wrksrc()
1258 1258
1259 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir / 'distname-1.0' 1259 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir / 'distname-1.0'
1260 assert str_vars(adjuster.build_vars) == [] 1260 assert str_vars(adjuster.build_vars) == []
1261 1261
1262 1262
1263def test_Adjuster_determine_wrksrc__several_dirs(tmp_path: Path): 1263def test_Adjuster_determine_wrksrc__several_dirs(tmp_path: Path):
1264 adjuster = Adjuster(up, '', Lines()) 1264 adjuster = Adjuster(g, '', Lines())
1265 adjuster.abs_wrkdir = tmp_path 1265 adjuster.abs_wrkdir = tmp_path
1266 (tmp_path / 'subdir1').mkdir() 1266 (tmp_path / 'subdir1').mkdir()
1267 (tmp_path / 'subdir2').mkdir() 1267 (tmp_path / 'subdir2').mkdir()
1268 1268
1269 adjuster.determine_wrksrc() 1269 adjuster.determine_wrksrc()
1270 1270
1271 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir 1271 assert adjuster.abs_wrksrc == adjuster.abs_wrkdir
1272 assert str_vars(adjuster.build_vars) == [ 1272 assert str_vars(adjuster.build_vars) == [
1273 'WRKSRC=${WRKDIR} # TODO: one of subdir1 subdir2, or leave it as-is', 1273 'WRKSRC=${WRKDIR} # TODO: one of subdir1 subdir2, or leave it as-is',
1274 ] 1274 ]
1275 1275
1276 1276
1277def test_Adjuster_adjust__empty_wrkdir(tmp_path: Path): 1277def test_Adjuster_adjust__empty_wrkdir(tmp_path: Path):
1278 up.pkgdir = tmp_path 1278 g.pkgdir = tmp_path
1279 up.show_var = lambda varname: {'WRKDIR': str(tmp_path)}[varname] 1279 g.show_var = lambda varname: {'WRKDIR': str(tmp_path)}[varname]
1280 adjuster = Adjuster(up, 'https://example.org/distfile-1.0.zip', Lines()) 1280 adjuster = Adjuster(g, 'https://example.org/distfile-1.0.zip', Lines())
1281 (tmp_path / 'Makefile').write_text('# url2pkg-marker\n') 1281 (tmp_path / 'Makefile').write_text('# url2pkg-marker\n')
1282 1282
1283 adjuster.adjust() 1283 adjuster.adjust()
1284 1284
1285 assert detab(adjuster.generate_lines()) == [ 1285 assert detab(adjuster.generate_lines()) == [
1286 'WRKSRC= ${WRKDIR}', 1286 'WRKSRC= ${WRKDIR}',
1287 'USE_LANGUAGES= # none', 1287 'USE_LANGUAGES= # none',
1288 '', 1288 '',
1289 ] 1289 ]
1290 1290
1291 1291
1292def test_Adjuster_adjust__files_in_wrksrc(tmp_path: Path): 1292def test_Adjuster_adjust__files_in_wrksrc(tmp_path: Path):
1293 wrkdir = tmp_path / 'work' 1293 wrkdir = tmp_path / 'work'
1294 wrkdir.mkdir() 1294 wrkdir.mkdir()
1295 (wrkdir / '.hidden').touch() 1295 (wrkdir / '.hidden').touch()
1296 (wrkdir / 'file').touch() 1296 (wrkdir / 'file').touch()
1297 (wrkdir / 'dir').mkdir() 1297 (wrkdir / 'dir').mkdir()
1298 (wrkdir / 'dir' / '.hidden-dir').mkdir() 1298 (wrkdir / 'dir' / '.hidden-dir').mkdir()
1299 (wrkdir / 'dir' / 'subdir').mkdir() 1299 (wrkdir / 'dir' / 'subdir').mkdir()
1300 (wrkdir / 'dir' / 'subdir' / '.hidden').touch() 1300 (wrkdir / 'dir' / 'subdir' / '.hidden').touch()
1301 (wrkdir / 'dir' / 'subdir' / 'file').touch() 1301 (wrkdir / 'dir' / 'subdir' / 'file').touch()
1302 (wrkdir / 'dir2').mkdir() # to make WRKSRC = WRKDIR 1302 (wrkdir / 'dir2').mkdir() # to make WRKSRC = WRKDIR
1303 up.show_var = lambda varname: {'WRKDIR': str(wrkdir)}[varname] 1303 g.show_var = lambda varname: {'WRKDIR': str(wrkdir)}[varname]
1304 up.pkgdir = tmp_path 1304 g.pkgdir = tmp_path
1305 (tmp_path / 'Makefile').write_text('# url2pkg-marker\n') 1305 (tmp_path / 'Makefile').write_text('# url2pkg-marker\n')
1306 adjuster = Adjuster(up, 'https://example.org/distfile-1.0.zip', Lines()) 1306 adjuster = Adjuster(g, 'https://example.org/distfile-1.0.zip', Lines())
1307 1307
1308 adjuster.adjust() 1308 adjuster.adjust()
1309 1309
1310 assert adjuster.wrksrc_dirs == [ 1310 assert adjuster.wrksrc_dirs == [
1311 'dir', 1311 'dir',
1312 'dir/.hidden-dir', 1312 'dir/.hidden-dir',
1313 'dir/subdir', 1313 'dir/subdir',
1314 'dir2', 1314 'dir2',
1315 ] 1315 ]
1316 assert adjuster.wrksrc_files == [ 1316 assert adjuster.wrksrc_files == [
1317 'dir/subdir/.hidden', 1317 'dir/subdir/.hidden',
1318 'dir/subdir/file', 1318 'dir/subdir/file',
1319 'file', 1319 'file',
1320 ] 1320 ]
1321 1321
1322 1322
1323def test_Adjuster_adjust_lines_python_module(tmp_path: Path): 1323def test_Adjuster_adjust_lines_python_module(tmp_path: Path):
1324 url = 'https://github.com/espressif/esptool/archive/v2.7.tar.gz' 1324 url = 'https://github.com/espressif/esptool/archive/v2.7.tar.gz'
1325 up.pkgdir = tmp_path 1325 g.pkgdir = tmp_path
1326 up.make = 'true' # the shell command 1326 g.make = 'true' # the shell command
1327 up.verbose = True 1327 g.verbose = True
1328 initial_lines = Generator(url).generate_Makefile() 1328 initial_lines = Generator(url).generate_Makefile()
1329 initial_lines.append('CATEGORIES', 'python') 1329 initial_lines.append('CATEGORIES', 'python')
1330 adjuster = Adjuster(up, url, initial_lines) 1330 adjuster = Adjuster(g, url, initial_lines)
1331 adjuster.makefile_lines = Lines(*initial_lines.lines) 1331 adjuster.makefile_lines = Lines(*initial_lines.lines)
1332 (up.pkgdir / 'Makefile').touch() 1332 (g.pkgdir / 'Makefile').touch()
1333 1333
1334 assert detab(adjuster.makefile_lines) == [ 1334 assert detab(adjuster.makefile_lines) == [
1335 mkcvsid, 1335 mkcvsid,
1336 '', 1336 '',
1337 'GITHUB_PROJECT= esptool', 1337 'GITHUB_PROJECT= esptool',
1338 'GITHUB_TAG= v2.7', 1338 'GITHUB_TAG= v2.7',
1339 'DISTNAME= v2.7', 1339 'DISTNAME= v2.7',
1340 'PKGNAME= ${GITHUB_PROJECT}-${DISTNAME:S,^v,,}', 1340 'PKGNAME= ${GITHUB_PROJECT}-${DISTNAME:S,^v,,}',
1341 'CATEGORIES= pkgtools python', 1341 'CATEGORIES= pkgtools python',
1342 'MASTER_SITES= ${MASTER_SITE_GITHUB:=espressif/}', 1342 'MASTER_SITES= ${MASTER_SITE_GITHUB:=espressif/}',
1343 'DIST_SUBDIR= ${GITHUB_PROJECT}', 1343 'DIST_SUBDIR= ${GITHUB_PROJECT}',
1344 '', 1344 '',
1345 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 1345 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
1346 'HOMEPAGE= https://github.com/espressif/esptool/', 1346 'HOMEPAGE= https://github.com/espressif/esptool/',
1347 'COMMENT= TODO: Short description of the package', 1347 'COMMENT= TODO: Short description of the package',
1348 '#LICENSE= # TODO: (see mk/license.mk)', 1348 '#LICENSE= # TODO: (see mk/license.mk)',
1349 '', 1349 '',
1350 '# url2pkg-marker (please do not remove this line.)', 1350 '# url2pkg-marker (please do not remove this line.)',
1351 '.include "../../mk/bsd.pkg.mk"', 1351 '.include "../../mk/bsd.pkg.mk"',
1352 ] 1352 ]
1353 1353
1354 lines = adjuster.generate_lines() 1354 lines = adjuster.generate_lines()
1355 1355
1356 assert detab(lines) == [ 1356 assert detab(lines) == [
1357 mkcvsid, 1357 mkcvsid,
1358 '', 1358 '',
1359 'DISTNAME= esptool-2.7', 1359 'DISTNAME= esptool-2.7',
1360 'PKGNAME= ${PYPKGPREFIX}-${DISTNAME}', 1360 'PKGNAME= ${PYPKGPREFIX}-${DISTNAME}',
1361 'CATEGORIES= pkgtools python', 1361 'CATEGORIES= pkgtools python',
1362 'MASTER_SITES= ${MASTER_SITE_PYPI:=e/esptool/}', 1362 'MASTER_SITES= ${MASTER_SITE_PYPI:=e/esptool/}',
1363 '', 1363 '',
1364 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org', 1364 'MAINTAINER= INSERT_YOUR_MAIL_ADDRESS_HERE # or use pkgsrc-users@NetBSD.org',
1365 'HOMEPAGE= https://github.com/espressif/esptool/', 1365 'HOMEPAGE= https://github.com/espressif/esptool/',
1366 'COMMENT= TODO: Short description of the package', 1366 'COMMENT= TODO: Short description of the package',
1367 '#LICENSE= # TODO: (see mk/license.mk)', 1367 '#LICENSE= # TODO: (see mk/license.mk)',
1368 '', 1368 '',
1369 '# url2pkg-marker (please do not remove this line.)', 1369 '# url2pkg-marker (please do not remove this line.)',
1370 '.include "../../mk/bsd.pkg.mk"', 1370 '.include "../../mk/bsd.pkg.mk"',
1371 ] 1371 ]
1372 1372
1373 try_mk = tmp_path / 'try-pypi.mk' 1373 try_mk = tmp_path / 'try-pypi.mk'
1374 assert up.err.written() == [ 1374 assert g.err.written() == [
1375 f"url2pkg: running ['true', '-f', '{try_mk}', 'distinfo'] to try PyPI", 1375 f"url2pkg: running ['true', '-f', '{try_mk}', 'distinfo'] to try PyPI",
1376 ] 1376 ]
1377 1377
1378 1378
1379def test_Adjuster_adjust_lines_python_module__edited(): 1379def test_Adjuster_adjust_lines_python_module__edited():
1380 # When the package developer has edited the Makefile, it's unclear 1380 # When the package developer has edited the Makefile, it's unclear
1381 # what has changed. To not damage anything, let the package 1381 # what has changed. To not damage anything, let the package
1382 # developer migrate manually. 1382 # developer migrate manually.
1383 1383
1384 url = 'https://github.com/espressif/esptool/archive/v2.7.tar.gz' 1384 url = 'https://github.com/espressif/esptool/archive/v2.7.tar.gz'
1385 initial_lines = Generator(url).generate_Makefile() 1385 initial_lines = Generator(url).generate_Makefile()
1386 initial_lines.append('CATEGORIES', 'python') 1386 initial_lines.append('CATEGORIES', 'python')
1387 adjuster = Adjuster(up, url, initial_lines) 1387 adjuster = Adjuster(g, url, initial_lines)
1388 adjuster.makefile_lines = Lines(*initial_lines.lines) 1388 adjuster.makefile_lines = Lines(*initial_lines.lines)
1389 initial_lines.add('') # to make the lines different 1389 initial_lines.add('') # to make the lines different
1390 1390
1391 lines = adjuster.generate_lines() 1391 lines = adjuster.generate_lines()
1392 1392
1393 assert lines.get('GITHUB_PROJECT') == 'esptool' 1393 assert lines.get('GITHUB_PROJECT') == 'esptool'
1394 1394
1395 adjuster.adjust_lines_python_module(lines) 1395 adjuster.adjust_lines_python_module(lines)
1396 1396
1397 assert lines.get('GITHUB_PROJECT') == 'esptool' 1397 assert lines.get('GITHUB_PROJECT') == 'esptool'
1398 assert lines.index('TODO: Migrate MASTER_SITES to MASTER_SITE_PYPI') == 14 1398 assert lines.index('TODO: Migrate MASTER_SITES to MASTER_SITE_PYPI') == 14
1399 1399
1400 1400
1401def test_main__wrong_dir(tmp_path): 1401def test_main__wrong_dir(tmp_path):
1402 os.chdir(tmp_path) 1402 os.chdir(tmp_path)
1403 error = r'url2pkg: must be run from a package directory' 1403 error = r'url2pkg: must be run from a package directory'
1404 1404
1405 with pytest.raises(SystemExit, match=error): 1405 with pytest.raises(SystemExit, match=error):
1406 main(['url2pkg'], up) 1406 main(['url2pkg'], g)
1407 1407
1408 1408
1409def test_main__unknown_option(): 1409def test_main__unknown_option():
1410 with pytest.raises(SystemExit, match=r'usage:'): 1410 with pytest.raises(SystemExit, match=r'usage:'):
1411 main(['url2pkg', '--unknown'], up) 1411 main(['url2pkg', '--unknown'], g)
1412 1412
1413 1413
1414def test_main__verbose(): 1414def test_main__verbose():
1415 with pytest.raises(SystemExit, match=r'url2pkg: invalid URL: broken URL'): 1415 with pytest.raises(SystemExit, match=r'url2pkg: invalid URL: broken URL'):
1416 main(['url2pkg', '--verbose', 'broken URL'], up) 1416 main(['url2pkg', '--verbose', 'broken URL'], g)
1417 1417
1418 1418
1419def test_main__valid_URL(): 1419def test_main__valid_URL():
1420 import shutil 1420 import shutil
1421 1421
1422 up.editor = 'true' 1422 g.editor = 'true'
1423 up.make = os.getenv('MAKE') or sys.exit('MAKE must be set') 1423 g.make = os.getenv('MAKE') or sys.exit('MAKE must be set')
1424 up.pkgdir = up.pkgsrcdir / 'pkgtools' / 'url2pkg-test-main' 1424 g.pkgdir = g.pkgsrcdir / 'pkgtools' / 'url2pkg-test-main'
1425 up.pkgdir.is_dir() and shutil.rmtree(up.pkgdir) 1425 g.pkgdir.is_dir() and shutil.rmtree(g.pkgdir)
1426 try: 1426 try:
1427 up.pkgdir.mkdir() 1427 g.pkgdir.mkdir()
1428 except OSError: 1428 except OSError:
1429 return # skip if the directory is not writable 1429 return # skip if the directory is not writable
1430 os.chdir(up.pkgdir) 1430 os.chdir(g.pkgdir)
1431 1431
1432 main(['url2pkg', '-v', 'https://github.com/rillig/checkperms/archive/v1.12.tar.gz'], up) 1432 main(['url2pkg', '-v', 'https://github.com/rillig/checkperms/archive/v1.12.tar.gz'], g)
1433 1433
1434 assert up.out.written() == [ 1434 assert g.out.written() == [
1435 '', 1435 '',
1436 'Remember to run pkglint when you\'re done.', 1436 'Remember to run pkglint when you\'re done.',
1437 'See ../../doc/pkgsrc.txt to get some help.', 1437 'See ../../doc/pkgsrc.txt to get some help.',
1438 '', 1438 '',
1439 ] 1439 ]
1440 assert up.err.written() == [ 1440 assert g.err.written() == [
1441 f'url2pkg: running bmake (\'clean\', \'distinfo\', \'extract\') in \'{up.pkgdir}\'', 1441 f'url2pkg: running bmake (\'clean\', \'distinfo\', \'extract\') in \'{g.pkgdir}\'',
1442 'url2pkg: Adjusting the Makefile', 1442 'url2pkg: Adjusting the Makefile',
1443 ] 1443 ]
1444 1444
1445 up.verbose = False 1445 g.verbose = False
1446 up.bmake('clean') # remove the work directory 1446 g.bmake('clean') # remove the work directory
1447 1447
1448 expected_files = ['DESCR', 'Makefile', 'PLIST', 'distinfo'] 1448 expected_files = ['DESCR', 'Makefile', 'PLIST', 'distinfo']
1449 assert sorted([f.name for f in up.pkgdir.glob("*")]) == expected_files 1449 assert sorted([f.name for f in g.pkgdir.glob("*")]) == expected_files
1450 1450
1451 shutil.rmtree(up.pkgdir) 1451 shutil.rmtree(g.pkgdir)