def find_build_dir(dir, **kwargs): '''Heuristic for finding a build directory. The default build directory is computed by reading the build.dir-fmt configuration option, defaulting to DEFAULT_BUILD_DIR if not set. It might be None if the build.dir-fmt configuration option is set but cannot be resolved. If the given argument is truthy, it is returned. Otherwise, if the default build folder is a build directory, it is returned. Next, if the current working directory is a build directory, it is returned. Finally, the default build directory is returned (may be None). ''' if dir: build_dir = dir else: cwd = os.getcwd() default = config.get('build', 'dir-fmt', fallback=DEFAULT_BUILD_DIR) try: default = _resolve_build_dir(default, cwd, **kwargs) log.dbg('config dir-fmt: {}'.format(default), level=log.VERBOSE_EXTREME) except KeyError: default = None if default and is_zephyr_build(default): build_dir = default elif is_zephyr_build(cwd): build_dir = cwd else: build_dir = default log.dbg('build dir: {}'.format(build_dir), level=log.VERBOSE_EXTREME) if build_dir: return os.path.abspath(build_dir) else: return None
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 getConfig(self, name): """Gets a configuration for a command :param self: Self :param name: The name of the configuration to get :return None: Configuration not found :return String: The configurtion's value """ # We'll let them qualify namespaces with ':' in their provided name, # but we need to split off any namespaces and combine with our uber # namespace; and provide the final configuration option name as a # standalone string fields = name.split(".") namespace = Command.ConfigPrefix if len(fields) > 1: namespace += ":{}".format(fields[0]) option = fields[1] else: option = fields[0] return config.get(namespace, option, fallback=None)
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 fetch_strategy(self, args): cfg = config.get('update', 'fetch', fallback=None) if cfg is not None and cfg not in ('always', 'smart'): log.wrn(f'ignoring invalid config update.fetch={cfg}; ' 'choices: always, smart') cfg = None if args.fetch_strategy: return args.fetch_strategy elif cfg: return cfg else: return 'smart'
def load_runners_yaml(path, args): # Load runners.yaml using its location in the CMake cache, # allowing a command line override for the cache file location. try: with open(path, 'r') as f: config = yaml.safe_load(f.read()) except FileNotFoundError: log.die(f'runners.yaml file not found: {path}') if not config.get('runners'): log.wrn(f'no pre-configured runners in {path}; ' "this probably won't work") return config
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 _update_west(rebase, keep_descendants): _banner('self-updating west:') with _error_context(_FAILED_UPDATE_MSG): project = _west_project() old_sha = _sha(project, 'HEAD') _update(project, rebase, keep_descendants) if config.get('zephyr', 'base', fallback=None) is None: for proj in _all_projects(): if proj.path == 'zephyr': update_config('zephyr', 'base', proj.path) break if old_sha != _sha(project, 'HEAD'): _msg(project.format('{name}: updated to {revision} (from {url}).')) # Signal self-update, which will cause a restart. This is a bit # nicer than doing the restart here, as callers will have a # chance to flush file buffers, etc. raise WestUpdated()
def get_build_dir(args, die_if_none=True): # Get the build directory for the given argument list and environment. if args.build_dir: return args.build_dir guess = config.get('build', 'guess-dir', fallback='never') guess = guess == 'runners' dir = find_build_dir(None, guess) if dir and is_zephyr_build(dir): return dir elif die_if_none: msg = '--build-dir was not given, ' if dir: msg = msg + 'and neither {} nor {} are zephyr build directories.' else: msg = msg + ('{} is not a build directory and the default build ' 'directory cannot be determined. Check your ' 'build.dir-fmt configuration option') log.die(msg.format(getcwd(), dir)) else: return None
def do_run(self, args, ignored): if self.topdir: zb = os.environ.get('ZEPHYR_BASE') if zb: msg = textwrap.dedent(''' Note: In your environment, ZEPHYR_BASE is set to: {} This forces west to search for an installation there. Try unsetting ZEPHYR_BASE and re-running this command.'''. format(zb)) else: msg = '' log.die('already initialized in {}, aborting.{}'.format( self.topdir, msg)) if args.local and (args.manifest_url or args.manifest_rev): log.die('-l cannot be combined with -m or --mr') if shutil.which('git') is None: log.die("can't find git; install it or ensure it's on your PATH") # west.manifest will try to read manifest.path and use it when # parsing the manifest. Clear it out for now so we can parse # the manifest without it; local() or bootstrap() will set it # properly. if config.get('manifest', 'path', fallback=None) is not None: config.remove_option('manifest', 'path') if args.local: projects, manifest_dir = self.local(args) else: projects, manifest_dir = self.bootstrap(args) self.fixup_zephyr_base(projects) log.banner('Initialized. Now run "west update" inside {}.'.format( self.topdir))
def do_run(self, args, ignored): if self.topdir: log.die('already in an installation ({}), aborting'. format(self.topdir)) if shutil.which('git') is None: log.die("can't find git; install it or ensure it's on your PATH") # west.manifest will try to read manifest.path and use it when # parsing the manifest. Clear it out for now so we can parse # the manifest without it; local() or bootstrap() will set it # properly. if config.get('manifest', 'path', fallback=None) is not None: config.remove_option('manifest', 'path') if args.local: projects, manifest_dir = self.local(args) else: projects, manifest_dir = self.bootstrap(args) self.fixup_zephyr_base(projects) _banner('Initialized. Now run "west update" inside {}.'. format(self.topdir))
def config_get(option, fallback): return config.get('build', option, fallback=fallback)
def _load(self, data, sections): # Initialize this instance's fields from values given in the # manifest data, which must be validated according to the schema. if 'west' in sections: west = data.get('west', {}) url = west.get('url') or WEST_URL_DEFAULT revision = west.get('revision') or WEST_REV_DEFAULT self.west_project = SpecialProject('west', url=url, revision=revision, path=os.path.join( '.west', 'west')) # Next is the manifest section if 'manifest' not in sections: return projects = [] project_abspaths = set() manifest = data.get('manifest') path = config.get('manifest', 'path', fallback=None) self_tag = manifest.get('self') if path is None: path = self_tag.get('path') if self_tag else '' west_commands = self_tag.get('west-commands') if self_tag else None project = SpecialProject(path, path=path, west_commands=west_commands) projects.insert(MANIFEST_PROJECT_INDEX, project) # Map from each remote's name onto that remote's data in the manifest. remotes = tuple( Remote(r['name'], r['url-base']) for r in manifest['remotes']) remotes_dict = {r.name: r for r in remotes} # Get any defaults out of the manifest. # # md = manifest defaults (dictionary with values parsed from # the manifest) md = manifest.get('defaults', dict()) mdrem = md.get('remote') if mdrem: # The default remote name, if provided, must refer to a # well-defined remote. if mdrem not in remotes_dict: self._malformed( 'default remote {} is not defined'.format(mdrem)) default_remote = remotes_dict[mdrem] default_remote_name = mdrem else: default_remote = None default_remote_name = None defaults = Defaults(remote=default_remote, revision=md.get('revision')) # mp = manifest project (dictionary with values parsed from # the manifest) for mp in manifest['projects']: # Validate the project name. name = mp['name'] if name == 'west': self._malformed('the name "west" is reserved and cannot ' 'be used to name a manifest project') # Validate the project remote. remote_name = mp.get('remote', default_remote_name) if remote_name is None: self._malformed( 'project {} does not specify a remote'.format(name)) if remote_name not in remotes_dict: self._malformed('project {} remote {} is not defined'.format( name, remote_name)) # Create the project instance for final checking. project = Project(name, remotes_dict[remote_name], defaults, path=mp.get('path'), clone_depth=mp.get('clone-depth'), revision=mp.get('revision'), west_commands=mp.get('west-commands')) # Two projects cannot have the same path. We use absolute # paths to check for collisions to ensure paths are # normalized (e.g. for case-insensitive file systems or # in cases like on Windows where / or \ may serve as a # path component separator). if project.abspath in project_abspaths: self._malformed('project {} path {} is already in use'.format( project.name, project.path)) project_abspaths.add(project.abspath) projects.append(project) self.defaults = defaults self.remotes = remotes self._remotes_dict = remotes_dict self.projects = tuple(projects)
def _load(self, data): # Initialize this instance's fields from values given in the # manifest data, which must be validated according to the schema. projects = [] project_names = set() project_abspaths = set() manifest = data.get('manifest') path = config.get('manifest', 'path', fallback=None) self_tag = manifest.get('self') if path is None: path = self_tag.get('path') if self_tag else '' # Both are named "self.path" depending on where you look at. if path and self.path: realpath = os.path.dirname(self.path) realdir = os.path.basename(realpath) if realdir not in [os.path.basename(path), 'manifest-tmp']: raise MalformedManifest("""Manifest self.path is '{}' \ but located in directory '{}'""".format(path, realpath)) west_commands = self_tag.get('west-commands') if self_tag else None project = ManifestProject(path=path, west_commands=west_commands) projects.insert(MANIFEST_PROJECT_INDEX, project) # Map from each remote's name onto that remote's data in the manifest. remotes = tuple( Remote(r['name'], r['url-base']) for r in manifest.get('remotes', [])) remotes_dict = {r.name: r for r in remotes} # Get any defaults out of the manifest. # # md = manifest defaults (dictionary with values parsed from # the manifest) md = manifest.get('defaults', dict()) mdrem = md.get('remote') if mdrem: # The default remote name, if provided, must refer to a # well-defined remote. if mdrem not in remotes_dict: self._malformed( 'default remote {} is not defined'.format(mdrem)) default_remote = remotes_dict[mdrem] default_remote_name = mdrem else: default_remote = None default_remote_name = None defaults = Defaults(remote=default_remote, revision=md.get('revision')) # mp = manifest project (dictionary with values parsed from # the manifest) for mp in manifest['projects']: # Validate the project name. name = mp['name'] # Validate the project remote or URL. remote_name = mp.get('remote', default_remote_name) url = mp.get('url') if remote_name is None and url is None: self._malformed( 'project {} does not specify a remote or URL'.format(name)) if remote_name: if remote_name not in remotes_dict: self._malformed( 'project {} remote {} is not defined'.format( name, remote_name)) remote = remotes_dict[remote_name] else: remote = None # Create the project instance for final checking. try: project = Project(name, defaults, path=mp.get('path'), clone_depth=mp.get('clone-depth'), revision=mp.get('revision'), west_commands=mp.get('west-commands'), remote=remote, url=url) except ValueError as ve: self._malformed(ve.args[0]) # Project names must be unique. if project.name in project_names: self._malformed('project name {} is already used'.format( project.name)) # Two projects cannot have the same path. We use absolute # paths to check for collisions to ensure paths are # normalized (e.g. for case-insensitive file systems or # in cases like on Windows where / or \ may serve as a # path component separator). if project.abspath in project_abspaths: self._malformed('project {} path {} is already in use'.format( project.name, project.path)) project_names.add(project.name) project_abspaths.add(project.abspath) projects.append(project) self.defaults = defaults self.remotes = remotes self._remotes_dict = remotes_dict self.projects = tuple(projects)
def do_run(self, args, remainder): self.args = args # Avoid having to pass them around log.dbg('args: {} remainder: {}'.format(args, remainder, level=log.VERBOSE_EXTREME)) # Store legacy -s option locally source_dir = self.args.source_dir self._parse_remainder(remainder) if source_dir: if self.args.source_dir: log.die("source directory specified twice:({} and {})".format( source_dir, self.args.source_dir)) self.args.source_dir = source_dir log.dbg('source_dir: {} cmake_opts: {}'.format(self.args.source_dir, self.args.cmake_opts)) self._sanity_precheck() self._setup_build_dir() if args.pristine is not None: pristine = args.pristine else: # Load the pristine={auto, always, never} configuration value pristine = config.get('build', 'pristine', fallback='never') if pristine not in ['auto', 'always', 'never']: log.wrn('treating unknown build.pristine value "{}" as "never"'. format(pristine)) pristine = 'never' self.auto_pristine = (pristine == 'auto') log.dbg('pristine: {} auto_pristine: {}'.format(pristine, self.auto_pristine)) if is_zephyr_build(self.build_dir): if pristine == 'always': log.inf('Making build dir {} pristine'.format(self.build_dir)) self._run_build('pristine') self.run_cmake = True else: self._update_cache() if self.args.cmake or self.args.cmake_opts: self.run_cmake = True else: self.run_cmake = True self._setup_source_dir() self._sanity_check() log.inf('source directory: {}'.format(self.source_dir), colorize=True) log.inf('build directory: {}{}'. format(self.build_dir, (' (created)' if self.created_build_dir else '')), colorize=True) if self.cmake_cache: board = self.cmake_cache.get('CACHED_BOARD') elif self.args.board: board = self.args.board else: board = 'UNKNOWN' # shouldn't happen log.inf('BOARD:', board, colorize=True) self._run_cmake(self.args.cmake_opts) self._sanity_check() self._update_cache() self._run_build(args.target)