Permalink
Browse files
cli: stage command migrated to docopts
This also introduces recursive lifecycle execution to properly handle dependencies. Signed-off-by: Sergio Schvezov <sergio.schvezov@canonical.com>
- Loading branch information...
Showing
with
170 additions
and 129 deletions.
- +0 −58 snapcraft/cmds.py
- +39 −0 snapcraft/commands/stage.py
- +48 −0 snapcraft/lifecycle.py
- +0 −46 snapcraft/tests/test_cmds.py
- +73 −20 snapcraft/tests/test_lifecycle.py
- +10 −5 snapcraft/yaml.py
| @@ -1,58 +0,0 @@ | ||
| -# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- | ||
| -# | ||
| -# Copyright (C) 2015 Canonical Ltd | ||
| -# | ||
| -# This program is free software: you can redistribute it and/or modify | ||
| -# it under the terms of the GNU General Public License version 3 as | ||
| -# published by the Free Software Foundation. | ||
| -# | ||
| -# This program is distributed in the hope that it will be useful, | ||
| -# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| -# GNU General Public License for more details. | ||
| -# | ||
| -# You should have received a copy of the GNU General Public License | ||
| -# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| - | ||
| -import filecmp | ||
| -import logging | ||
| -import os | ||
| - | ||
| -logger = logging.getLogger(__name__) | ||
| - | ||
| - | ||
| -def _check_for_collisions(parts): | ||
| - parts_files = {} | ||
| - for part in parts: | ||
| - # Gather our own files up | ||
| - part_files, _ = part.migratable_fileset_for('stage') | ||
| - | ||
| - # Scan previous parts for collisions | ||
| - for other_part_name in parts_files: | ||
| - common = part_files & parts_files[other_part_name]['files'] | ||
| - conflict_files = [] | ||
| - for f in common: | ||
| - this = os.path.join(part.installdir, f) | ||
| - other = os.path.join( | ||
| - parts_files[other_part_name]['installdir'], | ||
| - f) | ||
| - if os.path.islink(this) and os.path.islink(other): | ||
| - continue | ||
| - if not filecmp.cmp(this, other, shallow=False): | ||
| - conflict_files.append(f) | ||
| - | ||
| - if conflict_files: | ||
| - logger.error('Error: parts %s and %s have the following file ' | ||
| - 'paths in common which have different ' | ||
| - 'contents:\n %s', | ||
| - other_part_name, | ||
| - part.name, | ||
| - '\n '.join(sorted(conflict_files))) | ||
| - | ||
| - return False | ||
| - | ||
| - # And add our files to the list | ||
| - parts_files[part.name] = {'files': part_files, | ||
| - 'installdir': part.installdir} | ||
| - | ||
| - return True |
| @@ -0,0 +1,39 @@ | ||
| +# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- | ||
| +# | ||
| +# Copyright (C) 2015 Canonical Ltd | ||
| +# | ||
| +# This program is free software: you can redistribute it and/or modify | ||
| +# it under the terms of the GNU General Public License version 3 as | ||
| +# published by the Free Software Foundation. | ||
| +# | ||
| +# This program is distributed in the hope that it will be useful, | ||
| +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| +# GNU General Public License for more details. | ||
| +# | ||
| +# You should have received a copy of the GNU General Public License | ||
| +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| + | ||
| +""" | ||
| +snapcraft stage | ||
| + | ||
| +Stage parts. | ||
| + | ||
| +Usage: | ||
| + stage [options] [PART ...] | ||
| + | ||
| +Options: | ||
| + -h --help show this help message and exit. | ||
| + | ||
| +""" | ||
| + | ||
| +from docopt import docopt | ||
| + | ||
| +from snapcraft import lifecycle | ||
| + | ||
| + | ||
| +def main(argv=None): | ||
| + argv = argv if argv else [] | ||
| + args = docopt(__doc__, argv=argv) | ||
| + | ||
| + lifecycle.execute('stage', args['PART']) |
| @@ -15,6 +15,7 @@ | ||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| import contextlib | ||
| +import filecmp | ||
| import glob | ||
| import importlib | ||
| import logging | ||
| @@ -48,15 +49,30 @@ def execute(step, part_names=None): | ||
| parts = {p for p in config.all_parts if p.name in part_names} | ||
| else: | ||
| parts = config.all_parts | ||
| + part_names = config.part_names | ||
| step_index = common.COMMAND_ORDER.index(step) + 1 | ||
| for step in common.COMMAND_ORDER[0:step_index]: | ||
| + if step == 'stage': | ||
| + _check_for_collisions(config.all_parts) | ||
| for part in parts: | ||
| + prereqs = config.part_prereqs(part.name) | ||
| + if prereqs and not prereqs.issubset(part_names): | ||
| + raise RuntimeError( | ||
| + 'Requested {!r} of {!r} but there are prerequisites: ' | ||
|
|
||
| + '{!r}'.format(step, part.name, ' '.join(prereqs))) | ||
| + elif prereqs: | ||
| + # prerequisites need to build all the way to the staging | ||
| + # step to be able to share the common assets that make them | ||
| + # a dependency. | ||
| + execute('stage', prereqs) | ||
sergiusens
Owner
|
||
| common.env = config.build_env_for_part(part) | ||
| if step == 'pull': | ||
| part.pull() | ||
| elif step == 'build': | ||
| part.build() | ||
| + elif step == 'stage': | ||
| + part.stage() | ||
| class PluginError(Exception): | ||
| @@ -420,3 +436,35 @@ def _validate_relative_paths(files): | ||
| for d in files: | ||
| if os.path.isabs(d): | ||
| raise PluginError('path "{}" must be relative'.format(d)) | ||
| + | ||
| + | ||
| +def _check_for_collisions(parts): | ||
| + parts_files = {} | ||
| + for part in parts: | ||
| + # Gather our own files up | ||
| + part_files, _ = part.migratable_fileset_for('stage') | ||
| + | ||
| + # Scan previous parts for collisions | ||
| + for other_part_name in parts_files: | ||
| + common = part_files & parts_files[other_part_name]['files'] | ||
| + conflict_files = [] | ||
| + for f in common: | ||
| + this = os.path.join(part.installdir, f) | ||
| + other = os.path.join( | ||
| + parts_files[other_part_name]['installdir'], | ||
| + f) | ||
| + if os.path.islink(this) and os.path.islink(other): | ||
| + continue | ||
| + if not filecmp.cmp(this, other, shallow=False): | ||
| + conflict_files.append(f) | ||
| + | ||
| + if conflict_files: | ||
| + raise EnvironmentError( | ||
| + 'Parts {!r} and {!r} have the following file paths in ' | ||
| + 'common which have different contents:\n{}'.format( | ||
| + other_part_name, part.name, | ||
| + '\n'.join(sorted(conflict_files)))) | ||
| + | ||
| + # And add our files to the list | ||
| + parts_files[part.name] = {'files': part_files, | ||
| + 'installdir': part.installdir} | ||
Oops, something went wrong.
unsatisfied prerequisites?