def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self._project_options = project_options self._snapcraft_yaml = get_snapcraft_yaml() snapcraft_yaml = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(snapcraft_yaml) self._validator.validate() snapcraft_yaml = self._process_remote_parts(snapcraft_yaml) snapcraft_yaml = self._expand_filesets(snapcraft_yaml) self.data = self._expand_env(snapcraft_yaml) self._ensure_no_duplicate_app_aliases() # both confinement type and build quality are optionals _ensure_confinement_default(self.data, self._validator.schema) _ensure_grade_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self.parts = parts.PartsConfig(self.data, self._project_options, self._validator, self.build_tools, self._snapcraft_yaml) if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch]
def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self._project_options = project_options self._snapcraft_yaml = _get_snapcraft_yaml() self.data = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(self.data) self._validator.validate() _ensure_confinement_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self.parts = parts.PartsConfig(self.data.get('parts', {}), self._project_options, self._validator, self.build_tools, self._snapcraft_yaml) if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch]
def __init__(self, project_options=None): self.build_tools = [] self.all_parts = [] self._part_names = [] self._project_options = project_options self.after_requests = {} self.data = _snapcraft_yaml_load() # To make the transition less painful self._remap_skills_to_interfaces() self._validator = Validator(self.data) self._validator.validate() self.build_tools = self.data.get('build-packages', []) self._wiki = wiki.Wiki() for part_name in self.data.get('parts', []): self._part_names.append(part_name) properties = self.data['parts'][part_name] or {} plugin_name = properties.pop('plugin', None) if not plugin_name: logger.info( 'Searching the wiki to compose part "{}"'.format( part_name)) with contextlib.suppress(KeyError): properties = self._wiki.compose(part_name, properties) plugin_name = properties.pop('plugin', None) # The wiki still supports using 'type' for snapcraft 1.x if 'type' in properties: del properties['type'] if not plugin_name: raise PluginNotDefinedError(part_name) if 'after' in properties: self.after_requests[part_name] = properties.pop('after') properties['stage'] = _expand_filesets_for('stage', properties) properties['snap'] = _expand_filesets_for('snap', properties) if 'filesets' in properties: del properties['filesets'] self.load_plugin(part_name, plugin_name, properties) self._compute_part_dependencies() self.all_parts = self._sort_parts() if 'architectures' not in self.data: self.data['architectures'] = [common.get_arch(), ]
def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self.all_parts = [] self._part_names = [] self._project_options = project_options self.after_requests = {} self.data = _snapcraft_yaml_load() self._validator = Validator(self.data) self._validator.validate() self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self._wiki = wiki.Wiki() self._process_parts()
def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self.all_parts = [] self._part_names = [] self._project_options = project_options self.after_requests = {} self._snapcraft_yaml = _get_snapcraft_yaml() self.data = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(self.data) self._validator.validate() _ensure_confinement_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self._remote_parts = parts.get_remote_parts() self._process_parts()
def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self.all_parts = [] self._part_names = [] self._project_options = project_options self.after_requests = {} self._snapcraft_yaml = _get_snapcraft_yaml() self.data = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(self.data) self._validator.validate() _ensure_confinement_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self._process_parts()
class Config: @property def part_names(self): return self.parts.part_names @property def all_parts(self): return self.parts.all_parts @property def _remote_parts(self): if getattr(self, '_remote_parts_attr', None) is None: self._remote_parts_attr = get_remote_parts() return self._remote_parts_attr def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self._project_options = project_options self._snapcraft_yaml = get_snapcraft_yaml() snapcraft_yaml = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(snapcraft_yaml) self._validator.validate() snapcraft_yaml = self._process_remote_parts(snapcraft_yaml) snapcraft_yaml = self._expand_filesets(snapcraft_yaml) self.data = self._expand_env(snapcraft_yaml) self._ensure_no_duplicate_app_aliases() # both confinement type and build quality are optionals _ensure_confinement_default(self.data, self._validator.schema) _ensure_grade_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self.parts = parts.PartsConfig(self.data, self._project_options, self._validator, self.build_tools, self._snapcraft_yaml) if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch] def _ensure_no_duplicate_app_aliases(self): # Prevent multiple apps within a snap from having duplicate alias names aliases = [] for app_name, app in self.data.get('apps', {}).items(): aliases.extend(app.get('aliases', [])) seen = set() duplicates = set() for alias in aliases: if alias in seen: duplicates.add(alias) else: seen.add(alias) if duplicates: raise errors.DuplicateAliasError(aliases=duplicates) def get_project_state(self, step): """Returns a dict of states for the given step of each part.""" state = {} for part in self.parts.all_parts: state[part.name] = part.get_state(step) return state def stage_env(self): stage_dir = self._project_options.stage_dir core_dynamic_linker = self._project_options.get_core_dynamic_linker() env = [] env += _runtime_env(stage_dir, self._project_options.arch_triplet) env += _build_env_for_stage( stage_dir, self.data['name'], self.data['confinement'], self._project_options.arch_triplet, core_dynamic_linker=core_dynamic_linker) for part in self.parts.all_parts: env += part.env(stage_dir) return env def snap_env(self): snap_dir = self._project_options.snap_dir env = [] env += _runtime_env(snap_dir, self._project_options.arch_triplet) dependency_paths = set() for part in self.parts.all_parts: env += part.env(snap_dir) dependency_paths |= part.get_primed_dependency_paths() # Dependency paths are only valid if they actually exist. Sorting them # here as well so the LD_LIBRARY_PATH is consistent between runs. dependency_paths = sorted({ path for path in dependency_paths if os.path.isdir(path)}) if dependency_paths: # Add more specific LD_LIBRARY_PATH from the dependencies. env.append('LD_LIBRARY_PATH="' + ':'.join(dependency_paths) + ':$LD_LIBRARY_PATH"') return env def project_env(self): return [ 'SNAPCRAFT_STAGE={}'.format(self._project_options.stage_dir), 'SNAPCRAFT_PROJECT_NAME={}'.format(self.data['name']), 'SNAPCRAFT_PROJECT_VERSION={}'.format(self.data['version']), ] def _expand_env(self, snapcraft_yaml): environment_keys = ['name', 'version'] for key in snapcraft_yaml: if any((key == env_key for env_key in environment_keys)): continue snapcraft_yaml[key] = replace_attr( snapcraft_yaml[key], [ ('$SNAPCRAFT_PROJECT_NAME', snapcraft_yaml['name']), ('$SNAPCRAFT_PROJECT_VERSION', snapcraft_yaml['version']), ('$SNAPCRAFT_STAGE', self._project_options.stage_dir), ]) return snapcraft_yaml def _expand_filesets(self, snapcraft_yaml): parts = snapcraft_yaml.get('parts', {}) for part_name in parts: # FIXME: Remove `snap` from here; it's deprecated for step in ('stage', 'snap', 'prime'): step_fileset = _expand_filesets_for(step, parts[part_name]) parts[part_name][step] = step_fileset return snapcraft_yaml def _process_remote_parts(self, snapcraft_yaml): parts = snapcraft_yaml.get('parts', {}) new_parts = {} for part_name in parts: if 'plugin' not in parts[part_name]: properties = self._remote_parts.compose(part_name, parts[part_name]) new_parts[part_name] = properties else: new_parts[part_name] = parts[part_name].copy() after_parts = parts[part_name].get('after', []) after_remote_parts = [p for p in after_parts if p not in parts] for after_part in after_remote_parts: properties = self._remote_parts.get_part(after_part) new_parts[after_part] = properties snapcraft_yaml['parts'] = new_parts return snapcraft_yaml
class Config: @property def part_names(self): return self._part_names def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self.all_parts = [] self._part_names = [] self._project_options = project_options self.after_requests = {} self.data = _snapcraft_yaml_load() self._validator = Validator(self.data) self._validator.validate() _ensure_confinement_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self._wiki = wiki.Wiki() self._process_parts() def _process_parts(self): for part_name in self.data.get('parts', []): self._part_names.append(part_name) properties = self.data['parts'][part_name] or {} plugin_name = properties.pop('plugin', None) if not plugin_name: logger.info( 'Searching the wiki to compose part "{}"'.format( part_name)) with contextlib.suppress(KeyError): properties = self._wiki.compose(part_name, properties) plugin_name = properties.pop('plugin', None) # The wiki still supports using 'type' for snapcraft 1.x if 'type' in properties: del properties['type'] if not plugin_name: raise PluginNotDefinedError(part_name) if 'after' in properties: self.after_requests[part_name] = properties.pop('after') properties['stage'] = _expand_filesets_for('stage', properties) properties['snap'] = _expand_filesets_for('snap', properties) if 'filesets' in properties: del properties['filesets'] self.load_plugin(part_name, plugin_name, properties) self._compute_part_dependencies() self.all_parts = self._sort_parts() if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch] def _compute_part_dependencies(self): '''Gather the lists of dependencies and adds to all_parts.''' for part in self.all_parts: dep_names = self.after_requests.get(part.name, []) for dep in dep_names: found = False for i in range(len(self.all_parts)): if dep == self.all_parts[i].name: part.deps.append(self.all_parts[i]) found = True break if not found: wiki_part = self._wiki.get_part(dep) found = True if wiki_part else False if found: plugin_name = wiki_part.pop('plugin') part.deps.append(self.load_plugin( dep, plugin_name, wiki_part)) self._part_names.append(dep) if not found: raise SnapcraftLogicError( 'part name missing {}'.format(dep)) def _sort_parts(self): '''Performs an inneficient but easy to follow sorting of parts.''' sorted_parts = [] while self.all_parts: top_part = None for part in self.all_parts: mentioned = False for other in self.all_parts: if part in other.deps: mentioned = True break if not mentioned: top_part = part break if not top_part: raise SnapcraftLogicError( 'circular dependency chain found in parts definition') sorted_parts = [top_part] + sorted_parts self.all_parts.remove(top_part) return sorted_parts def part_prereqs(self, part_name): """Returns a set with all of part_names' prerequisites.""" return set(self.after_requests.get(part_name, [])) def part_dependents(self, part_name): """Returns a set of all the parts that depend upon part_name.""" dependents = set() for part, prerequisites in self.after_requests.items(): if part_name in prerequisites: dependents.add(part) return dependents def get_part(self, part_name): for part in self.all_parts: if part.name == part_name: return part return None def get_project_state(self, step): """Returns a dict of states for the given step of each part.""" state = {} for part in self.all_parts: state[part.name] = part.get_state(step) return state def validate_parts(self, part_names): for part_name in part_names: if part_name not in self._part_names: raise EnvironmentError( 'The part named {!r} is not defined in ' '\'snapcraft.yaml\''.format(part_name)) def load_plugin(self, part_name, plugin_name, properties): part = pluginhandler.load_plugin( part_name, plugin_name, properties, self._project_options, self._validator.part_schema) self.build_tools += part.code.build_packages self.build_tools += sources.get_required_packages(part.code.options) self.all_parts.append(part) return part def build_env_for_part(self, part, root_part=True): """Return a build env of all the part's dependencies.""" env = [] stagedir = self._project_options.stage_dir if root_part: # this has to come before any {}/usr/bin env += _create_pkg_config_override( part.bindir, part.installdir, stagedir, self._project_options.arch_triplet) env += part.env(part.installdir) env += _runtime_env(part.installdir, self._project_options.arch_triplet) env += _runtime_env(stagedir, self._project_options.arch_triplet) env += _build_env(part.installdir, self._project_options.arch_triplet) env += _build_env_for_stage(stagedir, self._project_options.arch_triplet) else: env += part.env(stagedir) env += _runtime_env(stagedir, self._project_options.arch_triplet) for dep_part in part.deps: env += dep_part.env(stagedir) env += self.build_env_for_part(dep_part, root_part=False) return env def stage_env(self): stage_dir = self._project_options.stage_dir env = [] env += _runtime_env(stage_dir, self._project_options.arch_triplet) env += _build_env_for_stage(stage_dir, self._project_options.arch_triplet) for part in self.all_parts: env += part.env(stage_dir) return env def snap_env(self): snap_dir = self._project_options.snap_dir env = [] env += _runtime_env(snap_dir, self._project_options.arch_triplet) dependency_paths = set() for part in self.all_parts: env += part.env(snap_dir) dependency_paths |= part.get_primed_dependency_paths() # Dependency paths are only valid if they actually exist. Sorting them # here as well so the LD_LIBRARY_PATH is consistent between runs. dependency_paths = sorted({ path for path in dependency_paths if os.path.isdir(path)}) if dependency_paths: # Add more specific LD_LIBRARY_PATH from the dependencies. env.append('LD_LIBRARY_PATH="' + ':'.join(dependency_paths) + ':$LD_LIBRARY_PATH"') return env
class Config: @property def part_names(self): return self.parts.part_names @property def all_parts(self): return self.parts.all_parts @property def _remote_parts(self): if getattr(self, '_remote_parts_attr', None) is None: self._remote_parts_attr = get_remote_parts() return self._remote_parts_attr def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self._project_options = project_options self._snapcraft_yaml = get_snapcraft_yaml() snapcraft_yaml = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(snapcraft_yaml) self._validator.validate() snapcraft_yaml = self._process_remote_parts(snapcraft_yaml) snapcraft_yaml = self._expand_filesets(snapcraft_yaml) self.data = self._expand_env(snapcraft_yaml) self._ensure_no_duplicate_app_aliases() # both confinement type and build quality are optionals _ensure_confinement_default(self.data, self._validator.schema) _ensure_grade_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self.parts = parts.PartsConfig(self.data, self._project_options, self._validator, self.build_tools, self._snapcraft_yaml) if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch] def get_metadata(self): return { 'name': self.data['name'], 'version': self.data['version'], 'arch': self.data['architectures'] } def _ensure_no_duplicate_app_aliases(self): # Prevent multiple apps within a snap from having duplicate alias names aliases = [] for app_name, app in self.data.get('apps', {}).items(): aliases.extend(app.get('aliases', [])) seen = set() duplicates = set() for alias in aliases: if alias in seen: duplicates.add(alias) else: seen.add(alias) if duplicates: raise errors.DuplicateAliasError(aliases=duplicates) def get_project_state(self, step): """Returns a dict of states for the given step of each part.""" state = {} for part in self.parts.all_parts: state[part.name] = states.get_state(part.statedir, step) return state def stage_env(self): stage_dir = self._project_options.stage_dir core_dynamic_linker = self._project_options.get_core_dynamic_linker() env = [] env += _runtime_env(stage_dir, self._project_options.arch_triplet) env += _build_env_for_stage(stage_dir, self.data['name'], self.data['confinement'], self._project_options.arch_triplet, core_dynamic_linker=core_dynamic_linker) for part in self.parts.all_parts: env += part.env(stage_dir) return env def snap_env(self): snap_dir = self._project_options.snap_dir env = [] env += _runtime_env(snap_dir, self._project_options.arch_triplet) dependency_paths = set() for part in self.parts.all_parts: env += part.env(snap_dir) dependency_paths |= part.get_primed_dependency_paths() # Dependency paths are only valid if they actually exist. Sorting them # here as well so the LD_LIBRARY_PATH is consistent between runs. dependency_paths = sorted( {path for path in dependency_paths if os.path.isdir(path)}) if dependency_paths: # Add more specific LD_LIBRARY_PATH from the dependencies. env.append('LD_LIBRARY_PATH="' + ':'.join(dependency_paths) + ':$LD_LIBRARY_PATH"') return env def project_env(self): return [ 'SNAPCRAFT_STAGE={}'.format(self._project_options.stage_dir), 'SNAPCRAFT_PROJECT_NAME={}'.format(self.data['name']), 'SNAPCRAFT_PROJECT_VERSION={}'.format(self.data['version']), ] def _expand_env(self, snapcraft_yaml): environment_keys = ['name', 'version'] for key in snapcraft_yaml: if any((key == env_key for env_key in environment_keys)): continue snapcraft_yaml[key] = replace_attr(snapcraft_yaml[key], [ ('$SNAPCRAFT_PROJECT_NAME', snapcraft_yaml['name']), ('$SNAPCRAFT_PROJECT_VERSION', snapcraft_yaml['version']), ('$SNAPCRAFT_STAGE', self._project_options.stage_dir), ]) return snapcraft_yaml def _expand_filesets(self, snapcraft_yaml): parts = snapcraft_yaml.get('parts', {}) for part_name in parts: # FIXME: Remove `snap` from here; it's deprecated for step in ('stage', 'snap', 'prime'): step_fileset = _expand_filesets_for(step, parts[part_name]) parts[part_name][step] = step_fileset return snapcraft_yaml def _process_remote_parts(self, snapcraft_yaml): parts = snapcraft_yaml.get('parts', {}) new_parts = {} for part_name in parts: if 'plugin' not in parts[part_name]: properties = self._remote_parts.compose( part_name, parts[part_name]) new_parts[part_name] = properties else: new_parts[part_name] = parts[part_name].copy() after_parts = parts[part_name].get('after', []) after_remote_parts = [p for p in after_parts if p not in parts] for after_part in after_remote_parts: properties = self._remote_parts.get_part(after_part) new_parts[after_part] = properties snapcraft_yaml['parts'] = new_parts return snapcraft_yaml
class Config: @property def part_names(self): return self.parts.part_names @property def all_parts(self): return self.parts.all_parts def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self._project_options = project_options self._snapcraft_yaml = _get_snapcraft_yaml() snapcraft_yaml = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(snapcraft_yaml) self._validator.validate() self.data = self._expand_env(snapcraft_yaml) # both confinement type and build quality are optionals _ensure_confinement_default(self.data, self._validator.schema) _ensure_grade_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self.parts = parts.PartsConfig(self.data.get('parts', {}), self._project_options, self._validator, self.build_tools, self._snapcraft_yaml) if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch] def get_project_state(self, step): """Returns a dict of states for the given step of each part.""" state = {} for part in self.parts.all_parts: state[part.name] = part.get_state(step) return state def stage_env(self): stage_dir = self._project_options.stage_dir env = [] env += _runtime_env(stage_dir, self._project_options.arch_triplet) env += _build_env_for_stage(stage_dir, self._project_options.arch_triplet) for part in self.parts.all_parts: env += part.env(stage_dir) return env def snap_env(self): snap_dir = self._project_options.snap_dir env = [] env += _runtime_env(snap_dir, self._project_options.arch_triplet) dependency_paths = set() for part in self.parts.all_parts: env += part.env(snap_dir) dependency_paths |= part.get_primed_dependency_paths() # Dependency paths are only valid if they actually exist. Sorting them # here as well so the LD_LIBRARY_PATH is consistent between runs. dependency_paths = sorted({ path for path in dependency_paths if os.path.isdir(path)}) if dependency_paths: # Add more specific LD_LIBRARY_PATH from the dependencies. env.append('LD_LIBRARY_PATH="' + ':'.join(dependency_paths) + ':$LD_LIBRARY_PATH"') return env def project_env(self): return [ 'SNAPCRAFT_STAGE={}'.format(self._project_options.stage_dir), 'SNAPCRAFT_PROJECT_NAME={}'.format(self.data['name']), 'SNAPCRAFT_PROJECT_VERSION={}'.format(self.data['version']), ] def _expand_env(self, snapcraft_yaml): environment_keys = ['name', 'version'] for key in snapcraft_yaml: if any((key == env_key for env_key in environment_keys)): continue snapcraft_yaml[key] = replace_attr( snapcraft_yaml[key], [ ('$SNAPCRAFT_PROJECT_NAME', snapcraft_yaml['name']), ('$SNAPCRAFT_PROJECT_VERSION', snapcraft_yaml['version']), ('$SNAPCRAFT_STAGE', self._project_options.stage_dir), ]) return snapcraft_yaml
class Config: @property def part_names(self): return self._part_names def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self.all_parts = [] self._part_names = [] self._project_options = project_options self.after_requests = {} self.data = _snapcraft_yaml_load() self._validator = Validator(self.data) self._validator.validate() _ensure_confinement_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self._wiki = wiki.Wiki() self._process_parts() def _process_parts(self): for part_name in self.data.get('parts', []): self._part_names.append(part_name) properties = self.data['parts'][part_name] or {} plugin_name = properties.pop('plugin', None) if not plugin_name: logger.info('Searching the wiki to compose part "{}"'.format( part_name)) with contextlib.suppress(KeyError): properties = self._wiki.compose(part_name, properties) plugin_name = properties.pop('plugin', None) # The wiki still supports using 'type' for snapcraft 1.x if 'type' in properties: del properties['type'] if not plugin_name: raise PluginNotDefinedError(part_name) if 'after' in properties: self.after_requests[part_name] = properties.pop('after') properties['stage'] = _expand_filesets_for('stage', properties) properties['snap'] = _expand_filesets_for('snap', properties) if 'filesets' in properties: del properties['filesets'] self.load_plugin(part_name, plugin_name, properties) self._compute_part_dependencies() self.all_parts = self._sort_parts() if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch] def _compute_part_dependencies(self): '''Gather the lists of dependencies and adds to all_parts.''' for part in self.all_parts: dep_names = self.after_requests.get(part.name, []) for dep in dep_names: found = False for i in range(len(self.all_parts)): if dep == self.all_parts[i].name: part.deps.append(self.all_parts[i]) found = True break if not found: wiki_part = self._wiki.get_part(dep) found = True if wiki_part else False if found: plugin_name = wiki_part.pop('plugin') part.deps.append( self.load_plugin(dep, plugin_name, wiki_part)) self._part_names.append(dep) if not found: raise SnapcraftLogicError( 'part name missing {}'.format(dep)) def _sort_parts(self): '''Performs an inneficient but easy to follow sorting of parts.''' sorted_parts = [] while self.all_parts: top_part = None for part in self.all_parts: mentioned = False for other in self.all_parts: if part in other.deps: mentioned = True break if not mentioned: top_part = part break if not top_part: raise SnapcraftLogicError( 'circular dependency chain found in parts definition') sorted_parts = [top_part] + sorted_parts self.all_parts.remove(top_part) return sorted_parts def part_prereqs(self, part_name): """Returns a set with all of part_names' prerequisites.""" return set(self.after_requests.get(part_name, [])) def part_dependents(self, part_name): """Returns a set of all the parts that depend upon part_name.""" dependents = set() for part, prerequisites in self.after_requests.items(): if part_name in prerequisites: dependents.add(part) return dependents def get_part(self, part_name): for part in self.all_parts: if part.name == part_name: return part return None def get_project_state(self, step): """Returns a dict of states for the given step of each part.""" state = {} for part in self.all_parts: state[part.name] = part.get_state(step) return state def validate_parts(self, part_names): for part_name in part_names: if part_name not in self._part_names: raise EnvironmentError('The part named {!r} is not defined in ' '\'snapcraft.yaml\''.format(part_name)) def load_plugin(self, part_name, plugin_name, properties): part = pluginhandler.load_plugin(part_name, plugin_name, properties, self._project_options, self._validator.part_schema) self.build_tools += part.code.build_packages self.build_tools += sources.get_required_packages(part.code.options) self.all_parts.append(part) return part def build_env_for_part(self, part, root_part=True): """Return a build env of all the part's dependencies.""" env = [] stagedir = self._project_options.stage_dir if root_part: # this has to come before any {}/usr/bin env += _create_pkg_config_override( part.bindir, part.installdir, stagedir, self._project_options.arch_triplet) env += part.env(part.installdir) env += _runtime_env(part.installdir, self._project_options.arch_triplet) env += _runtime_env(stagedir, self._project_options.arch_triplet) env += _build_env(part.installdir, self._project_options.arch_triplet) env += _build_env_for_stage(stagedir, self._project_options.arch_triplet) else: env += part.env(stagedir) env += _runtime_env(stagedir, self._project_options.arch_triplet) for dep_part in part.deps: env += dep_part.env(stagedir) env += self.build_env_for_part(dep_part, root_part=False) return env def stage_env(self): stage_dir = self._project_options.stage_dir env = [] env += _runtime_env(stage_dir, self._project_options.arch_triplet) env += _build_env_for_stage(stage_dir, self._project_options.arch_triplet) for part in self.all_parts: env += part.env(stage_dir) return env def snap_env(self): snap_dir = self._project_options.snap_dir env = [] env += _runtime_env(snap_dir, self._project_options.arch_triplet) dependency_paths = set() for part in self.all_parts: env += part.env(snap_dir) dependency_paths |= part.get_primed_dependency_paths() # Dependency paths are only valid if they actually exist. Sorting them # here as well so the LD_LIBRARY_PATH is consistent between runs. dependency_paths = sorted( {path for path in dependency_paths if os.path.isdir(path)}) if dependency_paths: # Add more specific LD_LIBRARY_PATH from the dependencies. env.append('LD_LIBRARY_PATH="' + ':'.join(dependency_paths) + ':$LD_LIBRARY_PATH"') return env
class Config: @property def part_names(self): return self.parts.part_names @property def all_parts(self): return self.parts.all_parts def __init__(self, project_options=None): if project_options is None: project_options = snapcraft.ProjectOptions() self.build_tools = [] self._project_options = project_options self._snapcraft_yaml = _get_snapcraft_yaml() self.data = _snapcraft_yaml_load(self._snapcraft_yaml) self._validator = Validator(self.data) self._validator.validate() _ensure_confinement_default(self.data, self._validator.schema) self.build_tools = self.data.get('build-packages', []) self.build_tools.extend(project_options.additional_build_packages) self.parts = parts.PartsConfig(self.data.get('parts', {}), self._project_options, self._validator, self.build_tools, self._snapcraft_yaml) if 'architectures' not in self.data: self.data['architectures'] = [self._project_options.deb_arch] def get_project_state(self, step): """Returns a dict of states for the given step of each part.""" state = {} for part in self.parts.all_parts: state[part.name] = part.get_state(step) return state def stage_env(self): stage_dir = self._project_options.stage_dir env = [] env += _runtime_env(stage_dir, self._project_options.arch_triplet) env += _build_env_for_stage(stage_dir, self._project_options.arch_triplet) for part in self.parts.all_parts: env += part.env(stage_dir) return env def snap_env(self): snap_dir = self._project_options.snap_dir env = [] env += _runtime_env(snap_dir, self._project_options.arch_triplet) dependency_paths = set() for part in self.parts.all_parts: env += part.env(snap_dir) dependency_paths |= part.get_primed_dependency_paths() # Dependency paths are only valid if they actually exist. Sorting them # here as well so the LD_LIBRARY_PATH is consistent between runs. dependency_paths = sorted({ path for path in dependency_paths if os.path.isdir(path)}) if dependency_paths: # Add more specific LD_LIBRARY_PATH from the dependencies. env.append('LD_LIBRARY_PATH="' + ':'.join(dependency_paths) + ':$LD_LIBRARY_PATH"') return env