def do_run(self, args, user_args): # manifest.path is not supposed to be set during init, thus clear it # for the session and update it to correct location when complete. if config.get('manifest', 'path', fallback=None) is not None: config.remove_option('manifest', 'path') manifest_file = os.path.join(args.local or args.cache, 'west.yml') projects = Manifest.from_file(manifest_file).projects manifest_project = projects[MANIFEST_PROJECT_INDEX] if args.local is not None: rel_manifest = os.path.relpath(args.local, util.west_topdir()) update_config('manifest', 'path', rel_manifest) else: if manifest_project.path == '': url_path = urlparse(args.manifest_url).path manifest_project.path = posixpath.basename(url_path) manifest_project.abspath = os.path.realpath( os.path.join(util.west_topdir(), manifest_project.path)) manifest_project.name = manifest_project.path shutil.move(args.cache, manifest_project.abspath) update_config('manifest', 'path', manifest_project.path) for project in projects: if project.path == 'zephyr': update_config('zephyr', 'base', project.path)
def run(self, argv): # Run the command-line application with argument list 'argv'. # See if we're in a workspace. It's fine if we're not. # Note that this falls back on searching from ZEPHYR_BASE # if the current directory isn't inside a west workspace. try: self.topdir = west_topdir() except WestNotFound: pass # Read the configuration files. We need this to get # manifest.path to parse the manifest, etc. # # TODO: re-work to avoid global state (#149). config.read_config(topdir=self.topdir) # Set self.manifest and self.extensions. self.load_manifest() self.load_extension_specs() # Set up initial argument parsers. This requires knowing # self.extensions, so it can't happen before now. self.setup_parsers() # OK, we are all set. Run the command. self.run_command(argv)
def __init__(self, name, defaults=None, path=None, clone_depth=None, revision=None, west_commands=None, remote=None, url=None): '''Specify a Project by name, Remote, and optional information. :param name: Project's user-defined name in the manifest. :param defaults: If the revision parameter is not given, the project's revision is set to defaults.revision if defaults is not None, or the west-wide default otherwise. :param path: Relative path to the project in the west installation, if present in the manifest. If not given, the project's ``name`` is used. :param clone_depth: Nonnegative integer clone depth if present in the manifest. :param revision: Project revision as given in the manifest, if present. If not given, defaults.revision is used instead. :param west_commands: path to a YAML file in the project containing a description of west extension commands provided by the project, if given. :param remote: Remote instance corresponding to this Project as specified in the manifest. This is used to build the project's URL, and is also stored as an attribute. :param url: The project's fetch URL. This cannot be given with `remote` as well: choose one. ''' if remote and url: raise ValueError('got remote={} and url={}'.format(remote, url)) if not (remote or url): raise ValueError('got neither a remote nor a URL') if defaults is None: defaults = _DEFAULTS self.name = name '''Project name as it appears in the manifest.''' self.url = url or (remote.url_base + '/' + name) '''Complete fetch URL for the project, either as given by the url kwarg or computed from the remote URL base and the project name.''' self.path = os.path.normpath(path or name) '''Relative path to the project in the installation.''' self.abspath = os.path.realpath( os.path.join(util.west_topdir(), self.path)) '''Absolute path to the project.''' self.posixpath = PurePath(self.abspath).as_posix() '''Absolute path to the project, POSIX style (with forward slashes).''' self.clone_depth = clone_depth '''Project's clone depth, or None''' self.revision = revision or defaults.revision '''Revision to check out for this project, as given in the manifest, from manifest defaults, or from the default supplied by west.''' self.west_commands = west_commands '''Path to project's "west-commands", or None.''' self.remote = remote '''`Remote` instance corresponding to the project's remote, or None.'''
def __init__(self, name, path=None, revision='(not set)', url='(not set)', west_commands=None): '''Specify a Special Project by name, and url, and optional information. :param name: Special Project's user-defined name in the manifest :param path: Relative path to the project in the west installation, if present in the manifest. If None, the project's ``name`` is used. :param revision: Project revision as given in the manifest, if present. :param url: Complete URL for special project. :param west_commands: path to a YAML file in the project containing a description of external west commands provided by the project, if given. This obviously only makes sense for the manifest project, not west. ''' if name == 'west' and west_commands: raise ValueError('setting west_commands on west is forbidden') self.name = name self.url = url self.path = path or name self.abspath = os.path.realpath( os.path.join(util.west_topdir(), self.path)) self.posixpath = PurePath(self.abspath).as_posix() self.revision = revision self.remote = None self.clone_depth = None self.west_commands = west_commands
def _clone(project): log.small_banner(f'{project.name}: cloning and initializing') project.git(f'init {project.abspath}', cwd=util.west_topdir()) # This remote is added as a convenience for the user. # However, west always fetches project data by URL, not remote name. # The user is therefore free to change the URL of this remote. project.git(f'remote add -- {project.remote_name} {project.url}')
def __init__(self, name, remote, defaults, path=None, clone_depth=None, revision=None): '''Specify a Project by name, Remote, and optional information. :param name: Project's user-defined name in the manifest :param remote: Remote instance corresponding to this Project's remote. This may not be None. :param path: Relative path to the project in the west installation, if present in the manifest. If None, the project's ``name`` is used. :param revision: Project revision as given in the manifest, if present. ''' if remote is None: raise ValueError('remote may not be None') _wrn_if_not_remote(remote) self.name = name self.remote = remote self.url = remote.url + '/' + name self.path = path or name self.abspath = os.path.normpath( os.path.join(util.west_topdir(), self.path)) self.clone_depth = clone_depth self.revision = revision or defaults.revision
def __init__(self, name, remote, defaults, path=None, clone_depth=None, revision=None): '''Specify a Project by name, Remote, and optional information. :param name: Project's user-defined name in the manifest. :param remote: Remote instance corresponding to this Project as specified in the manifest. This is used to build the project's URL, and is also stored as an attribute. :param defaults: If the revision parameter is not given, the project's revision is set to defaults.revision. :param path: Relative path to the project in the west installation, if present in the manifest. If not given, the project's ``name`` is used. :param clone_depth: Nonnegative integer clone depth if present in the manifest. :param revision: Project revision as given in the manifest, if present. If not given, defaults.revision is used instead. ''' _wrn_if_not_remote(remote) self.name = name self.remote = remote self.url = remote.url_base + '/' + name self.path = os.path.normpath(path or name) self.abspath = os.path.realpath(os.path.join(util.west_topdir(), self.path)) self.clone_depth = clone_depth self.revision = revision or defaults.revision
def generate_input(data: Data): '''Generate input files from list of files/globs from command line and/or a text file.''' full_set = set() if args.input_files is not None: cwd = Path('.').resolve() for globs in args.input_files: joiner = '", "' data.inputs.append(f'Files: "{joiner.join(globs)}" (relative to "{cwd}")') r = resolve_globs(cwd, globs) full_set.update(r) if args.input_list_file is not None: for file in args.input_list_file: file_path = Path(file).resolve() data.inputs.append(f'A list of files read from: "{file_path}"') globs = list() try: with open(file_path, 'r') as fd: for line in fd: line = line.strip() if line == '' or line[0] == '#': continue globs.append(line) except Exception as e: raise SbomException(f'Cannot read from file "{file_path}": {e}') from e r = resolve_globs(file_path.parent, globs) full_set.update(r) for file_path in full_set: file = FileInfo() file.file_path = file_path file.file_rel_path = os.path.relpath(file_path, util.west_topdir()) data.files.append(file)
def _clone(project): log.small_banner(project.format('{name}: cloning and initializing')) project.git('init {abspath}', cwd=util.west_topdir()) # The "origin" remote is only added for the user's convenience. We # always fetch directly from the URL specified in the manifest. # Later changes to the manifest won't change this remote, # unfortunately -- the user will have to fix that themselves. project.git('remote add -- origin {url}')
def bootstrap(self, args): manifest_url = args.manifest_url or MANIFEST_URL_DEFAULT manifest_rev = args.manifest_rev or MANIFEST_REV_DEFAULT topdir = util.canon_path(args.directory or os.getcwd()) west_dir = join(topdir, WEST_DIR) try: already = util.west_topdir(topdir, fall_back=False) self.die_already(already) except util.WestNotFound: pass log.banner('Initializing in', topdir) if not isdir(topdir): self.create(topdir, exist_ok=False) # Clone the manifest repository into a temporary directory. tempdir = join(west_dir, 'manifest-tmp') if exists(tempdir): log.dbg('removing existing temporary manifest directory', tempdir) shutil.rmtree(tempdir) try: self.clone_manifest(manifest_url, manifest_rev, tempdir) except subprocess.CalledProcessError: shutil.rmtree(tempdir, ignore_errors=True) raise # Verify the manifest file exists. temp_manifest = join(tempdir, 'west.yml') if not exists(temp_manifest): log.die(f'can\'t init: no "west.yml" found in {tempdir}\n' f' Hint: check --manifest-url={manifest_url} and ' '--manifest-rev={manifest_rev}\n' f' You may need to remove {west_dir} before retrying.') # Parse the manifest to get the manifest path, if it declares one. # Otherwise, use the URL. Ignore imports -- all we really # want to know is if there's a "self: path:" or not. projects = Manifest.from_file(temp_manifest, import_flags=ImportFlag.IGNORE, topdir=topdir).projects manifest_project = projects[MANIFEST_PROJECT_INDEX] if manifest_project.path: manifest_path = manifest_project.path else: manifest_path = posixpath.basename(urlparse(manifest_url).path) manifest_abspath = join(topdir, manifest_path) log.dbg('moving', tempdir, 'to', manifest_abspath, level=log.VERBOSE_EXTREME) try: shutil.move(tempdir, manifest_abspath) except shutil.Error as e: log.die(e) log.small_banner('setting manifest.path to', manifest_path) update_config('manifest', 'path', manifest_path, topdir=topdir) return topdir
def main(argv=None): # Makes ANSI color escapes work on Windows, and strips them when # stdout/stderr isn't a terminal colorama.init() # See if we're in an installation. try: topdir = west_topdir() except WestNotFound: topdir = None # Read the configuration files before looking for extensions. # We need this to find the manifest path in order to load extensions. config.read_config() # Load any extension command specs if we're in an installation. if topdir: try: extensions = get_extension_commands() except (MalformedConfig, FileNotFoundError): extensions = {} else: extensions = {} if argv is None: argv = sys.argv[1:] args, unknown = parse_args(argv, extensions, topdir) for_stack_trace = 'run as "west -v {}" for a stack trace'.format( quote_sh_list(argv)) try: args.handler(args, unknown) except KeyboardInterrupt: sys.exit(0) except CalledProcessError as cpe: log.err('command exited with status {}: {}'.format( cpe.args[0], quote_sh_list(cpe.args[1]))) if args.verbose: traceback.print_exc() else: log.inf(for_stack_trace) sys.exit(cpe.returncode) except ExtensionCommandError as ece: log.err( 'extension command', args.command, 'was improperly defined and could not be run{}'.format( ': ' + ece.hint if ece.hint else '')) if args.verbose: traceback.print_exc() else: log.inf(for_stack_trace) sys.exit(ece.returncode) except CommandContextError as cce: log.err('command', args.command, 'cannot be run in this context:', *cce.args) sys.exit(cce.returncode) except CommandError as ce: sys.exit(ce.returncode)
def __init__(self): super().__init__( 'usfs', 'build usfs tools', None) self.top_dir = util.west_topdir() self.build_dir = os.path.join(self.top_dir, 'build/usfs') self.source_dir = Path(os.path.dirname(os.path.realpath(__file__))).parent.parent
def _git_base(project, cmd, *, extra_args=(), capture_stdout=False, check=True): # Runs a git command in the West top directory. See _git_helper() for # parameter documentation. # # Returns a CompletedProcess instance (see below). return _git_helper(project, cmd, extra_args, util.west_topdir(), capture_stdout, check)
def main(argv=None): # Makes ANSI color escapes work on Windows, and strips them when # stdout/stderr isn't a terminal colorama.init() # See if we're in an installation. try: topdir = west_topdir() except WestNotFound: topdir = None # Read the configuration files before looking for extensions. # We need this to find the manifest path in order to load extensions. config.read_config() # Load any extension command specs if we're in an installation. if topdir: try: extensions = get_extension_commands() except (MalformedConfig, FileNotFoundError): extensions = {} else: extensions = {} if argv is None: argv = sys.argv[1:] args, unknown = parse_args(argv, extensions, topdir) try: args.handler(args, unknown) except KeyboardInterrupt: sys.exit(0) except CalledProcessError as cpe: log.err('command exited with status {}: {}'.format( cpe.returncode, quote_sh_list(cpe.cmd))) if args.verbose: traceback.print_exc() sys.exit(cpe.returncode) except ExtensionCommandError as ece: msg = 'extension command "{}" could not be run{}.'.format( args.command, ': ' + ece.hint if ece.hint else '') if args.verbose: log.err(msg) traceback.print_exc() else: log.err(msg, 'See {} for a traceback.'.format(dump_traceback())) sys.exit(ece.returncode) except CommandContextError as cce: log.err('command', args.command, 'cannot be run in this context:', *cce.args) log.err('see {} for a traceback.'.format(dump_traceback())) sys.exit(cce.returncode) except CommandError as ce: # No need to dump_traceback() here. The command is responsible # for logging its own errors. sys.exit(ce.returncode)
def manifest_path(): '''Return the path to the manifest file. Raises WestNotFound if called from outside of a west working directory.''' try: return os.path.join(util.west_topdir(), config.get('manifest', 'path'), 'west.yml') except (configparser.NoOptionError, configparser.NoSectionError) as e: raise MalformedConfig('missing key: \'{}\' in west config file'.format( e.args[0])) from e
def _clone(project): log.small_banner(f'{project.name}: cloning and initializing') project.git(f'init {project.abspath}', cwd=util.west_topdir()) # The "origin" remote is added to follow the practice that 'origin' # is the remote a Git repository was always cloned from. # # However, west doesn't fetch from this remote: it always forms # a fetch URL from the manifest file and fetches that directly. # # The URL of this remote can thus be changed by the user at will. project.git(f'remote add -- origin {project.url}')
def manifest_path(): '''Return the path to the manifest file. Raises: WestNotFound if called from outside of a west installation, MalformedConfig if the configuration file is missing a manifest.path key, and FileNotFoundError if the manifest.path file doesn't exist.''' ret = os.path.join(util.west_topdir(), _mpath(), 'west.yml') # It's kind of annoying to manually instantiate a FileNotFoundError. # This seems to be the best way. if not os.path.isfile(ret): raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), ret) return ret
def _fetch(project): # Fetches upstream changes for 'project' and updates the 'manifest-rev' # branch to point to the revision specified in the manifest. If the # project's repository does not already exist, it is created first. if not _cloned(project): _msg(project.format('{name}: cloning and initializing')) _git(project, 'init {abspath}', cwd=util.west_topdir()) # This remote is only added for the user's convenience. We always fetch # directly from the URL specified in the manifest. _git(project, 'remote add -- {remote_name} {url}') # Fetch the revision specified in the manifest into the manifest-rev branch msg = "{name}: fetching changes" if project.clone_depth: fetch_cmd = "fetch --depth={clone_depth}" msg += " with --depth {clone_depth}" else: fetch_cmd = "fetch" _msg(project.format(msg)) # This two-step approach avoids a "trying to write non-commit object" error # when the revision is an annotated tag. ^{commit} type peeling isn't # supported for the <src> in a <src>:<dst> refspec, so we have to do it # separately. # # --tags is required to get tags when the remote is specified as an URL. if _is_sha(project.revision): # Don't fetch a SHA directly, as server may restrict from doing so. _git(project, fetch_cmd + ' -f --tags ' '-- {url} refs/heads/*:refs/west/*') _git(project, 'update-ref ' + QUAL_MANIFEST_REV + ' {revision}') else: _git(project, fetch_cmd + ' -f --tags -- {url} {revision}') _git(project, 'update-ref ' + QUAL_MANIFEST_REV + ' FETCH_HEAD^{{commit}}') _git(project, 'lfs fetch {remote_name} FETCH_HEAD^{{commit}}') if not _head_ok(project): # If nothing it checked out (which would usually only happen just after # we initialize the repository), check out 'manifest-rev' in a detached # HEAD state. # # Otherwise, the initial state would have nothing checked out, and HEAD # would point to a non-existent refs/heads/master branch (that would # get created if the user makes an initial commit). That state causes # e.g. 'west rebase' to fail, and might look confusing. # # The --detach flag is strictly redundant here, because the # refs/heads/<branch> form already detaches HEAD, but it avoids a # spammy detached HEAD warning from Git. _git(project, 'checkout --detach ' + QUAL_MANIFEST_REV)
def __init__(self, name, path=None, revision='(not set)', url='(not set)', west_commands=None): '''Specify a Special Project by name, and url, and optional information. :param name: Special Project's user-defined name in the manifest :param path: Relative path to the project in the west installation, if present in the manifest. If None, the project's ``name`` is used. :param revision: Project revision as given in the manifest, if present. :param url: Complete URL for special project. :param west_commands: path to a YAML file in the project containing a description of west extension commands provided by the project, if given. This obviously only makes sense for the manifest project, not west. ''' if name == 'west' and west_commands: raise ValueError('setting west_commands on west is forbidden') self.name = name '''Project name, either "west" or "manifest".''' self.url = url '''Complete fetch URL for the project.''' self.path = path or name '''Relative path to the project in the installation.''' self.abspath = os.path.realpath( os.path.join(util.west_topdir(), self.path)) '''Absolute path to the project.''' self.posixpath = PurePath(self.abspath).as_posix() '''Absolute path to the project, POSIX style (with forward slashes).''' self.revision = revision '''Revision to check out for the west project, as given in the manifest, from manifest defaults, or from the default supplied by west. Undefined for the manifest project.''' self.remote = None '''None, provided for analogy with Project.''' self.clone_depth = None '''None, provided for analogy with Project.''' self.west_commands = west_commands '''Path to project's "west-commands", for the manifest project, or
def __init__(self, name, remote, defaults, path=None, clone_depth=None, revision=None, west_commands=None): '''Specify a Project by name, Remote, and optional information. :param name: Project's user-defined name in the manifest. :param remote: Remote instance corresponding to this Project as specified in the manifest. This is used to build the project's URL, and is also stored as an attribute. :param defaults: If the revision parameter is not given, the project's revision is set to defaults.revision. :param path: Relative path to the project in the west installation, if present in the manifest. If not given, the project's ``name`` is used. :param clone_depth: Nonnegative integer clone depth if present in the manifest. :param revision: Project revision as given in the manifest, if present. If not given, defaults.revision is used instead. :param west_commands: path to a YAML file in the project containing a description of west extension commands provided by the project, if given. ''' _wrn_if_not_remote(remote) self.name = name '''Project name as it appears in the manifest.''' self.remote = remote '''`Remote` instance corresponding to the project's remote.''' self.url = remote.url_base + '/' + name '''Complete fetch URL for the project.''' self.path = os.path.normpath(path or name) '''Relative path to the project in the installation.''' self.abspath = os.path.realpath( os.path.join(util.west_topdir(), self.path)) '''Absolute path to the project.''' self.posixpath = PurePath(self.abspath).as_posix() '''Absolute path to the project, POSIX style (with forward slashes).''' self.clone_depth = clone_depth '''Project's clone depth, or None''' self.revision = revision or defaults.revision '''Revision to check out for this project, as given in the manifest, from manifest defaults, or from the default supplied by west.''' self.west_commands = west_commands '''Path to project's "west-commands", or None.'''
def manifest_path(): '''Return the path to the manifest file. Raises: WestNotFound if called from outside of a west working directory, MalformedConfig if the configuration file is missing a manifest.path key, and FileNotFoundError if the manifest.path file doesn't exist.''' try: ret = os.path.join(util.west_topdir(), config.get('manifest', 'path'), 'west.yml') except (configparser.NoOptionError, configparser.NoSectionError) as e: raise MalformedConfig('no "manifest.path" config option is set') from e # It's kind of annoying to manually instantiate a FileNotFoundError. # This seems to be the best way. if not os.path.isfile(ret): raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), ret) return ret
def __init__(self, name, path=None, revision=None, url=None): '''Specify a Special Project by name, and url, and optional information. :param name: Special Project's user-defined name in the manifest :param path: Relative path to the project in the west installation, if present in the manifest. If None, the project's ``name`` is used. :param revision: Project revision as given in the manifest, if present. :param url: Complete URL for special project. ''' self.name = name self.url = url self.path = path or name self.abspath = os.path.realpath(os.path.join(util.west_topdir(), self.path)) self.revision = revision self.remote = None self.clone_depth = None
def do_run(self, args, user_args): manifest_file = os.path.join(args.local or args.cache, 'west.yml') project = Manifest.from_file(manifest_file)\ .projects[MANIFEST_PROJECT_INDEX] if args.local is not None: rel_manifest = os.path.relpath(args.local, util.west_topdir()) _update_key(config, 'manifest', 'path', rel_manifest) else: if project.path is None: url_path = urlparse(args.manifest_url).path project.path = posixpath.basename(url_path) project.name = project.path _inf(project, 'Creating repository for {name_and_path}') shutil.move(args.cache, project.abspath) _update_key(config, 'manifest', 'path', project.path)
def __init__(self, cmdname, cmddesc, projectdir, builddir): super().__init__(cmdname, cmddesc, None, accepts_unknown_args=True) self.top_dir = util.west_topdir() self.build_dir = os.path.join(self.top_dir, os.path.join('build', builddir)) self.project_dir = os.path.join(self.top_dir, projectdir) self.idf_path = os.path.join(self.top_dir, 'external/esp-idf') self.extra_component_dirs = [ os.path.join(self.top_dir, 'components'), os.path.join(self.top_dir, 'components/usfs/lib'), ] self.sdkconfig_final = os.path.join(self.build_dir, 'sdkconfig') self.sdkconfig_defaults = os.path.join(self.build_dir, 'sdkconfig.defaults') self.sdkconfigs = [ os.path.join(self.project_dir, 'sdkconfig.defaults'), os.path.join(self.top_dir, 'sdkconfig.defaults'), ]
def manifest_path(): '''Absolute path of the manifest file in the current installation. Exceptions raised: - `west.util.WestNotFound` if called from outside of a west installation - `MalformedConfig` if the configuration file has no ``manifest.path`` key - ``FileNotFoundError`` if no ``west.yml`` exists in ``manifest.path`` ''' ret = os.path.join(util.west_topdir(), _mpath(), _WEST_YML) # It's kind of annoying to manually instantiate a FileNotFoundError. # This seems to be the best way. if not os.path.isfile(ret): raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), ret) return ret
def setupDocuments(self): log.dbg("setting up placeholder documents") # set up build document cfgBuild = DocumentConfig() cfgBuild.name = "build" cfgBuild.namespace = self.cfg.namespacePrefix + "/build" cfgBuild.docRefID = "DocumentRef-build" self.docBuild = Document(cfgBuild) # we'll create the build packages in walkTargets() # the DESCRIBES relationship for the build document will be # with the zephyr_final package rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT rd.ownerDocument = self.docBuild rd.otherType = RelationshipDataElementType.TARGETNAME rd.otherTargetName = "zephyr_final" rd.rlnType = "DESCRIBES" # add it to pending relationships queue self.pendingRelationships.append(rd) # set up zephyr document cfgZephyr = DocumentConfig() cfgZephyr.name = "zephyr-sources" cfgZephyr.namespace = self.cfg.namespacePrefix + "/zephyr" cfgZephyr.docRefID = "DocumentRef-zephyr" self.docZephyr = Document(cfgZephyr) # also set up zephyr sources package cfgPackageZephyr = PackageConfig() cfgPackageZephyr.name = "zephyr-sources" cfgPackageZephyr.spdxID = "SPDXRef-zephyr-sources" # relativeBaseDir is Zephyr sources topdir try: cfgPackageZephyr.relativeBaseDir = west_topdir( self.cm.paths_source) except WestNotFound: log.err( f"cannot find west_topdir for CMake Codemodel sources path {self.cm.paths_source}; bailing" ) return False pkgZephyr = Package(cfgPackageZephyr, self.docZephyr) self.docZephyr.pkgs[pkgZephyr.cfg.spdxID] = pkgZephyr # create DESCRIBES relationship data rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT rd.ownerDocument = self.docZephyr rd.otherType = RelationshipDataElementType.PACKAGEID rd.otherPackageID = cfgPackageZephyr.spdxID rd.rlnType = "DESCRIBES" # add it to pending relationships queue self.pendingRelationships.append(rd) # set up app document cfgApp = DocumentConfig() cfgApp.name = "app-sources" cfgApp.namespace = self.cfg.namespacePrefix + "/app" cfgApp.docRefID = "DocumentRef-app" self.docApp = Document(cfgApp) # also set up app sources package cfgPackageApp = PackageConfig() cfgPackageApp.name = "app-sources" cfgPackageApp.spdxID = "SPDXRef-app-sources" # relativeBaseDir is app sources dir cfgPackageApp.relativeBaseDir = self.cm.paths_source pkgApp = Package(cfgPackageApp, self.docApp) self.docApp.pkgs[pkgApp.cfg.spdxID] = pkgApp # create DESCRIBES relationship data rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT rd.ownerDocument = self.docApp rd.otherType = RelationshipDataElementType.PACKAGEID rd.otherPackageID = cfgPackageApp.spdxID rd.rlnType = "DESCRIBES" # add it to pending relationships queue self.pendingRelationships.append(rd) if self.cfg.includeSDK: # set up SDK document cfgSDK = DocumentConfig() cfgSDK.name = "sdk" cfgSDK.namespace = self.cfg.namespacePrefix + "/sdk" cfgSDK.docRefID = "DocumentRef-sdk" self.docSDK = Document(cfgSDK) # also set up zephyr sdk package cfgPackageSDK = PackageConfig() cfgPackageSDK.name = "sdk" cfgPackageSDK.spdxID = "SPDXRef-sdk" # relativeBaseDir is SDK dir cfgPackageSDK.relativeBaseDir = self.sdkPath pkgSDK = Package(cfgPackageSDK, self.docSDK) self.docSDK.pkgs[pkgSDK.cfg.spdxID] = pkgSDK # create DESCRIBES relationship data rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT rd.ownerDocument = self.docSDK rd.otherType = RelationshipDataElementType.PACKAGEID rd.otherPackageID = cfgPackageSDK.spdxID rd.rlnType = "DESCRIBES" # add it to pending relationships queue self.pendingRelationships.append(rd) return True
def from_file(source_file=None, topdir=None): '''Manifest object factory given a source YAML file. Results depend on the parameters given: - If both *source_file* and *topdir* are given, the returned Manifest object is based on the data in *source_file*, rooted at *topdir*. The configuration files are not read in this case. This allows parsing a manifest file "as if" its project hierarchy were rooted at another location in the system. - If neither *source_file* nor *topdir* is given, the file system is searched for *topdir*. That installation's ``manifest.path`` configuration option is used to find *source_file*, ``topdir/<manifest.path>/west.yml``. - If only *source_file* is given, *topdir* is found starting there. The directory containing *source_file* doesn't have to be ``manifest.path`` in this case. - If only *topdir* is given, that installation's ``manifest.path`` is used to find *source_file*. Exceptions raised: - `west.util.WestNotFound` if no *topdir* can be found - `MalformedManifest` if *source_file* contains invalid data - `MalformedConfig` if ``manifest.path`` is needed and can't be read - ``ValueError`` if *topdir* is given but is not a west installation root :param source_file: path to the manifest YAML file :param topdir: west installation top level directory ''' if source_file is None and topdir is None: # neither source_file nor topdir: search the filesystem # for the installation and use its manifest.path. topdir = util.west_topdir() source_file = _west_yml(topdir) return Manifest(source_file=source_file, topdir=topdir) elif source_file is not None and topdir is None: # just source_file: find topdir starting there. # fall_back is the default value -- this is just for emphasis. topdir = util.west_topdir(start=os.path.dirname(source_file), fall_back=True) elif topdir is not None and source_file is None: # just topdir. verify it's a real west installation root. msg = 'topdir {} is not a west installation root'.format(topdir) try: real_topdir = util.west_topdir(start=topdir, fall_back=False) except util.WestNotFound: raise ValueError(msg) if PurePath(topdir) != PurePath(real_topdir): raise ValueError(msg + '; but {} is'.format(real_topdir)) # find west.yml based on manifest.path. source_file = _west_yml(topdir) else: # both source_file and topdir. nothing more to do, but # let's check the invariant. assert source_file assert topdir return Manifest(source_file=source_file, topdir=topdir)
def _clone(project): log.small_banner(project.format('{name}: cloning and initializing')) project.git('init {abspath}', cwd=util.west_topdir()) # This remote is only added for the user's convenience. We always fetch # directly from the URL specified in the manifest. project.git('remote add -- {remote_name} {url}')
def set_zephyr_base(args): '''Ensure ZEPHYR_BASE is set Order of precedence: 1) Value given as command line argument 2) Value from environment setting: ZEPHYR_BASE 3) Value of zephyr.base setting in west config file Order of precedence between 2) and 3) can be changed with the setting zephyr.base-prefer. zephyr.base-prefer takes the values 'env' and 'configfile' If 2) and 3) has different values and zephyr.base-prefer is unset a warning is printed to the user.''' if args.zephyr_base: # The command line --zephyr-base takes precedence over # everything else. zb = os.path.abspath(args.zephyr_base) zb_origin = 'command line' else: # If the user doesn't specify it concretely, then use ZEPHYR_BASE # from the environment or zephyr.base from west.configuration. # # `west init` will configure zephyr.base to the project that has path # 'zephyr'. # # At some point, we need a more flexible way to set environment # variables based on manifest contents, but this is good enough # to get started with and to ask for wider testing. zb_env = os.environ.get('ZEPHYR_BASE') zb_prefer = config.config.get('zephyr', 'base-prefer', fallback=None) zb_config = config.config.get('zephyr', 'base', fallback=None) if zb_config is not None: zb_config = os.path.join(west_topdir(), zb_config) if zb_prefer == 'env' and zb_env is not None: zb = zb_env zb_origin = 'env' elif zb_prefer == 'configfile' and zb_config is not None: zb = zb_config zb_origin = 'configfile' elif zb_env is not None: zb = zb_env zb_origin = 'env' try: different = (zb_config is not None and not os.path.samefile(zb_config, zb_env)) except FileNotFoundError: different = (zb_config is not None and (os.path.normpath(os.path.abspath(zb_config)) != os.path.normpath(os.path.abspath(zb_env)))) if different: # The environment ZEPHYR_BASE takes precedence over the config # setting, but in normal multi-repo operation we shouldn't # expect to need to set ZEPHYR_BASE. # Therefore issue a warning as it might have happened that # zephyr-env.sh/cmd was run in some other zephyr installation, # and the user forgot about that. log.wrn( 'ZEPHYR_BASE={}'.format(zb_env), 'in the calling environment will be used, but was set ' 'to', zb_config, 'in west config.\n To disable this ' 'warning, execute ' '\'west config --global zephyr.base-prefer env\'') elif zb_config is not None: zb = zb_config zb_origin = 'configfile' else: zb = None zb_origin = None # No --zephyr-base, no ZEPHYR_BASE envronment and no zephyr.base # Fallback to loop over projects, to identify if a project has path # 'zephyr' for fallback. try: manifest = Manifest.from_file() for project in manifest.projects: if project.path == 'zephyr': zb = project.abspath zb_origin = 'manifest file {}'.format(manifest.path) break else: log.err('no --zephyr-base given, ZEPHYR_BASE is unset,', 'west config contains no zephyr.base setting,', 'and no manifest project has path "zephyr"') except MalformedConfig as e: log.wrn("Can't set ZEPHYR_BASE:", 'parsing of manifest file failed during command', args.command, ':', *e.args) except WestNotFound: log.wrn("Can't set ZEPHYR_BASE:", 'not currently in a west installation') if zb is not None: os.environ['ZEPHYR_BASE'] = zb log.dbg('ZEPHYR_BASE={} (origin: {})'.format(zb, zb_origin))
def from_file(source_file=None, topdir=None): '''Create and return a new Manifest object given a source YAML file. :param source_file: Path to a YAML file containing the manifest. :param topdir: If given, the returned Manifest has a project hierarchy rooted at this directory. If neither *source_file* nor *topdir* is given, a search is performed in the filesystem for a west installation, which is used as topdir. Its manifest.path configuration option is used to find source_file, ``topdir/<manifest.path>/west.yml``. If only *source_file* is given, the search for the corresponding topdir is done starting from its parent directory. This directory containing *source_file* does NOT have to be manifest.path in this case, allowing parsing of additional manifest files besides the "main" one in an installation. If only *topdir* is given, that directory must be a west installation root, and its manifest.path will be used to find the source file. If both *source_file* and *topdir* are given, the returned Manifest object is based on the data in *source_file*, rooted at *topdir*. The configuration files are not read in this case. This allows parsing a manifest file "as if" its project hierarchy were rooted at another location in the system. Exceptions raised: - `west.util.WestNotFound` if a .west directory is needed but cannot be found. - `MalformedManifest` in case of validation errors. - `MalformedConfig` in case of a missing manifest.path configuration option or otherwise malformed configuration. - `ValueError` if topdir is not a west installation root and needs to be ''' if source_file is None and topdir is None: # neither source_file nor topdir: search the filesystem # for the installation and use its manifest.path. topdir = util.west_topdir() source_file = _west_yml(topdir) return Manifest(source_file=source_file, topdir=topdir) elif source_file is not None and topdir is None: # just source_file: find topdir starting there. # fall_back is the default value -- this is just for emphasis. topdir = util.west_topdir(start=os.path.dirname(source_file), fall_back=True) elif topdir is not None and source_file is None: # just topdir. verify it's a real west installation root. msg = 'topdir {} is not a west installation root'.format(topdir) try: real_topdir = util.west_topdir(start=topdir, fall_back=False) except util.WestNotFound: raise ValueError(msg) if PurePath(topdir) != PurePath(real_topdir): raise ValueError(msg + '; but {} is'.format(real_topdir)) # find west.yml based on manifest.path. source_file = _west_yml(topdir) else: # both source_file and topdir. nothing more to do, but # let's check the invariant. assert source_file assert topdir return Manifest(source_file=source_file, topdir=topdir)