def update_config(section, key, value, configfile=ConfigFile.LOCAL): ''' Sets 'key' to 'value' in the given config 'section', creating the section if it does not exist. The destination file to write is given by 'configfile'. ''' if configfile == ConfigFile.ALL: # Not possible to update ConfigFile.ALL, needs specific conf file here. raise ValueError('invalid configfile: {}'.format(configfile)) if configfile == ConfigFile.LOCAL: filename = os.path.join(west_dir(), configfile.value) else: filename = configfile.value if use_configobj: updater = configobj.ConfigObj(filename) else: updater = configparser.ConfigParser() read_config(configfile, updater) if section not in updater: updater[section] = {} updater[section][key] = value if use_configobj: updater.write() else: with open(filename, 'w') as f: updater.write(f)
def _location(cfg: ConfigFile, topdir: Optional[PathType] = None) -> str: # Making this a function that gets called each time you ask for a # configuration file makes it respect updated environment # variables (such as XDG_CONFIG_HOME, PROGRAMDATA) if they're set # during the program lifetime. # # Its existence is also relied on in the test cases, to ensure # that the WEST_CONFIG_xyz variables are respected and we're not about # to clobber the user's own configuration files. # # Make sure to use pathlib's / operator override to join paths in # any cases which might run on Windows, then call fspath() on the # final result. This lets the standard library do the work of # producing a canonical string name. env = os.environ if cfg == ConfigFile.ALL: raise ValueError('ConfigFile.ALL has no location') elif cfg == ConfigFile.SYSTEM: if 'WEST_CONFIG_SYSTEM' in env: return env['WEST_CONFIG_SYSTEM'] plat = platform.system() if plat == 'Linux': return '/etc/westconfig' elif plat == 'Darwin': return '/usr/local/etc/westconfig' elif plat == 'Windows': return os.path.expandvars('%PROGRAMDATA%\\west\\config') elif 'BSD' in plat: return '/etc/westconfig' elif 'CYGWIN' in plat: # Cygwin can handle windows style paths, so make sure we # return one. We don't want to use os.path.join because # that uses '/' as separator character, and the ProgramData # variable is likely to be something like r'C:\ProgramData'. # # See https://github.com/zephyrproject-rtos/west/issues/300 # for details. pd = PureWindowsPath(os.environ['ProgramData']) return os.fspath(pd / 'west' / 'config') else: raise ValueError('unsupported platform ' + plat) elif cfg == ConfigFile.GLOBAL: if 'WEST_CONFIG_GLOBAL' in env: return env['WEST_CONFIG_GLOBAL'] elif platform.system() == 'Linux' and 'XDG_CONFIG_HOME' in env: return os.path.join(env['XDG_CONFIG_HOME'], 'west', 'config') else: return os.fspath(Path.home() / '.westconfig') elif cfg == ConfigFile.LOCAL: if topdir: return os.fspath(Path(topdir) / '.west' / 'config') elif 'WEST_CONFIG_LOCAL' in env: return env['WEST_CONFIG_LOCAL'] else: # Might raise WestNotFound! return os.fspath(Path(west_dir()) / 'config') else: raise ValueError(f'invalid configuration file {cfg}')
def parse_args(argv): # The prog='west' override avoids the absolute path of the main.py script # showing up when West is run via the wrapper west_parser = argparse.ArgumentParser( prog='west', description='The Zephyr RTOS meta-tool.', epilog='Run "west <command> -h" for help on each command.') # Remember to update scripts/west-completion.bash if you add or remove # flags west_parser.add_argument('-z', '--zephyr-base', default=None, help='''Override the Zephyr base directory. The default is the manifest project with path "zephyr".''') west_parser.add_argument('-v', '--verbose', default=0, action='count', help='''Display verbose output. May be given multiple times to increase verbosity.''') west_parser.add_argument('-V', '--version', action='store_true') subparser_gen = west_parser.add_subparsers(title='commands', dest='command') for command in COMMANDS: parser = command.add_parser(subparser_gen) parser.set_defaults(handler=partial(command_handler, command)) args, unknown = west_parser.parse_known_args(args=argv) if args.version: print_version_info() sys.exit(0) # Set up logging verbosity before doing anything else, so # e.g. verbose messages related to argument handling errors # work properly. log.set_verbosity(args.verbose) if IN_MULTIREPO_INSTALL: set_zephyr_base(args) if 'handler' not in args: log.err('west installation found (in {}), but no command given'.format( west_dir()), fatal=True) west_parser.print_help(file=sys.stderr) sys.exit(1) return args, unknown
def _location(cfg, topdir=None): # Making this a function that gets called each time you ask for a # configuration file makes it respect updated environment # variables (such as XDG_CONFIG_HOME, PROGRAMDATA) if they're set # during the program lifetime. # # Its existence is also relied on in the test cases, to ensure # that the WEST_CONFIG_xyz variables are respected and we're not about # to clobber the user's own configuration files. env = os.environ if cfg == ConfigFile.ALL: raise ValueError('ConfigFile.ALL has no location') elif cfg == ConfigFile.SYSTEM: if 'WEST_CONFIG_SYSTEM' in env: return env['WEST_CONFIG_SYSTEM'] plat = platform.system() if plat == 'Linux': return '/etc/westconfig' elif plat == 'Darwin': return '/usr/local/etc/westconfig' elif plat == 'Windows': return os.path.expandvars('%PROGRAMDATA%\\west\\config') elif 'BSD' in plat: return '/etc/westconfig' elif 'CYGWIN' in plat: # Cygwin can handle windows style paths, so make sure we # return one. We don't want to use os.path.join because # that uses '/' as separator character, and the ProgramData # variable is likely to be something like r'C:\ProgramData'. # # See https://github.com/zephyrproject-rtos/west/issues/300 # for details. pd = pathlib.PureWindowsPath(os.environ['ProgramData']) return str(pd / 'west' / 'config') else: raise ValueError('unsupported platform ' + plat) elif cfg == ConfigFile.GLOBAL: if 'WEST_CONFIG_GLOBAL' in env: return env['WEST_CONFIG_GLOBAL'] elif platform.system() == 'Linux' and 'XDG_CONFIG_HOME' in env: return os.path.join(env['XDG_CONFIG_HOME'], 'west', 'config') else: return canon_path( os.path.join(os.path.expanduser('~'), '.westconfig')) elif cfg == ConfigFile.LOCAL: if topdir: return os.path.join(topdir, '.west', 'config') elif 'WEST_CONFIG_LOCAL' in env: return env['WEST_CONFIG_LOCAL'] else: # Might raise WestNotFound! return os.path.join(west_dir(), 'config') else: raise ValueError('invalid configuration file {}'.format(cfg))
def _update_key(config, section, key, value): ''' Updates 'key' in section 'section' in ConfigParser 'config', creating 'section' if it does not exist and write the file afterwards. If value is None/empty, 'key' is left as-is. ''' if not value: return if section not in config: config[section] = {} config[section][key] = value with open(os.path.join(util.west_dir(), 'config'), 'w') as f: config.write(f)
def _location(cfg, topdir=None): # Making this a function that gets called each time you ask for a # configuration file makes it respect updated environment # variables (such as XDG_CONFIG_HOME, PROGRAMDATA) if they're set # during the program lifetime. # # Its existence is also relied on in the test cases, to ensure # that the WEST_CONFIG_xyz variables are respected and we're not about # to clobber the user's own configuration files. env = os.environ if cfg == ConfigFile.ALL: raise ValueError('ConfigFile.ALL has no location') elif cfg == ConfigFile.SYSTEM: if 'WEST_CONFIG_SYSTEM' in env: return env['WEST_CONFIG_SYSTEM'] plat = platform.system() if plat == 'Linux': return '/etc/westconfig' elif plat == 'Darwin': return '/usr/local/etc/westconfig' elif plat == 'Windows': return os.path.expandvars('%PROGRAMDATA%\\west\\config') elif 'BSD' in plat: return '/etc/westconfig' else: raise ValueError('unsupported platform ' + plat) elif cfg == ConfigFile.GLOBAL: if 'WEST_CONFIG_GLOBAL' in env: return env['WEST_CONFIG_GLOBAL'] elif platform.system() == 'Linux' and 'XDG_CONFIG_HOME' in env: return os.path.join(env['XDG_CONFIG_HOME'], 'west', 'config') else: return canon_path( os.path.join(os.path.expanduser('~'), '.westconfig')) elif cfg == ConfigFile.LOCAL: if topdir: return os.path.join(topdir, '.west', 'config') elif 'WEST_CONFIG_LOCAL' in env: return env['WEST_CONFIG_LOCAL'] else: # Might raise WestNotFound! return os.path.join(west_dir(), 'config') else: raise ValueError('invalid configuration file {}'.format(cfg))
def _location(cfg): # Making this a function that gets called each time you ask for a # configuration file makes it respect updated environment # variables (such as XDG_CONFIG_HOME, PROGRAMDATA) if they're set # during the program lifetime. It also makes it easier to # monkey-patch for testing :). env = os.environ if cfg == ConfigFile.ALL: raise ValueError('ConfigFile.ALL has no location') elif cfg == ConfigFile.SYSTEM: if 'WEST_CONFIG_SYSTEM' in os.environ: return os.environ['WEST_CONFIG_SYSTEM'] plat = platform.system() if plat == 'Linux': return '/etc/westconfig' elif plat == 'Darwin': return '/usr/local/etc/westconfig' elif plat == 'Windows': return os.path.expandvars('%PROGRAMDATA%\\west\\config') elif 'BSD' in plat: return '/etc/westconfig' else: raise ValueError('unsupported platform ' + plat) elif cfg == ConfigFile.GLOBAL: if 'WEST_CONFIG_GLOBAL' in os.environ: return os.environ['WEST_CONFIG_GLOBAL'] elif platform.system() == 'Linux' and 'XDG_CONFIG_HOME' in env: return os.path.join(env['XDG_CONFIG_HOME'], 'west', 'config') else: return canon_path( os.path.join(os.path.expanduser('~'), '.westconfig')) elif cfg == ConfigFile.LOCAL: if 'WEST_CONFIG_LOCAL' in os.environ: return os.environ['WEST_CONFIG_LOCAL'] else: # Might raise WestNotFound! return os.path.join(west_dir(), 'config') else: raise ValueError('invalid configuration file {}'.format(cfg))
def default_path(): '''Return the path to the default manifest in the west directory. Raises WestNotFound if called from outside of a west working directory.''' return os.path.join(util.west_dir(), 'manifest', 'default.yml')
def read_config(): ''' Reads all configuration files, making the configuration values available as a configparser.ConfigParser object in config.config. This object works similarly to a dictionary: config.config['foo']['bar'] gets the value for key 'bar' in section 'foo'. Git conventions for configuration file locations are used. See the FILES section in the git-config(1) man page. The following configuration files are read. System-wide: Linux: /etc/westconfig Mac OS: /usr/local/etc/westconfig Windows: %PROGRAMDATA%\\west\\config User-specific: $XDG_CONFIG_HOME/west/config (on Linux) and ~/.westconfig ($XDG_CONFIG_DIR defaults to ~/.config/ if unset.) Instance-specific: <West base directory>/west/config Configuration values from later configuration files override configuration from earlier ones. Instance-specific configuration values have the highest precedence, and system-wide the lowest. ''' # Gather (potential) configuration file paths # System-wide and user-specific if platform.system() == 'Linux': # Probably wouldn't hurt to check $XDG_CONFIG_HOME (defaults to # ~/.config) on all systems. It's listed in git-config(1). People were # iffy about it as of writing though. files = ['/etc/westconfig', os.path.join(os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), 'west', 'config')] elif platform.system() == 'Darwin': # Mac OS # This was seen on a local machine ($(prefix) = /usr/local) files = ['/usr/local/etc/westconfig'] elif platform.system() == 'Windows': # Seen on a local machine files = [os.path.expandvars('%PROGRAMDATA%\\west\\config')] files.append(os.path.expanduser('~/.westconfig')) # Repository-specific files.append(os.path.join(west_dir(), 'config')) # # Parse all existing configuration files # config.read(files, encoding='utf-8')
def read_config(config_file=ConfigFile.ALL, config=config): '''Reads all configuration files, making the configuration values available as a configparser.ConfigParser object in config.config. This object works similarly to a dictionary: config.config['foo']['bar'] gets the value for key 'bar' in section 'foo'. If config_file is given, then read only that particular file, file can be either 'ConfigFile.LOCAL', 'ConfigFile.GLOBAL', or 'ConfigFile.SYSTEM'. If config object is provided, then configuration values will be copied to there instead of the module global 'config' variable. Git conventions for configuration file locations are used. See the FILES section in the git-config(1) man page. The following configuration files are read. System-wide: - Linux: ``/etc/westconfig`` - macOS: ``/usr/local/etc/westconfig`` - Windows: ``%PROGRAMDATA%\\west\\config`` "Global" or user-wide: - Linux: ``~/.westconfig`` or ``$XDG_CONFIG_HOME/west/config`` - macOS: ``~/.westconfig`` - Windows: ``.westconfig`` in the user's home directory, as determined by os.path.expanduser. Local (per-installation) - Linux, macOS, Windows: ``path/to/installation/.west/config`` Configuration values from later configuration files override configuration from earlier ones. Local values have highest precedence, and system values lowest.''' # Gather (potential) configuration file paths files = [] # System-wide and user-specific if config_file == ConfigFile.ALL or config_file == ConfigFile.SYSTEM: files.append(ConfigFile.SYSTEM.value) if config_file == ConfigFile.ALL and platform.system() == 'Linux': files.append( os.path.join( os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), 'west', 'config')) if config_file == ConfigFile.ALL or config_file == ConfigFile.GLOBAL: files.append(ConfigFile.GLOBAL.value) # Repository-specific if config_file == ConfigFile.ALL or config_file == ConfigFile.LOCAL: files.append(os.path.join(west_dir(), ConfigFile.LOCAL.value)) # # Parse all existing configuration files # config.read(files, encoding='utf-8')