Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config utilities for describing config files and CLI arguments #17

Merged
merged 13 commits into from
Aug 11, 2014

Conversation

NikolausDemmel
Copy link
Member

  • new module config_utils for a general purpose tool to describe config files, parse
    yaml config files and expose specific arguments to the command line; includes some
    unit tests for the config item types
  • new module config describes xylem's global configuration; includes the logic to
    compute sources and cache folders given command line arguments and config files
  • new module arguments for global command line arguments (moved from utils);
    interacts with config to include and process global config arguments
  • new module yaml_utils contains customization to loading and dumping yaml (moved
    (from utils)
  • --help argument now uses pydoc.pager to display the help in a less-like scrollable
    manner on pty's
  • help output includes new section config arguments, describing the arguments
    that correspond to a config file entry
  • commands have a new hook to add to the config description; some logic common
    to all commands was moved to commands.main
  • context objects like InstallerContext and SourcesContext now take a config
    dictionary as argument, which defaults to the global config singleton if not
    passed explicitly
  • high-level API used by the commands (update, resolve, lookup) is also
    parameterized by an optional config dict argument, which defaults to the
    global config
  • Introduce XylemError as common Exception base class. Having a common
    base class allows users to catch all xylem related exceptions in one handler.

Output of xylem resolve --help:

usage: xylem resolve [--show-trumped] [--all] [--show-priority]
                     [--show-default-installer] [--os name:version]
                     [--os-features "feature1,feature2,..."]
                     [--core-installers "inst1,inst2,..."]
                     [--use-additional-installers yes|no]
                     [--install-from "inst1:[key1,key2,...] ..."]
                     [--installer-options "inst1:{opt1:val1,...}, ..."]
                     [--user-sources yes|no] [--cache-dir PATH]
                     [--sources-dir PATH] [-h] [--version] [-v] [-d]
                     [--print-config] [--no-user-config]
                     [--prefix XYLEM_PREFIX] [--xylem-dir XYLEM_DIR]
                     [xylem_key [xylem_key ...]]

Lookup a xylem key and resolve to unique, parsed rule based on priorities.

positional arguments:
  xylem_key

optional arguments:
  --show-trumped        Show all possible resolutions for key, also for
                        trumped installers.
  --all                 Resolve all keys with resolution for this OS.
  --show-priority       Show priority of installer.
  --show-default-installer
                        Show installer even if it is the default installer.

config arguments:
  The following typed arguments correspond to entries in the config file.
  Command line argument values are interpreted as YAML and override the
  corresponding entries in user/system config files.

  There are some special cases and short hand notation for parsing config
  arguments:
  * List: the outer '[]' can be omitted; multiple occurrences of the same
  command line argument are concatenated
  * MergingDict: the outer '{}' can be omitted; multiple occurrences of the
  same command line argument are merged; value is merged with the config
  file entries
  * Path: string parsed as-is; path is expanded (e.g. `~`)
  * String: string parsed as-is

  --os name:version     override os detection; if no ':' is present, the
                        entire string is interpreted as the os name and the
                        version is detected
                        (config: `os_override`, type: String)
  --os-features "feature1,feature2,..."
                        OS features to be used. The list of possible values
                        and the default choice is defined by the os plugin for
                        the selected OS.
                        (config: `os_options/features`, type: List)
  --core-installers "inst1,inst2,..."
                        core installers to be used. The default list is
                        defined by the OS plugin for the selected OS.
                        Additional installers as defined by installer plugins
                        may be used on top of the core installers unless the
                        `use_additional_installers` option is set to False.
                        (config: `os_options/installers`, type: List)
  --use-additional-installers yes|no
                        if `True`, use additional installers as defined by
                        installer plugins on top of the core installers
                        (type: Boolean, default: True)
  --install-from "inst1:[key1,key2,...] ..."
                        mapping installer names to list of xylem keys;
                        overwrites the installer priority such that the given
                        keys are only ever installed with the specified
                        installer
                        (type: MergingDict)
  --installer-options "inst1:{opt1:val1,...}, ..."
                        options passed to installer plugins; valid options are
                        specific to each installer plugin
                        (type: MergingDict)
  --user-sources yes|no
                        if `True`, look for sources and cache in user
                        directory instead of system-wide locations
                        (type: Boolean, default: False)
  --cache-dir PATH      override the cache location
                        (type: Path)
  --sources-dir PATH    override the sources directory
                        (type: Path)

global arguments:
  By default xylem operates with system-wide configuration of sources and
  cache. The path under which those are found can be set with the
  XYLEM_PREFIX environment variable (or `--prefix` argument). To instead use
  sources and directories in the user's home directory, make use of the
  `--user- sources` argument. An alternative mode of configuration is by
  setting the XYLEM_DIR environment variable (or `--xylem-dir` argument).
  With that, only config files in that directory are used and sources/cache
  folder is local to the XYLEM_DIR. This can be used by third party tools to
  utilize xylem with config/sources/cache in a temporary directory.

  -h, --help            show this help message and exit
  --version             print xylem version and exit
  -v, --verbose         verbose console output
  -d, --debug           enable debug messages (overwrites the XYLEM_DEBUG
                        environment variable)
  --print-config        print the effective configuration (from command line
                        and config files) and exit
  --no-user-config      disable user config (system-wide config only)
  --prefix XYLEM_PREFIX
                        Set the FHS prefix for finding system-wide
                        configurations and caches. System-wide configuration
                        files will be looked for in 'XYLEM_PREFIX/etc/xylem'
                        and cache files will be placed in
                        'XYLEM_PREFIX/var/cache/xylem'. The default prefix is
                        '/'. The prefix can also be set by the XYLEM_PREFIX
                        environment variable, but the command line option
                        takes precedence.
  --xylem-dir XYLEM_DIR
                        Specify the path of directory to use for configuration
                        and caches. Configuration files will be looked for in
                        'XYLEM_DIR' and caches will be placed in
                        'XYLEM_DIR/cache'. This is intended to be used by
                        tools that want to create a local configuration and
                        cache independent from the system-wide setup. If set,
                        only the configuration files in XYLEM_DIR are used
                        instead of system and user configuration files, i.e.
                        XYLEM_PREFIX will be ignored. This can also be set by
                        the XYLEM_DIR environment variable, but the command
                        line option takes precedence.

Given the following config file in ~/.config/xylem/config.yaml,

install_from:
  homebrew: [foo, bar, baz]
installer_options:
  apt:
    repositories: [{sourceline: "foo bar"}]
os_options:
  features: []
os_override: osx
user_sources: yes

the output of two example commands to illustrate the config functionality follows:

$ xylem resolve boost --os "ubuntu:trusty&python3" --install-from "apt: [foo, bar]" --install-from "pip: [quux, quax]" --print-config
cache_dir: /Users/demmeln/.config/xylem/cache
install_from:
  apt: [foo, bar]
  homebrew: [foo, bar, baz]
  pip: [quux, quax]
installer_options:
  apt:
    repositories: [{sourceline: foo bar}]
os_options:
  features: [python3]
  installers:
os_override: [ubuntu, trusty]
sources_dir: /Users/demmeln/.config/xylem/sources.d
use_additional_installers: true
user_sources: true
$ xylem resolve boost --os "ubuntu:trusty&python3" --install-from "apt: [foo, bar]" --install-from "pip: [quux, quax]" --debug --verbose
overriding OS to [ubuntu:trusty]
initializing database with sources dir `/Users/demmeln/.config/xylem/sources.d` and cache dir `/Users/demmeln/.config/xylem/cache/sources`
No configs found in configured source dir '/Users/demmeln/.config/xylem/sources.d', using default sources.
Loading default source urls
boost --> libboost-all-dev

Having a common base class allows users to catch all xylem
related exceptions in one handler.
 - extensive tests for config types
 - tests for other parts of config utils are still TODO
- new module `config` describes the global configuration

- `config` includes the logic to compute soruces and cache folders given command
  line arguments and options

- `arguments` module features help action, which uses pydoc.pager to display the
  help in a `less`-like scrollable manner on pty's

- help output includes new section `config arguments`, describing the arguments
  that correspond to a config file entry

- commands have a new hook to add to the config description; some logic common
  to all commands was moved to `commands.main`

- context objects like `InstallerContext` and `SourcesContext` now take a config
  dictionary as argument, which defaults to the global config sigleton if not
  passed explicitly

- high-level API used by the commands (`update`, `resolve`, `lookup`) is also
  parameterized by an optional config dict argument, which defaults to the
  global config
@NikolausDemmel
Copy link
Member Author

@wjwwood please review.

This has become a bit more extensive than anticipated. More stuff to follow soon.

@wjwwood
Copy link
Member

wjwwood commented Jul 29, 2014

@NikolausDemmel Extensive indeed, I'll do my best to review it tonight.

# add argument groups and some global config-related arguments that
# are independent from the description
group = parser.add_argument_group('global arguments')
add_global_config_arguments(group, "footool")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also use TOOL_NAME?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

@wjwwood
Copy link
Member

wjwwood commented Aug 11, 2014

I'm not sure if this is desired, but I get this when using the --print-config global option:

% xylem --print-config
usage: xylem [--os name:version] [--os-features "feature1,feature2,..."]
             [--core-installers "inst1,inst2,..."]
             [--use-additional-installers yes|no]
             [--install-from "inst1:[key1,key2,...] ..."]
             [--installer-options "inst1:{opt1:val1,...}, ..."]
             [--user-sources yes|no] [--cache-dir PATH] [--sources-dir PATH]
             [-h] [--version] [-v] [-d] [--print-config] [--no-user-config]
             [--prefix XYLEM_PREFIX] [--xylem-dir XYLEM_DIR]
             [resolve | lookup | update] ...
xylem: error: too few arguments

@wjwwood
Copy link
Member

wjwwood commented Aug 11, 2014

When I run xylem resolve with no arguments, nothing happens, I would expect usage for resolve:

% xylem resolve

@wjwwood
Copy link
Member

wjwwood commented Aug 11, 2014

Ok, other than the few small comments this is a +1 from me. Please fixup those things I touched on, merge this, and then rebase the other pull requests.

@NikolausDemmel
Copy link
Member Author

I'm not sure if this is desired, but I get this when using the --print-config global option:

It seems to be a limitation of argparse to not allow optional subparsers. The simplest fix might involve http://stackoverflow.com/a/22054398/1813258.

P.S.: I just stumbled upon http://docopt.org/ (the recorded talk is a nice watch). I seems like a really powerful and simple way to do CLI, but unfortunately it looks to be not as practical when options come from different places.

When I run xylem resolve with no arguments, nothing happens

Will fix.

NikolausDemmel added a commit that referenced this pull request Aug 11, 2014
NikolausDemmel added a commit that referenced this pull request Aug 11, 2014
Config utilities for describing config files and CLI arguments

- new module `config_utils` for a general purpose tool to describe config files, parse 
  yaml config files and expose specific arguments to the command line; includes some
  unit tests for the config item types

- new module `config` describes xylem's global configuration; includes the logic to 
  compute sources and cache folders given command line arguments and config files

- new module `arguments` for global command line arguments (moved from `utils`); 
  interacts with config to include and process global config arguments

- new module `yaml_utils` contains customization to loading and dumping yaml (moved
  (from `utils`)

- `--help` argument now uses pydoc.pager to display the help in a `less`-like scrollable 
  manner on pty's

- help output includes new section `config arguments`, describing the arguments
  that correspond to a config file entry

- commands have a new hook to add to the config description; some logic common
  to all commands was moved to `commands.main`

- context objects like `InstallerContext` and `SourcesContext` now take a config
  dictionary as argument, which defaults to the global config singleton if not
  passed explicitly

- high-level API used by the commands (`update`, `resolve`, `lookup`) is also
  parameterized by an optional config dict argument, which defaults to the
  global config

- Introduce XylemError as common Exception base class. Having a common 
  base class allows users to catch all xylem related exceptions in one handler.
@NikolausDemmel NikolausDemmel merged commit 7bc9791 into master Aug 11, 2014
@NikolausDemmel
Copy link
Member Author

Ok, other than the few small comments this is a +1 from me. Please fixup those things I touched on, merge this, and then rebase the other pull requests.

I addressed the other comments as a new commit 720d3db ontop of the most recent stuff to avoid rebasing so many commits and possibly manually mergin a bunch of times.

Thanks for the comments.

NikolausDemmel added a commit that referenced this pull request Aug 11, 2014
NikolausDemmel added a commit that referenced this pull request Aug 11, 2014
@NikolausDemmel NikolausDemmel deleted the config branch August 11, 2014 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants