diff options
| author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2015-08-05 15:48:00 +0100 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-09-03 23:45:54 +0100 |
| commit | e616beba1c85e31246d1c798191b194d168b3489 (patch) | |
| tree | 5b9d19e7c4a7caeb72f1bb9da4a2b221cfb1da96 /scripts/lib/devtool/standard.py | |
| parent | f2854c67ce963211f27223bd1194420621694bc2 (diff) | |
| download | poky-e616beba1c85e31246d1c798191b194d168b3489.tar.gz | |
scripts: ensure tinfoil is shut down correctly
We should always shut down tinfoil when we're finished with it, either
by explicitly calling the shutdown() method or by using it as a
context manager ("with ...").
(From OE-Core rev: 5ec6d9ef309b841cdcbf1d14ac678d106d5d888a)
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/lib/devtool/standard.py')
| -rw-r--r-- | scripts/lib/devtool/standard.py | 355 |
1 files changed, 183 insertions, 172 deletions
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py index 0d5a42197b..98451da441 100644 --- a/scripts/lib/devtool/standard.py +++ b/scripts/lib/devtool/standard.py | |||
| @@ -213,54 +213,56 @@ def add(args, config, basepath, workspace): | |||
| 213 | _add_md5(config, recipename, os.path.join(recipedir, fn)) | 213 | _add_md5(config, recipename, os.path.join(recipedir, fn)) |
| 214 | 214 | ||
| 215 | tinfoil = setup_tinfoil(config_only=True, basepath=basepath) | 215 | tinfoil = setup_tinfoil(config_only=True, basepath=basepath) |
| 216 | rd = oe.recipeutils.parse_recipe(tinfoil.cooker, recipefile, None) | 216 | try: |
| 217 | if not rd: | 217 | rd = oe.recipeutils.parse_recipe(tinfoil.cooker, recipefile, None) |
| 218 | return 1 | 218 | if not rd: |
| 219 | 219 | return 1 | |
| 220 | if args.fetchuri and not args.no_git: | ||
| 221 | setup_git_repo(srctree, args.version, 'devtool', d=tinfoil.config_data) | ||
| 222 | |||
| 223 | initial_rev = None | ||
| 224 | if os.path.exists(os.path.join(srctree, '.git')): | ||
| 225 | (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree) | ||
| 226 | initial_rev = stdout.rstrip() | ||
| 227 | |||
| 228 | if args.src_subdir: | ||
| 229 | srctree = os.path.join(srctree, args.src_subdir) | ||
| 230 | |||
| 231 | bb.utils.mkdirhier(os.path.dirname(appendfile)) | ||
| 232 | with open(appendfile, 'w') as f: | ||
| 233 | f.write('inherit externalsrc\n') | ||
| 234 | f.write('EXTERNALSRC = "%s"\n' % srctree) | ||
| 235 | |||
| 236 | b_is_s = use_external_build(args.same_dir, args.no_same_dir, rd) | ||
| 237 | if b_is_s: | ||
| 238 | f.write('EXTERNALSRC_BUILD = "%s"\n' % srctree) | ||
| 239 | if initial_rev: | ||
| 240 | f.write('\n# initial_rev: %s\n' % initial_rev) | ||
| 241 | |||
| 242 | if args.binary: | ||
| 243 | f.write('do_install_append() {\n') | ||
| 244 | f.write(' rm -rf ${D}/.git\n') | ||
| 245 | f.write(' rm -f ${D}/singletask.lock\n') | ||
| 246 | f.write('}\n') | ||
| 247 | |||
| 248 | if bb.data.inherits_class('npm', rd): | ||
| 249 | f.write('do_install_append() {\n') | ||
| 250 | f.write(' # Remove files added to source dir by devtool/externalsrc\n') | ||
| 251 | f.write(' rm -f ${NPM_INSTALLDIR}/singletask.lock\n') | ||
| 252 | f.write(' rm -rf ${NPM_INSTALLDIR}/.git\n') | ||
| 253 | f.write(' rm -rf ${NPM_INSTALLDIR}/oe-local-files\n') | ||
| 254 | f.write(' for symlink in ${EXTERNALSRC_SYMLINKS} ; do\n') | ||
| 255 | f.write(' rm -f ${NPM_INSTALLDIR}/${symlink%%:*}\n') | ||
| 256 | f.write(' done\n') | ||
| 257 | f.write('}\n') | ||
| 258 | 220 | ||
| 259 | _add_md5(config, recipename, appendfile) | 221 | if args.fetchuri and not args.no_git: |
| 222 | setup_git_repo(srctree, args.version, 'devtool', d=tinfoil.config_data) | ||
| 260 | 223 | ||
| 261 | logger.info('Recipe %s has been automatically created; further editing may be required to make it fully functional' % recipefile) | 224 | initial_rev = None |
| 225 | if os.path.exists(os.path.join(srctree, '.git')): | ||
| 226 | (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree) | ||
| 227 | initial_rev = stdout.rstrip() | ||
| 228 | |||
| 229 | if args.src_subdir: | ||
| 230 | srctree = os.path.join(srctree, args.src_subdir) | ||
| 231 | |||
| 232 | bb.utils.mkdirhier(os.path.dirname(appendfile)) | ||
| 233 | with open(appendfile, 'w') as f: | ||
| 234 | f.write('inherit externalsrc\n') | ||
| 235 | f.write('EXTERNALSRC = "%s"\n' % srctree) | ||
| 236 | |||
| 237 | b_is_s = use_external_build(args.same_dir, args.no_same_dir, rd) | ||
| 238 | if b_is_s: | ||
| 239 | f.write('EXTERNALSRC_BUILD = "%s"\n' % srctree) | ||
| 240 | if initial_rev: | ||
| 241 | f.write('\n# initial_rev: %s\n' % initial_rev) | ||
| 242 | |||
| 243 | if args.binary: | ||
| 244 | f.write('do_install_append() {\n') | ||
| 245 | f.write(' rm -rf ${D}/.git\n') | ||
| 246 | f.write(' rm -f ${D}/singletask.lock\n') | ||
| 247 | f.write('}\n') | ||
| 248 | |||
| 249 | if bb.data.inherits_class('npm', rd): | ||
| 250 | f.write('do_install_append() {\n') | ||
| 251 | f.write(' # Remove files added to source dir by devtool/externalsrc\n') | ||
| 252 | f.write(' rm -f ${NPM_INSTALLDIR}/singletask.lock\n') | ||
| 253 | f.write(' rm -rf ${NPM_INSTALLDIR}/.git\n') | ||
| 254 | f.write(' rm -rf ${NPM_INSTALLDIR}/oe-local-files\n') | ||
| 255 | f.write(' for symlink in ${EXTERNALSRC_SYMLINKS} ; do\n') | ||
| 256 | f.write(' rm -f ${NPM_INSTALLDIR}/${symlink%%:*}\n') | ||
| 257 | f.write(' done\n') | ||
| 258 | f.write('}\n') | ||
| 259 | |||
| 260 | _add_md5(config, recipename, appendfile) | ||
| 261 | |||
| 262 | logger.info('Recipe %s has been automatically created; further editing may be required to make it fully functional' % recipefile) | ||
| 262 | 263 | ||
| 263 | tinfoil.shutdown() | 264 | finally: |
| 265 | tinfoil.shutdown() | ||
| 264 | 266 | ||
| 265 | return 0 | 267 | return 0 |
| 266 | 268 | ||
| @@ -352,19 +354,21 @@ def extract(args, config, basepath, workspace): | |||
| 352 | if not tinfoil: | 354 | if not tinfoil: |
| 353 | # Error already shown | 355 | # Error already shown |
| 354 | return 1 | 356 | return 1 |
| 357 | try: | ||
| 358 | rd = parse_recipe(config, tinfoil, args.recipename, True) | ||
| 359 | if not rd: | ||
| 360 | return 1 | ||
| 355 | 361 | ||
| 356 | rd = parse_recipe(config, tinfoil, args.recipename, True) | 362 | srctree = os.path.abspath(args.srctree) |
| 357 | if not rd: | 363 | initial_rev = _extract_source(srctree, args.keep_temp, args.branch, False, rd) |
| 358 | return 1 | 364 | logger.info('Source tree extracted to %s' % srctree) |
| 359 | |||
| 360 | srctree = os.path.abspath(args.srctree) | ||
| 361 | initial_rev = _extract_source(srctree, args.keep_temp, args.branch, False, rd) | ||
| 362 | logger.info('Source tree extracted to %s' % srctree) | ||
| 363 | 365 | ||
| 364 | if initial_rev: | 366 | if initial_rev: |
| 365 | return 0 | 367 | return 0 |
| 366 | else: | 368 | else: |
| 367 | return 1 | 369 | return 1 |
| 370 | finally: | ||
| 371 | tinfoil.shutdown() | ||
| 368 | 372 | ||
| 369 | def sync(args, config, basepath, workspace): | 373 | def sync(args, config, basepath, workspace): |
| 370 | """Entry point for the devtool 'sync' subcommand""" | 374 | """Entry point for the devtool 'sync' subcommand""" |
| @@ -374,19 +378,21 @@ def sync(args, config, basepath, workspace): | |||
| 374 | if not tinfoil: | 378 | if not tinfoil: |
| 375 | # Error already shown | 379 | # Error already shown |
| 376 | return 1 | 380 | return 1 |
| 381 | try: | ||
| 382 | rd = parse_recipe(config, tinfoil, args.recipename, True) | ||
| 383 | if not rd: | ||
| 384 | return 1 | ||
| 377 | 385 | ||
| 378 | rd = parse_recipe(config, tinfoil, args.recipename, True) | 386 | srctree = os.path.abspath(args.srctree) |
| 379 | if not rd: | 387 | initial_rev = _extract_source(srctree, args.keep_temp, args.branch, True, rd) |
| 380 | return 1 | 388 | logger.info('Source tree %s synchronized' % srctree) |
| 381 | |||
| 382 | srctree = os.path.abspath(args.srctree) | ||
| 383 | initial_rev = _extract_source(srctree, args.keep_temp, args.branch, True, rd) | ||
| 384 | logger.info('Source tree %s synchronized' % srctree) | ||
| 385 | 389 | ||
| 386 | if initial_rev: | 390 | if initial_rev: |
| 387 | return 0 | 391 | return 0 |
| 388 | else: | 392 | else: |
| 389 | return 1 | 393 | return 1 |
| 394 | finally: | ||
| 395 | tinfoil.shutdown() | ||
| 390 | 396 | ||
| 391 | class BbTaskExecutor(object): | 397 | class BbTaskExecutor(object): |
| 392 | """Class for executing bitbake tasks for a recipe | 398 | """Class for executing bitbake tasks for a recipe |
| @@ -715,109 +721,111 @@ def modify(args, config, basepath, workspace): | |||
| 715 | args.recipename) | 721 | args.recipename) |
| 716 | 722 | ||
| 717 | tinfoil = setup_tinfoil(basepath=basepath) | 723 | tinfoil = setup_tinfoil(basepath=basepath) |
| 718 | rd = parse_recipe(config, tinfoil, args.recipename, True) | 724 | try: |
| 719 | if not rd: | 725 | rd = parse_recipe(config, tinfoil, args.recipename, True) |
| 720 | return 1 | 726 | if not rd: |
| 721 | |||
| 722 | pn = rd.getVar('PN', True) | ||
| 723 | if pn != args.recipename: | ||
| 724 | logger.info('Mapping %s to %s' % (args.recipename, pn)) | ||
| 725 | if pn in workspace: | ||
| 726 | raise DevtoolError("recipe %s is already in your workspace" % | ||
| 727 | pn) | ||
| 728 | |||
| 729 | if args.srctree: | ||
| 730 | srctree = os.path.abspath(args.srctree) | ||
| 731 | else: | ||
| 732 | srctree = get_default_srctree(config, pn) | ||
| 733 | |||
| 734 | if args.no_extract and not os.path.isdir(srctree): | ||
| 735 | raise DevtoolError("--no-extract specified and source path %s does " | ||
| 736 | "not exist or is not a directory" % | ||
| 737 | srctree) | ||
| 738 | if not args.no_extract: | ||
| 739 | tinfoil = _prep_extract_operation(config, basepath, pn, tinfoil) | ||
| 740 | if not tinfoil: | ||
| 741 | # Error already shown | ||
| 742 | return 1 | 727 | return 1 |
| 743 | 728 | ||
| 744 | recipefile = rd.getVar('FILE', True) | 729 | pn = rd.getVar('PN', True) |
| 745 | appendfile = recipe_to_append(recipefile, config, args.wildcard) | 730 | if pn != args.recipename: |
| 746 | if os.path.exists(appendfile): | 731 | logger.info('Mapping %s to %s' % (args.recipename, pn)) |
| 747 | raise DevtoolError("Another variant of recipe %s is already in your " | 732 | if pn in workspace: |
| 748 | "workspace (only one variant of a recipe can " | 733 | raise DevtoolError("recipe %s is already in your workspace" % |
| 749 | "currently be worked on at once)" | 734 | pn) |
| 750 | % pn) | ||
| 751 | |||
| 752 | _check_compatible_recipe(pn, rd) | ||
| 753 | 735 | ||
| 754 | initial_rev = None | 736 | if args.srctree: |
| 755 | commits = [] | 737 | srctree = os.path.abspath(args.srctree) |
| 756 | if not args.no_extract: | 738 | else: |
| 757 | initial_rev = _extract_source(srctree, False, args.branch, False, rd) | 739 | srctree = get_default_srctree(config, pn) |
| 758 | if not initial_rev: | 740 | |
| 759 | return 1 | 741 | if args.no_extract and not os.path.isdir(srctree): |
| 760 | logger.info('Source tree extracted to %s' % srctree) | 742 | raise DevtoolError("--no-extract specified and source path %s does " |
| 761 | # Get list of commits since this revision | 743 | "not exist or is not a directory" % |
| 762 | (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_rev, cwd=srctree) | 744 | srctree) |
| 763 | commits = stdout.split() | 745 | if not args.no_extract: |
| 764 | else: | 746 | tinfoil = _prep_extract_operation(config, basepath, pn, tinfoil) |
| 765 | if os.path.exists(os.path.join(srctree, '.git')): | 747 | if not tinfoil: |
| 766 | # Check if it's a tree previously extracted by us | 748 | # Error already shown |
| 767 | try: | 749 | return 1 |
| 768 | (stdout, _) = bb.process.run('git branch --contains devtool-base', cwd=srctree) | 750 | |
| 769 | except bb.process.ExecutionError: | 751 | recipefile = rd.getVar('FILE', True) |
| 770 | stdout = '' | 752 | appendfile = recipe_to_append(recipefile, config, args.wildcard) |
| 771 | for line in stdout.splitlines(): | 753 | if os.path.exists(appendfile): |
| 772 | if line.startswith('*'): | 754 | raise DevtoolError("Another variant of recipe %s is already in your " |
| 773 | (stdout, _) = bb.process.run('git rev-parse devtool-base', cwd=srctree) | 755 | "workspace (only one variant of a recipe can " |
| 774 | initial_rev = stdout.rstrip() | 756 | "currently be worked on at once)" |
| 757 | % pn) | ||
| 758 | |||
| 759 | _check_compatible_recipe(pn, rd) | ||
| 760 | |||
| 761 | initial_rev = None | ||
| 762 | commits = [] | ||
| 763 | if not args.no_extract: | ||
| 764 | initial_rev = _extract_source(srctree, False, args.branch, False, rd) | ||
| 775 | if not initial_rev: | 765 | if not initial_rev: |
| 776 | # Otherwise, just grab the head revision | 766 | return 1 |
| 777 | (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree) | 767 | logger.info('Source tree extracted to %s' % srctree) |
| 778 | initial_rev = stdout.rstrip() | 768 | # Get list of commits since this revision |
| 779 | 769 | (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_rev, cwd=srctree) | |
| 780 | # Check that recipe isn't using a shared workdir | 770 | commits = stdout.split() |
| 781 | s = os.path.abspath(rd.getVar('S', True)) | 771 | else: |
| 782 | workdir = os.path.abspath(rd.getVar('WORKDIR', True)) | 772 | if os.path.exists(os.path.join(srctree, '.git')): |
| 783 | if s.startswith(workdir) and s != workdir and os.path.dirname(s) != workdir: | 773 | # Check if it's a tree previously extracted by us |
| 784 | # Handle if S is set to a subdirectory of the source | 774 | try: |
| 785 | srcsubdir = os.path.relpath(s, workdir).split(os.sep, 1)[1] | 775 | (stdout, _) = bb.process.run('git branch --contains devtool-base', cwd=srctree) |
| 786 | srctree = os.path.join(srctree, srcsubdir) | 776 | except bb.process.ExecutionError: |
| 787 | 777 | stdout = '' | |
| 788 | bb.utils.mkdirhier(os.path.dirname(appendfile)) | 778 | for line in stdout.splitlines(): |
| 789 | with open(appendfile, 'w') as f: | 779 | if line.startswith('*'): |
| 790 | f.write('FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n') | 780 | (stdout, _) = bb.process.run('git rev-parse devtool-base', cwd=srctree) |
| 791 | # Local files can be modified/tracked in separate subdir under srctree | 781 | initial_rev = stdout.rstrip() |
| 792 | # Mostly useful for packages with S != WORKDIR | 782 | if not initial_rev: |
| 793 | f.write('FILESPATH_prepend := "%s:"\n' % | 783 | # Otherwise, just grab the head revision |
| 794 | os.path.join(srctree, 'oe-local-files')) | 784 | (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree) |
| 795 | 785 | initial_rev = stdout.rstrip() | |
| 796 | f.write('\ninherit externalsrc\n') | ||
| 797 | f.write('# NOTE: We use pn- overrides here to avoid affecting multiple variants in the case where the recipe uses BBCLASSEXTEND\n') | ||
| 798 | f.write('EXTERNALSRC_pn-%s = "%s"\n' % (pn, srctree)) | ||
| 799 | |||
| 800 | b_is_s = use_external_build(args.same_dir, args.no_same_dir, rd) | ||
| 801 | if b_is_s: | ||
| 802 | f.write('EXTERNALSRC_BUILD_pn-%s = "%s"\n' % (pn, srctree)) | ||
| 803 | |||
| 804 | if bb.data.inherits_class('kernel', rd): | ||
| 805 | f.write('SRCTREECOVEREDTASKS = "do_validate_branches do_kernel_checkout ' | ||
| 806 | 'do_fetch do_unpack do_patch do_kernel_configme do_kernel_configcheck"\n') | ||
| 807 | f.write('\ndo_configure_append() {\n' | ||
| 808 | ' cp ${B}/.config ${S}/.config.baseline\n' | ||
| 809 | ' ln -sfT ${B}/.config ${S}/.config.new\n' | ||
| 810 | '}\n') | ||
| 811 | if initial_rev: | ||
| 812 | f.write('\n# initial_rev: %s\n' % initial_rev) | ||
| 813 | for commit in commits: | ||
| 814 | f.write('# commit: %s\n' % commit) | ||
| 815 | |||
| 816 | _add_md5(config, pn, appendfile) | ||
| 817 | 786 | ||
| 818 | logger.info('Recipe %s now set up to build from %s' % (pn, srctree)) | 787 | # Check that recipe isn't using a shared workdir |
| 788 | s = os.path.abspath(rd.getVar('S', True)) | ||
| 789 | workdir = os.path.abspath(rd.getVar('WORKDIR', True)) | ||
| 790 | if s.startswith(workdir) and s != workdir and os.path.dirname(s) != workdir: | ||
| 791 | # Handle if S is set to a subdirectory of the source | ||
| 792 | srcsubdir = os.path.relpath(s, workdir).split(os.sep, 1)[1] | ||
| 793 | srctree = os.path.join(srctree, srcsubdir) | ||
| 794 | |||
| 795 | bb.utils.mkdirhier(os.path.dirname(appendfile)) | ||
| 796 | with open(appendfile, 'w') as f: | ||
| 797 | f.write('FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n') | ||
| 798 | # Local files can be modified/tracked in separate subdir under srctree | ||
| 799 | # Mostly useful for packages with S != WORKDIR | ||
| 800 | f.write('FILESPATH_prepend := "%s:"\n' % | ||
| 801 | os.path.join(srctree, 'oe-local-files')) | ||
| 802 | |||
| 803 | f.write('\ninherit externalsrc\n') | ||
| 804 | f.write('# NOTE: We use pn- overrides here to avoid affecting multiple variants in the case where the recipe uses BBCLASSEXTEND\n') | ||
| 805 | f.write('EXTERNALSRC_pn-%s = "%s"\n' % (pn, srctree)) | ||
| 806 | |||
| 807 | b_is_s = use_external_build(args.same_dir, args.no_same_dir, rd) | ||
| 808 | if b_is_s: | ||
| 809 | f.write('EXTERNALSRC_BUILD_pn-%s = "%s"\n' % (pn, srctree)) | ||
| 810 | |||
| 811 | if bb.data.inherits_class('kernel', rd): | ||
| 812 | f.write('SRCTREECOVEREDTASKS = "do_validate_branches do_kernel_checkout ' | ||
| 813 | 'do_fetch do_unpack do_patch do_kernel_configme do_kernel_configcheck"\n') | ||
| 814 | f.write('\ndo_configure_append() {\n' | ||
| 815 | ' cp ${B}/.config ${S}/.config.baseline\n' | ||
| 816 | ' ln -sfT ${B}/.config ${S}/.config.new\n' | ||
| 817 | '}\n') | ||
| 818 | if initial_rev: | ||
| 819 | f.write('\n# initial_rev: %s\n' % initial_rev) | ||
| 820 | for commit in commits: | ||
| 821 | f.write('# commit: %s\n' % commit) | ||
| 822 | |||
| 823 | _add_md5(config, pn, appendfile) | ||
| 824 | |||
| 825 | logger.info('Recipe %s now set up to build from %s' % (pn, srctree)) | ||
| 819 | 826 | ||
| 820 | tinfoil.shutdown() | 827 | finally: |
| 828 | tinfoil.shutdown() | ||
| 821 | 829 | ||
| 822 | return 0 | 830 | return 0 |
| 823 | 831 | ||
| @@ -1290,17 +1298,20 @@ def update_recipe(args, config, basepath, workspace): | |||
| 1290 | 'destination layer "%s"' % args.append) | 1298 | 'destination layer "%s"' % args.append) |
| 1291 | 1299 | ||
| 1292 | tinfoil = setup_tinfoil(basepath=basepath, tracking=True) | 1300 | tinfoil = setup_tinfoil(basepath=basepath, tracking=True) |
| 1301 | try: | ||
| 1293 | 1302 | ||
| 1294 | rd = parse_recipe(config, tinfoil, args.recipename, True) | 1303 | rd = parse_recipe(config, tinfoil, args.recipename, True) |
| 1295 | if not rd: | 1304 | if not rd: |
| 1296 | return 1 | 1305 | return 1 |
| 1297 | 1306 | ||
| 1298 | updated = _update_recipe(args.recipename, workspace, rd, args.mode, args.append, args.wildcard_version, args.no_remove, args.initial_rev) | 1307 | updated = _update_recipe(args.recipename, workspace, rd, args.mode, args.append, args.wildcard_version, args.no_remove, args.initial_rev) |
| 1299 | 1308 | ||
| 1300 | if updated: | 1309 | if updated: |
| 1301 | rf = rd.getVar('FILE', True) | 1310 | rf = rd.getVar('FILE', True) |
| 1302 | if rf.startswith(config.workspace_path): | 1311 | if rf.startswith(config.workspace_path): |
| 1303 | logger.warn('Recipe file %s has been updated but is inside the workspace - you will need to move it (and any associated files next to it) out to the desired layer before using "devtool reset" in order to keep any changes' % rf) | 1312 | logger.warn('Recipe file %s has been updated but is inside the workspace - you will need to move it (and any associated files next to it) out to the desired layer before using "devtool reset" in order to keep any changes' % rf) |
| 1313 | finally: | ||
| 1314 | tinfoil.shutdown() | ||
| 1304 | 1315 | ||
| 1305 | return 0 | 1316 | return 0 |
| 1306 | 1317 | ||
