3 # Generate the output tree into a specified directory.
6 import argparse
, sys
, os
, errno
, shutil
, re
, subprocess
10 source_dir
= os
.path
.abspath(os
.path
.dirname(__file__
))
11 sys
.path
.append(source_dir
)
12 # and import libraries we have
13 from lib
import kconfig
, patch
, make
14 from lib
import bpgit
as git
15 from lib
import bpgpg
as gpg
16 from lib
import bpkup
as kup
18 def read_copy_list(copyfile
):
20 Read a copy-list file and return a list of (source, target)
21 tuples. The source and target are usually the same, but in
22 the copy-list file there may be a rename included.
26 # remove leading/trailing whitespace
29 if not item
or item
[0] == '#':
32 raise Exception("Input path '%s' is absolute path, this isn't allowed" % (item
, ))
34 srcitem
, dstitem
= item
.split(' -> ')
35 if (srcitem
[-1] == '/') != (dstitem
[-1] == '/'):
36 raise Exception("Cannot copy file/dir to dir/file")
38 srcitem
= dstitem
= item
39 ret
.append((srcitem
, dstitem
))
43 def read_dependencies(depfilename
):
45 Read a (the) dependency file and return the list of
46 dependencies as a dictionary, mapping a Kconfig symbol
47 to a list of kernel version dependencies.
49 If a backported feature that an upstream backported driver
50 depends on had kconfig limitations (ie, debugging feature not
51 available) a built constaint restriction can be expressed
52 by using a kconfig expression. The kconfig expressions can
53 be specified by using the "kconfig: " prefix.
55 While reading ignore blank or commented lines.
58 depfile
= open(depfilename
, 'r')
62 if not item
or item
[0] == '#':
64 if "kconfig:" in item
:
65 sym
, kconfig_exp
= item
.split(" ", 1)
67 ret
[sym
] = [kconfig_exp
, ]
69 ret
[sym
].append(kconfig_exp
)
71 sym
, dep
= item
.split()
79 def check_output_dir(d
, clean
):
81 Check that the output directory doesn't exist or is empty,
82 unless clean is True in which case it's nuked. This helps
83 sanity check the output when generating a tree, so usually
84 running with --clean isn't suggested.
87 shutil
.rmtree(d
, ignore_errors
=True)
91 if e
.errno
!= errno
.ENOENT
:
95 def copytree(src
, dst
, symlinks
=False, ignore
=None):
97 Copy a directory tree. This differs from shutil.copytree()
98 in that it allows destination directories to already exist.
100 names
= os
.listdir(src
)
101 if ignore
is not None:
102 ignored_names
= ignore(src
, names
)
104 ignored_names
= set()
106 if not os
.path
.isdir(dst
):
110 if name
in ignored_names
:
112 srcname
= os
.path
.join(src
, name
)
113 dstname
= os
.path
.join(dst
, name
)
115 if symlinks
and os
.path
.islink(srcname
):
116 linkto
= os
.readlink(srcname
)
117 os
.symlink(linkto
, dstname
)
118 elif os
.path
.isdir(srcname
):
119 copytree(srcname
, dstname
, symlinks
, ignore
)
121 shutil
.copy2(srcname
, dstname
)
122 except (IOError, os
.error
) as why
:
123 errors
.append((srcname
, dstname
, str(why
)))
124 # catch the Error from the recursive copytree so that we can
125 # continue with other files
126 except shutil
.Error
as err
:
127 errors
.extend(err
.args
[0])
129 shutil
.copystat(src
, dst
)
131 # can't copy file access times on Windows
133 except OSError as why
:
134 errors
.extend((src
, dst
, str(why
)))
136 raise shutil
.Error(errors
)
139 def copy_files(srcpath
, copy_list
, outdir
):
141 Copy the copy_list files and directories from the srcpath
142 to the outdir. The copy_list contains source and target
145 For now, it also ignores any *~ editor backup files, though
146 this should probably be generalized (maybe using .gitignore?)
147 Similarly the code that only copies some files (*.c, *.h,
148 *.awk, Kconfig, Makefile) to avoid any build remnants in the
149 kernel if they should exist.
151 for srcitem
, tgtitem
in copy_list
:
153 copytree(srcpath
, outdir
, ignore
=shutil
.ignore_patterns('*~'))
154 elif tgtitem
[-1] == '/':
155 def copy_ignore(dir, entries
):
158 if i
[-2:] == '.o' or i
[-1] == '~':
161 copytree(os
.path
.join(srcpath
, srcitem
),
162 os
.path
.join(outdir
, tgtitem
),
166 os
.makedirs(os
.path
.join(outdir
, os
.path
.dirname(tgtitem
)))
168 # ignore dirs we might have created just now
169 if e
.errno
!= errno
.EEXIST
:
171 shutil
.copy(os
.path
.join(srcpath
, srcitem
),
172 os
.path
.join(outdir
, tgtitem
))
175 def copy_git_files(srcpath
, copy_list
, rev
, outdir
):
177 "Copy" files from a git repository. This really means listing them with
178 ls-tree and then using git show to obtain all the blobs.
180 for srcitem
, tgtitem
in copy_list
:
181 for m
, t
, h
, f
in git
.ls_tree(rev
=rev
, files
=(srcitem
,), tree
=srcpath
):
183 f
= os
.path
.join(outdir
, f
.replace(srcitem
, tgtitem
))
184 d
= os
.path
.dirname(f
)
185 if not os
.path
.exists(d
):
188 git
.get_blob(h
, outf
, tree
=srcpath
)
190 os
.chmod(f
, int(m
, 8))
192 def automatic_backport_mangle_c_file(name
):
193 return name
.replace('/', '-')
196 def add_automatic_backports(args
):
198 export
= re
.compile(r
'^EXPORT_SYMBOL(_GPL)?\((?P<sym>[^\)]*)\)')
199 bpi
= kconfig
.get_backport_info(os
.path
.join(args
.outdir
, 'compat', 'Kconfig'))
200 configtree
= kconfig
.ConfigTree(os
.path
.join(args
.outdir
, 'Kconfig'))
201 all_selects
= configtree
.all_selects()
202 for sym
, vals
in bpi
.items():
203 if sym
.startswith('BACKPORT_BUILD_'):
204 if not sym
[15:] in all_selects
:
205 disable_list
.append(sym
)
207 symtype
, module_name
, c_files
, h_files
= vals
212 files
.append((f
, os
.path
.join('compat', automatic_backport_mangle_c_file(f
))))
214 files
.append((os
.path
.join('include', f
),
215 os
.path
.join('include', os
.path
.dirname(f
), 'backport-' + os
.path
.basename(f
))))
216 if args
.git_revision
:
217 copy_git_files(args
.kerneldir
, files
, args
.git_revision
, args
.outdir
)
219 copy_files(args
.kerneldir
, files
, args
.outdir
)
221 # now add the Makefile line
222 mf
= open(os
.path
.join(args
.outdir
, 'compat', 'Makefile'), 'a+')
223 o_files
= [automatic_backport_mangle_c_file(f
)[:-1] + 'o' for f
in c_files
]
224 if symtype
== 'tristate':
226 raise Exception('backporting a module requires a #module-name')
228 mf
.write('%s-objs += %s\n' % (module_name
, of
))
229 mf
.write('obj-$(CPTCFG_%s) += %s.o\n' % (sym
, module_name
))
230 elif symtype
== 'bool':
231 mf
.write('compat-$(CPTCFG_%s) += %s\n' % (sym
, ' '.join(o_files
)))
233 # finally create the include file
236 for l
in open(os
.path
.join(args
.outdir
, 'compat',
237 automatic_backport_mangle_c_file(f
)), 'r'):
240 syms
.append(m
.group('sym'))
242 outf
= open(os
.path
.join(args
.outdir
, 'include', f
), 'w')
243 outf
.write('/* Automatically created during backport process */\n')
244 outf
.write('#ifndef CPTCFG_%s\n' % sym
)
245 outf
.write('#include_next <%s>\n' % f
)
246 outf
.write('#else\n');
248 outf
.write('#undef %s\n' % s
)
249 outf
.write('#define %s LINUX_BACKPORT(%s)\n' % (s
, s
))
250 outf
.write('#include <%s>\n' % (os
.path
.dirname(f
) + '/backport-' + os
.path
.basename(f
), ))
251 outf
.write('#endif /* CPTCFG_%s */\n' % sym
)
254 def git_debug_init(args
):
256 Initialize a git repository in the output directory and commit the current
257 code in it. This is only used for debugging the transformations this code
258 will do to the output later.
260 if not args
.gitdebug
:
262 git
.init(tree
=args
.outdir
)
263 git
.commit_all("Copied backport", tree
=args
.outdir
)
266 def git_debug_snapshot(args
, name
):
268 Take a git snapshot for the debugging.
270 if not args
.gitdebug
:
272 git
.commit_all(name
, tree
=args
.outdir
)
274 def get_rel_spec_stable(rel
):
276 Returns release specs for a linux-stable backports based release.
279 m
= re
.match(r
"(?P<VERSION>\d+)\.+" \
280 "(?P<PATCHLEVEL>\d+)[.]*" \
281 "(?P<SUBLEVEL>\d*)" \
282 "[-rc]+(?P<RC_VERSION>\d+)\-+" \
283 "(?P<RELMOD_UPDATE>\d+)[-]*" \
284 "(?P<RELMOD_TYPE>[usnpc]*)", \
287 m
= re
.match(r
"(?P<VERSION>\d+)\.+" \
288 "(?P<PATCHLEVEL>\d+)[.]*" \
289 "(?P<SUBLEVEL>\d*)\-+" \
290 "(?P<RELMOD_UPDATE>\d+)[-]*" \
291 "(?P<RELMOD_TYPE>[usnpc]*)", \
297 def get_rel_spec_next(rel
):
299 Returns release specs for a linux-next backports based release.
301 m
= re
.match(r
"(?P<DATE_VERSION>\d+)[-]*" \
302 "(?P<RELMOD_UPDATE>\d*)[-]*" \
303 "(?P<RELMOD_TYPE>[usnpc]*)", \
309 def get_rel_prep(rel
):
311 Returns a dict with prep work details we need prior to
312 uploading a backports release to kernel.org
314 rel_specs
= get_rel_spec_stable(rel
)
319 rel_specs
= get_rel_spec_next(rel
)
321 sys
.stdout
.write("rel: %s\n" % rel
)
323 if (rel_specs
['RELMOD_UPDATE'] == '0' or
324 rel_specs
['RELMOD_UPDATE'] == '1'):
327 date
= rel_specs
['DATE_VERSION']
332 if (len(month
) != 2):
340 rel_tag
= "backports-" + rel
.replace(rel_specs
['RELMOD_TYPE'], "")
343 if (not rel_specs
['RELMOD_UPDATE']):
345 if (rel_specs
['RELMOD_UPDATE'] == '0'):
347 ignore
+= rel_specs
['RELMOD_UPDATE']
348 if (rel_specs
['RELMOD_TYPE'] != ''):
349 ignore
+= rel_specs
['RELMOD_TYPE']
350 base_rel
= rel
.replace(ignore
, "")
351 paths
.append(base_rel
)
352 rel_tag
= "v" + rel
.replace(rel_specs
['RELMOD_TYPE'], "")
354 rel_prep
= dict(stable
= is_stable
,
355 expected_tag
= rel_tag
,
356 paths_to_create
= paths
)
359 def create_tar_and_bz2(tar_name
, dir_to_tar
):
361 We need both a tar file and bzip2 for kernel.org, the tar file
362 gets signed, then we upload the compressed version, kup-server
363 in the backend decompresses and verifies the tarball against
366 basename
= os
.path
.basename(dir_to_tar
)
367 tar
= tarfile
.open(tar_name
, "w")
368 tar
.add(dir_to_tar
, basename
)
371 tar_file
= open(tar_name
, "r")
373 bz2_file
= bz2
.BZ2File(tar_name
+ ".bz2", 'wb', compresslevel
=9)
374 bz2_file
.write(tar_file
.read())
377 def upload_release(args
, rel_prep
, logwrite
=lambda x
:None):
379 Given a path of a relase make tarball out of it, PGP sign it, and
380 then upload it to kernel.org using kup.
382 The linux-next based release do not require a RELMOD_UPDATE
383 given that typically only one release is made per day. Using
384 RELMOD_UPDATE for these releases is allowed though and if
385 present it must be > 1.
387 The linux-stable based releases require a RELMOD_UPDATE.
389 RELMOD_UPDATE must be numeric and > 0 just as the RC releases
392 The tree must also be tagged with the respective release, without
393 the RELMOD_TYPE. For linux-next based releases this consists of
394 backports- followed by DATE_VERSION and if RELMOD_TYPE is present.
395 For linux-stable releases this consists of v followed by the
396 full release version except the RELMOD_TYPE.
398 Uploads will not be allowed if these rules are not followed.
400 korg_path
= "/pub/linux/kernel/projects/backports"
402 if (rel_prep
['stable']):
403 korg_path
+= "stable"
405 parent
= os
.path
.dirname(args
.outdir
)
406 release
= os
.path
.basename(args
.outdir
)
407 tar_name
= parent
+ '/' + release
+ ".tar"
408 bzip2_name
= tar_name
+ ".bz2"
410 create_tar_and_bz2(tar_name
, args
.outdir
)
412 logwrite(gpg
.sign(tar_name
, extra_args
=['--armor', '--detach-sign']))
414 logwrite("------------------------------------------------------")
416 if (not args
.kup_test
):
417 logwrite("About to upload, current target path contents:")
419 logwrite("kup-test: current target path contents:")
421 logwrite(kup
.ls(path
=korg_path
))
423 for path
in rel_prep
['paths_to_create']:
424 korg_path
+= '/' + path
425 if (not args
.kup_test
):
426 logwrite(kup
.mkdir(korg_path
))
427 if (not args
.kup_test
):
428 logwrite(kup
.put(bzip2_name
, tar_name
+ '.asc', korg_path
))
429 logwrite("\nFinished upload!\n")
430 logwrite("Target path contents:")
431 logwrite(kup
.ls(path
=korg_path
))
433 kup_cmd
= "kup put /\n\t\t%s /\n\t\t%s /\n\t\t%s" % (bzip2_name
, tar_name
+ '.asc', korg_path
)
434 logwrite("kup-test: skipping cmd: %s" % kup_cmd
)
437 # set up and parse arguments
438 parser
= argparse
.ArgumentParser(description
='generate backport tree')
439 parser
.add_argument('kerneldir', metavar
='<kernel tree>', type=str,
440 help='Kernel tree to copy drivers from')
441 parser
.add_argument('outdir', metavar
='<output directory>', type=str,
442 help='Directory to write the generated tree to')
443 parser
.add_argument('--copy-list', metavar
='<listfile>', type=argparse
.FileType('r'),
445 help='File containing list of files/directories to copy, default "copy-list"')
446 parser
.add_argument('--git-revision', metavar
='<revision>', type=str,
447 help='git commit revision (see gitrevisions(7)) to take objects from.' +
448 'If this is specified, the kernel tree is used as git object storage ' +
449 'and we use git ls-tree to get the files.')
450 parser
.add_argument('--clean', const
=True, default
=False, action
="store_const",
451 help='Clean output directory instead of erroring if it isn\'t empty')
452 parser
.add_argument('--refresh', const
=True, default
=False, action
="store_const",
453 help='Refresh patches as they are applied, the source dir will be modified!')
454 parser
.add_argument('--base-name', metavar
='<name>', type=str, default
='Linux',
455 help='name of base tree, default just "Linux"')
456 parser
.add_argument('--gitdebug', const
=True, default
=False, action
="store_const",
457 help='Use git, in the output tree, to debug the various transformation steps ' +
458 'that the tree generation makes (apply patches, ...)')
459 parser
.add_argument('--verbose', const
=True, default
=False, action
="store_const",
460 help='Print more verbose information')
461 parser
.add_argument('--extra-driver', nargs
=2, metavar
=('<source dir>', '<copy-list>'), type=str,
462 action
='append', default
=[], help='Extra driver directory/copy-list.')
463 parser
.add_argument('--kup', const
=True, default
=False, action
="store_const",
464 help='For maintainers: upload a release to kernel.org')
465 parser
.add_argument('--kup-test', const
=True, default
=False, action
="store_const",
466 help='For maintainers: do all the work as if you were about to ' +
467 'upload to kernel.org but do not do the final `kup put` ' +
468 'and also do not run any `kup mkdir` commands. This will ' +
469 'however run `kup ls` on the target paths so ' +
470 'at the very least we test your kup configuration. ' +
471 'If this is your first time uploading use this first!')
472 args
= parser
.parse_args()
475 sys
.stdout
.write(msg
)
476 sys
.stdout
.write('\n')
479 return process(args
.kerneldir
, args
.outdir
, args
.copy_list
,
480 git_revision
=args
.git_revision
, clean
=args
.clean
,
481 refresh
=args
.refresh
, base_name
=args
.base_name
,
482 gitdebug
=args
.gitdebug
, verbose
=args
.verbose
,
483 extra_driver
=args
.extra_driver
,
485 kup_test
=args
.kup_test
,
488 def process(kerneldir
, outdir
, copy_list_file
, git_revision
=None,
489 clean
=False, refresh
=False, base_name
="Linux", gitdebug
=False,
490 verbose
=False, extra_driver
=[], kup
=False,
492 logwrite
=lambda x
:None,
493 git_tracked_version
=False):
495 def __init__(self
, kerneldir
, outdir
, copy_list_file
,
496 git_revision
, clean
, refresh
, base_name
,
497 gitdebug
, verbose
, extra_driver
, kup
,
499 self
.kerneldir
= kerneldir
501 self
.copy_list
= copy_list_file
502 self
.git_revision
= git_revision
504 self
.refresh
= refresh
505 self
.base_name
= base_name
506 self
.gitdebug
= gitdebug
507 self
.verbose
= verbose
508 self
.extra_driver
= extra_driver
510 self
.kup_test
= kup_test
511 def git_paranoia(tree
=None, logwrite
=lambda x
:None):
512 data
= git
.paranoia(tree
)
514 logwrite('Cannot use %s' % tree
)
515 logwrite('%s' % data
['output'])
518 logwrite('Validated tree: %s' % tree
)
520 args
= Args(kerneldir
, outdir
, copy_list_file
,
521 git_revision
, clean
, refresh
, base_name
,
522 gitdebug
, verbose
, extra_driver
, kup
, kup_test
)
525 # start processing ...
526 if (args
.kup
or args
.kup_test
):
527 git_paranoia(source_dir
, logwrite
)
528 git_paranoia(kerneldir
, logwrite
)
530 rel_describe
= git
.describe(rev
=None, tree
=source_dir
, extra_args
=['--dirty'])
531 release
= os
.path
.basename(args
.outdir
)
532 version
= release
.replace("backports-", "")
534 rel_prep
= get_rel_prep(version
)
536 logwrite('Invalid backports release name: %s' % release
)
537 logwrite('For rules on the release name see upload_release()')
539 rel_type
= "linux-stable"
540 if (not rel_prep
['stable']):
541 rel_type
= "linux-next"
542 if (rel_prep
['expected_tag'] != rel_describe
):
543 logwrite('Unexpected %s based backports release tag on' % rel_type
)
544 logwrite('the backports tree tree: %s\n' % rel_describe
)
545 logwrite('You asked to make a release with this ')
546 logwrite('directory name: %s' % release
)
547 logwrite('The actual expected tag we should find on')
548 logwrite('the backports tree then is: %s\n' % rel_prep
['expected_tag'])
549 logwrite('For rules on the release name see upload_release()')
552 copy_list
= read_copy_list(args
.copy_list
)
553 deplist
= read_dependencies(os
.path
.join(source_dir
, 'dependencies'))
555 # validate output directory
556 check_output_dir(args
.outdir
, args
.clean
)
559 backport_files
= [(x
, x
) for x
in [
560 'Kconfig', 'Makefile', 'Makefile.build', 'Makefile.kernel', '.gitignore',
561 'Makefile.real', 'compat/', 'backport-include/', 'kconf/', 'defconfigs/',
562 'scripts/', '.blacklist.map', 'udev/',
564 if not args
.git_revision
:
565 logwrite('Copy original source files ...')
567 logwrite('Get original source files from git ...')
569 copy_files(os
.path
.join(source_dir
, 'backport'), backport_files
, args
.outdir
)
573 if not args
.git_revision
:
574 copy_files(args
.kerneldir
, copy_list
, args
.outdir
)
576 copy_git_files(args
.kerneldir
, copy_list
, args
.git_revision
, args
.outdir
)
578 # FIXME: should we add a git version of this (e.g. --git-extra-driver)?
579 for src
, copy_list
in args
.extra_driver
:
580 if (args
.kup
or args
.kup_test
):
582 copy_files(src
, read_copy_list(open(copy_list
, 'r')), args
.outdir
)
584 git_debug_snapshot(args
, 'Add driver sources')
586 disable_list
= add_automatic_backports(args
)
588 bpcfg
= kconfig
.ConfigTree(os
.path
.join(args
.outdir
, 'compat', 'Kconfig'))
589 bpcfg
.disable_symbols(disable_list
)
590 git_debug_snapshot(args
, 'Add automatic backports')
592 logwrite('Apply patches ...')
594 for root
, dirs
, files
in os
.walk(os
.path
.join(source_dir
, 'patches')):
596 if f
.endswith('.patch'):
597 patches
.append(os
.path
.join(root
, f
))
599 prefix_len
= len(os
.path
.join(source_dir
, 'patches')) + 1
600 for pfile
in patches
:
601 print_name
= pfile
[prefix_len
:]
602 # read the patch file
603 p
= patch
.fromfile(pfile
)
604 # complain if it's not a patch
606 raise Exception('No patch content found in %s' % print_name
)
607 # leading / seems to be stripped?
608 if 'dev/null' in p
.items
[0].source
:
609 raise Exception('Patches creating files are not supported (in %s)' % print_name
)
610 # check if the first file the patch touches exists, if so
611 # assume the patch needs to be applied -- otherwise continue
612 patched_file
= '/'.join(p
.items
[0].source
.split('/')[1:])
613 fullfn
= os
.path
.join(args
.outdir
, patched_file
)
614 if not os
.path
.exists(fullfn
):
616 logwrite("Not applying %s, not needed" % print_name
)
619 logwrite("Applying patch %s" % print_name
)
622 # but for refresh, of course look at all files the patch touches
623 for patchitem
in p
.items
:
624 patched_file
= '/'.join(patchitem
.source
.split('/')[1:])
625 fullfn
= os
.path
.join(args
.outdir
, patched_file
)
626 shutil
.copyfile(fullfn
, fullfn
+ '.orig_file')
628 process
= subprocess
.Popen(['patch', '-p1'], stdout
=subprocess
.PIPE
,
629 stderr
=subprocess
.STDOUT
, stdin
=subprocess
.PIPE
,
630 close_fds
=True, universal_newlines
=True,
632 output
= process
.communicate(input=open(pfile
, 'r').read())[0]
633 output
= output
.split('\n')
638 logwrite('> %s' % line
)
639 if process
.returncode
!= 0:
641 logwrite("Failed to apply changes from %s" % print_name
)
643 logwrite('> %s' % line
)
647 pfilef
= open(pfile
+ '.tmp', 'a')
648 pfilef
.write(p
.top_header
)
650 for patchitem
in p
.items
:
651 patched_file
= '/'.join(patchitem
.source
.split('/')[1:])
652 fullfn
= os
.path
.join(args
.outdir
, patched_file
)
653 process
= subprocess
.Popen(['diff', '-p', '-u', patched_file
+ '.orig_file', patched_file
,
654 '--label', 'a/' + patched_file
,
655 '--label', 'b/' + patched_file
],
656 stdout
=pfilef
, close_fds
=True,
657 universal_newlines
=True, cwd
=args
.outdir
)
659 os
.unlink(fullfn
+ '.orig_file')
660 if not process
.returncode
in (0, 1):
661 logwrite("Failed to diff to refresh %s" % print_name
)
663 os
.unlink(pfile
+ '.tmp')
666 os
.rename(pfile
+ '.tmp', pfile
)
668 # remove orig/rej files that patch sometimes creates
669 for root
, dirs
, files
in os
.walk(args
.outdir
):
671 if f
[-5:] == '.orig' or f
[-4:] == '.rej':
672 os
.unlink(os
.path
.join(root
, f
))
673 git_debug_snapshot(args
, "apply backport patch %s" % print_name
)
675 # some post-processing is required
676 configtree
= kconfig
.ConfigTree(os
.path
.join(args
.outdir
, 'Kconfig'))
677 logwrite('Modify Kconfig tree ...')
678 configtree
.prune_sources(ignore
=['Kconfig.kernel', 'Kconfig.versions'])
679 git_debug_snapshot(args
, "prune Kconfig tree")
680 configtree
.force_tristate_modular()
681 git_debug_snapshot(args
, "force tristate options modular")
682 configtree
.modify_selects()
683 git_debug_snapshot(args
, "convert select to depends on")
685 # write the versioning file
686 if git_tracked_version
:
687 backports_version
= "(see git)"
688 kernel_version
= "(see git)"
690 backports_version
= git
.describe(tree
=source_dir
, extra_args
=['--long'])
691 kernel_version
= git
.describe(rev
=args
.git_revision
or 'HEAD',
693 extra_args
=['--long'])
694 f
= open(os
.path
.join(args
.outdir
, 'versions'), 'w')
695 f
.write('BACKPORTS_VERSION="%s"\n' % backports_version
)
696 f
.write('BACKPORTED_KERNEL_VERSION="%s"\n' % kernel_version
)
697 f
.write('BACKPORTED_KERNEL_NAME="%s"\n' % args
.base_name
)
698 if git_tracked_version
:
699 f
.write('BACKPORTS_GIT_TRACKED="backport tracker ID: $(shell git rev-parse HEAD 2>/dev/null || echo \'not built in git tree\')"\n')
702 symbols
= configtree
.symbols()
704 # write local symbol list -- needed during build
705 f
= open(os
.path
.join(args
.outdir
, '.local-symbols'), 'w')
707 f
.write('%s=\n' % sym
)
710 git_debug_snapshot(args
, "add versions/symbols files")
712 logwrite('Rewrite Makefiles and Kconfig files ...')
714 # rewrite Makefile and source symbols
716 for some_symbols
in [symbols
[i
:i
+ 50] for i
in range(0, len(symbols
), 50)]:
717 r
= 'CONFIG_((' + '|'.join([s
+ '(_MODULE)?' for s
in some_symbols
]) + ')([^A-Za-z0-9_]|$))'
718 regexes
.append(re
.compile(r
, re
.MULTILINE
))
719 for root
, dirs
, files
in os
.walk(args
.outdir
):
720 # don't go into .git dir (possible debug thing)
724 data
= open(os
.path
.join(root
, f
), 'r').read()
726 data
= r
.sub(r
'CPTCFG_\1', data
)
727 data
= re
.sub(r
'\$\(srctree\)', '$(backport_srctree)', data
)
728 data
= re
.sub(r
'-Idrivers', '-I$(backport_srctree)/drivers', data
)
729 fo
= open(os
.path
.join(root
, f
), 'w')
733 git_debug_snapshot(args
, "rename config symbol / srctree usage")
735 # disable unbuildable Kconfig symbols and stuff Makefiles that doesn't exist
736 maketree
= make
.MakeTree(os
.path
.join(args
.outdir
, 'Makefile.kernel'))
738 disable_makefile
= []
739 for sym
in maketree
.get_impossible_symbols():
740 disable_kconfig
.append(sym
[7:])
741 disable_makefile
.append(sym
[7:])
743 configtree
.disable_symbols(disable_kconfig
)
744 git_debug_snapshot(args
, "disable impossible kconfig symbols")
746 # add kernel version dependencies to Kconfig, from the dependency list
748 for sym
in tuple(deplist
.keys()):
750 for dep
in deplist
[sym
]:
751 if "kconfig:" in dep
:
752 kconfig_expr
= dep
.replace('kconfig: ', '')
753 new
.append(kconfig_expr
)
754 elif (dep
== "DISABLE"):
755 new
.append('BACKPORT_DISABLED_KCONFIG_OPTION')
757 new
.append('!BACKPORT_KERNEL_%s' % dep
.replace('.', '_'))
759 configtree
.add_dependencies(deplist
)
760 git_debug_snapshot(args
, "add kernel version dependencies")
762 # disable things in makefiles that can't be selected and that the
763 # build shouldn't recurse into because they don't exist -- if we
764 # don't do that then a symbol from the kernel could cause the build
765 # to attempt to recurse and fail
767 # Note that we split the regex after 50 symbols, this is because of a
768 # limitation in the regex implementation (it only supports 100 nested
769 # groups -- 50 seemed safer and is still fast)
771 for some_symbols
in [disable_makefile
[i
:i
+ 50] for i
in range(0, len(disable_makefile
), 50)]:
772 r
= '^([^#].*((CPTCFG|CONFIG)_(' + '|'.join([s
for s
in some_symbols
]) + ')))'
773 regexes
.append(re
.compile(r
, re
.MULTILINE
))
774 for f
in maketree
.get_makefiles():
775 data
= open(f
, 'r').read()
777 data
= r
.sub(r
'#\1', data
)
781 git_debug_snapshot(args
, "disable unsatisfied Makefile parts")
783 if (args
.kup
or args
.kup_test
):
784 upload_release(args
, rel_prep
, logwrite
=logwrite
)
789 if __name__
== '__main__':