forked from lbt/git-pkg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gp_mkpkg
executable file
·339 lines (276 loc) · 11.1 KB
/
gp_mkpkg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#!/usr/bin/python
# make_src
# This is part of the Mer git-packaging suite
# It takes a _src file and recreates any tarballs referenced in it.
#
# 3 types:
# native: extract the tarball using git archive <tag>
# upstream git: additionally use git format-patch to make patches
# pristine tar: use ptar and then git format-patch
# upstream with released tarball: as pristine tar but skip the commit
# labelled "pristine-tar" in the mer-<version> branch
import re
import os
import subprocess
import argparse
import sys
import collections
import yaml
import tempfile
import BlockDumper
# Should come from ~/.vendor and/or commandline option
vendor="mer"
pkg_branch="pkg-%s" % vendor
# Allow overriding of "git' command via the "GIT" environment variable
GIT_CMD = os.environ.get('GIT', 'git')
# Data passing class
class Patches():
def __init__(self):
self.spec_Patches=[]
self.spec_patches=[]
self.yaml_Patches=[]
class UnknownFormat(Exception):
pass
def git(*args, **kwargs):
"""Run git with arguments, return stdout as string"""
return subprocess.check_output([GIT_CMD] + list(args), **kwargs)
def fail(msg, *args):
"""Report an error message and exit with failure"""
print >>sys.stderr, 'ERROR:', msg % args
sys.exit(1)
def checkout_packaging_branch(pkg, force):
"""
Ensure we're on the latest packaging branch commit.
If force is False and we're on the packaging branch then no-op
(this essentially lets us run with uncommited changes to _src,
spec etc so the patch-sets can be added.)
"""
if force:
git('checkout', '-f', pkg)
try:
branch = git('symbolic-ref', 'HEAD').replace('refs/heads/', '').rstrip()
except subprocess.CalledProcessError:
return # We're not on a symbolic ref; assume tag
if not force and branch != pkg:
fail('Must be on the %s branch to use --no-checkout', pkg)
def guess_format(archive):
if (re.search(r'\.t(ar\.)?gz$', archive)):
return ("tar", "gzip")
elif (re.search(r'\.tar\.bz2$', archive)):
return ("tar", "bzip2")
elif (re.search(r'\.tar\.xz$', archive)):
return ("tar", "xz")
else:
raise UnknownFormat()
def count_commits(a, b):
return len(git('rev-list', '..'.join((a, b))).splitlines())
def prepare_tarball_and_patches(args):
p = Patches()
src_f = open("_src")
for src in src_f:
src = src.rstrip()
src = src.split(":")
vcs = src[0]
tag1, tag2 = None, None
if vcs.startswith("#"):
continue
if (vcs == "git" ):
# git:<tarball>:<tag1>:<tag2>
# make a tarball at tag1 and patches to tag2 (if present)
if len(src) < 3:
raise Exception("Not enough arguments for 'git' line in _src")
tarball, tag1 = src[1:3]
if len(src) > 3:
tag2 = src[3]
if args.make_tarball:
# Determine archive/compression
try:
format, compression = guess_format(tarball)
# Make a suitable tarball
subprocess.call(
GIT_CMD + " archive --format=%(format)s --prefix=src/ %(tag1)s "
"| %(compression)s > %(tarball)s" % locals(),
shell=True)
except UnknownFormat :
fail("Can't determine format of tarball %s", tarball)
elif (vcs == "pristine-tar"):
# pristine-tar:<tarball>:<tag1>:<tag2>
# extract upstream tarball and make patches from tag1 to tag2
# (if present) skipping the special 'pristine-tar' diff patch
if len(src) < 4:
raise Exception("Not enough arguments for 'pristine-tar' line in _src")
tarball, tag1 = src[1:3]
if len(src) > 3:
tag2 = src[3]
# For pristine tar style repos the first commit is the
# pristine tar delta stored in a commit labeled pristine-tar-delta
# Skip the first commit using commit~N terminology
tag1 = "%s~%d" %(tag2, count_commits(tag1, tag2) - 1)
if args.make_tarball:
subprocess.call(
[ "/usr/bin/pristine-tar", "checkout", tarball],
shell=False)
# Prevent pristine-tar from altering the %setup line
args.setup_src = False
else:
raise Exception("_src storage %s not recognised" % vcs)
# If a tag range was specified, create patches
# -M is --find-renames but that's not available on suse 11.4
if tag2:
patches = git('format-patch', '-M', '--binary', '--no-renames', '--ignore-submodules',
'-N', '--no-numbered', '..'.join((tag1, tag2))).splitlines()
count = 1
for patch in patches:
p.spec_Patches.append("Patch%(count)d:\t%(patch)s\n" % locals())
count+=1
if not args.make_tarball:
os.remove(patch)
count = 1
for patch in patches:
p.spec_patches.append("%%patch%(count)d -p1\n" % locals())
count+=1
# p.yaml_Patches.append("Patches:\n")
for patch in patches:
#p.yaml_Patches.append("- %(patch)s\n" % locals())
p.yaml_Patches.append(patch)
else:
print "No patches requested"
return p
def apply_patches_to_spec(args, p, specfilename):
spec_f = open(specfilename, "r+")
spec_new = []
Source_match = re.compile(r"^Source")
Patch_match = re.compile(r"^Patch")
prep_match = re.compile(r"^%prep")
patch_match = re.compile(r"^%patch")
setup_comment = "# Adjusting %%setup since git-pkg unpacks to src/\n"
setup_comment_present = False
if setup_comment in open(specfilename).read():
setup_comment_present = True
# Skip to the SourceXX: line
line = "python has no do: while syntax"
while line:
line = spec_f.readline()
if not Patch_match.search(line):
spec_new.extend(line)
if not Source_match.search(line):
continue
break
# Now print all Source lines but not Patch lines
while line:
line = spec_f.readline()
if Patch_match.search(line):
continue
if Source_match.search(line):
spec_new.extend(line)
continue
next_line = line
break
spec_new.extend(p.spec_Patches)
spec_new.extend(next_line)
# Skip to %prep
while line:
line = spec_f.readline()
if not Patch_match.search(line):
spec_new.extend(line)
if prep_match.search(line):
break
# Any remaining spec content, skipping %patch lines
# and updating when %setup is found
done_setup = False
while line:
line = spec_f.readline()
if patch_match.search(line):
continue
if re.search(r'^%setup', line):
if done_setup:
print "WARNING: multiple %setups found - please check patches are in the right place in spec"
else:
done_setup = True
if args.setup_src:
# use sys.stdout instead of print to get rid of
# the automatic linefeed, which is already
# included in setup_comment
sys.stdout.write(setup_comment)
if not setup_comment_present:
spec_new.extend(setup_comment)
spec_new.extend("# %s" % re.sub(r'%', '%%', line))
setup_comment_present = True
print line.strip()
line = re.sub(r'^%setup(.*(?=-n))(-n\s+\S*)(.*$)', r'%setup \1 -n src \3', line)
print "converted to"
print line.strip()
# Now output modified or orig %setup and any patches
spec_new.extend(line)
spec_new.extend(p.spec_patches)
continue
spec_new.extend(line)
spec_f.seek(0)
spec_f.writelines(spec_new)
spec_f.close()
def apply_patches_to_yaml(args, p, yamlfilename):
f = open(yamlfilename, "r+")
specify = yaml.load(f)
specify['Patches'] = p.yaml_Patches
if args.setup_src:
specify['SetupOptions'] = '-q -n src'
f.seek(0)
f.truncate()
yaml.dump(specify, f, Dumper=BlockDumper.BlockDumper, default_flow_style=False)
f.close()
print "Running specify"
subprocess.check_output(['specify', "-N", "-s", "-n"])
def apply_patches(args, p):
""
for f in os.listdir("."):
if f.endswith(".yaml"):
apply_patches_to_yaml(args, p, f)
# Could run specify here - fn name would change
return
if f.endswith(".spec"):
spec = f
# No yaml found, patch the spec
apply_patches_to_spec(args, p, spec)
parser = argparse.ArgumentParser(description='gitpkg build preparation')
parser.add_argument('-b', '--build',
dest='build', action='store_true',
help="Just prepare tarballs/patches for building - don't modify spec/yaml from git")
parser.add_argument('-n', '--no-checkout',
dest='force_checkout', action='store_false',
help="Don't force checkout the latest pkg branch (useful if working on packaging)")
parser.add_argument('--no-src',
dest='setup_src', action='store_false',
help="Don't modify %setup to use -n src/ (useful for pristine tar")
parser.add_argument('--no-tarball',
dest='make_tarball', action='store_false',
help="Don't create the tarball/patches")
parser.add_argument('--git-dir',
help="Specify the directory holding the gitpkg repo")
parser.add_argument('tag', metavar='tag', type=str, nargs='?',
default=pkg_branch,
help='A tag to force checkout')
args = parser.parse_args()
if args.git_dir:
try:
with open(os.devnull, 'w') as null:
git("--git-dir", args.git_dir, "rev-parse", "--git-dir", stderr=null)
except subprocess.CalledProcessError:
try:
# not a git dir - try appending .git
with open(os.devnull, 'w') as null:
git("--git-dir", os.path.join(args.git_dir,".git"), "rev-parse", "--git-dir", stderr=null)
args.git_dir = os.path.join(args.git_dir,".git")
except subprocess.CalledProcessError:
fail("The --git-dir option must point to a git repo.\n"
"%s nor %s/.git are a git directory" % (args.git_dir, args.git_dir))
os.environ['GIT_DIR']=args.git_dir
os.environ['GIT_WORK_TREE']=os.getcwd()
os.environ['GIT_INDEX_FILE']=tempfile.NamedTemporaryFile(prefix="gp_index_", delete=False).name
git("read-tree", "--empty")
# Checkout the tag (default is the hardcoded pkg_branch)
checkout_packaging_branch(args.tag, args.force_checkout)
patches=prepare_tarball_and_patches(args)
if not args.build:
apply_patches(args, patches)
if args.git_dir:
os.remove(os.environ['GIT_INDEX_FILE'])