diff options
author | Angelos Evripiotis <angelos.evripiotis@gmail.com> | 2018-11-20 12:12:11 +0000 |
---|---|---|
committer | Angelos Evripiotis <angelos.evripiotis@gmail.com> | 2018-11-20 12:12:11 +0000 |
commit | 8071c00c6fe886ac42b729f5979b2e466a84ce66 (patch) | |
tree | 4ae64f1775a4f82de378bb4d87e85ac025a4cea4 | |
parent | 3f663d82415c17f21a2c6216a317aea4aee1608a (diff) | |
parent | 7ae3a3d2433f0909a6c4d43655b8fff95fb8c318 (diff) | |
download | buildstream-8071c00c6fe886ac42b729f5979b2e466a84ce66.tar.gz |
Merge branch 'aevri/prompt-config' into 'master'
Add 'prompt.*' config options to buildstream.conf
See merge request BuildStream/buildstream!887
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | buildstream/_context.py | 72 | ||||
-rw-r--r-- | buildstream/_frontend/app.py | 7 | ||||
-rw-r--r-- | buildstream/_frontend/cli.py | 4 | ||||
-rw-r--r-- | buildstream/_yaml.py | 1 | ||||
-rw-r--r-- | buildstream/data/userconfig.yaml | 32 |
6 files changed, 108 insertions, 14 deletions
@@ -45,6 +45,12 @@ buildstream 1.3.1 instead of just a specially-formatted build-root with a `root` and `scratch` subdirectory. + o The buildstream.conf file learned new 'prompt.auto-init', + 'prompt.really-workspace-close-remove-dir', and + 'prompt.really-workspace-reset-hard' options. These allow users to suppress + certain confirmation prompts, e.g. double-checking that the user meant to + run the command as typed. + o Due to the element `build tree` being cached in the respective artifact their size in some cases has significantly increased. In *most* cases the build trees are not utilised when building targets, as such by default bst 'pull' & 'build' diff --git a/buildstream/_context.py b/buildstream/_context.py index b39c82b1d..7a47a30d3 100644 --- a/buildstream/_context.py +++ b/buildstream/_context.py @@ -110,6 +110,18 @@ class Context(): # Whether or not to attempt to pull build trees globally self.pull_buildtrees = None + # Boolean, whether to offer to create a project for the user, if we are + # invoked outside of a directory where we can resolve the project. + self.prompt_auto_init = None + + # Boolean, whether we double-check with the user that they meant to + # remove a workspace directory. + self.prompt_workspace_close_remove_dir = None + + # Boolean, whether we double-check with the user that they meant to do + # a hard reset of a workspace, potentially losing changes. + self.prompt_workspace_reset_hard = None + # Whether elements must be rebuilt when their dependencies have changed self._strict_build_plan = None @@ -165,7 +177,7 @@ class Context(): _yaml.node_validate(defaults, [ 'sourcedir', 'builddir', 'artifactdir', 'logdir', 'scheduler', 'artifacts', 'logging', 'projects', - 'cache' + 'cache', 'prompt' ]) for directory in ['sourcedir', 'builddir', 'artifactdir', 'logdir']: @@ -214,12 +226,34 @@ class Context(): 'on-error', 'fetchers', 'builders', 'pushers', 'network-retries' ]) - self.sched_error_action = _yaml.node_get(scheduler, str, 'on-error') + self.sched_error_action = _node_get_option_str( + scheduler, 'on-error', ['continue', 'quit', 'terminate']) self.sched_fetchers = _yaml.node_get(scheduler, int, 'fetchers') self.sched_builders = _yaml.node_get(scheduler, int, 'builders') self.sched_pushers = _yaml.node_get(scheduler, int, 'pushers') self.sched_network_retries = _yaml.node_get(scheduler, int, 'network-retries') + # Load prompt preferences + # + # We convert string options to booleans here, so we can be both user + # and coder-friendly. The string options are worded to match the + # responses the user would give at the cli, for least surprise. The + # booleans are converted here because it's easiest to eyeball that the + # strings are right. + # + prompt = _yaml.node_get( + defaults, Mapping, 'prompt') + _yaml.node_validate(prompt, [ + 'auto-init', 'really-workspace-close-remove-dir', + 'really-workspace-reset-hard', + ]) + self.prompt_auto_init = _node_get_option_str( + prompt, 'auto-init', ['ask', 'no']) == 'ask' + self.prompt_workspace_close_remove_dir = _node_get_option_str( + prompt, 'really-workspace-close-remove-dir', ['ask', 'yes']) == 'ask' + self.prompt_workspace_reset_hard = _node_get_option_str( + prompt, 'really-workspace-reset-hard', ['ask', 'yes']) == 'ask' + # Load per-projects overrides self._project_overrides = _yaml.node_get(defaults, Mapping, 'projects', default_value={}) @@ -230,13 +264,6 @@ class Context(): profile_end(Topics.LOAD_CONTEXT, 'load') - valid_actions = ['continue', 'quit'] - if self.sched_error_action not in valid_actions: - provenance = _yaml.node_get_provenance(scheduler, 'on-error') - raise LoadError(LoadErrorReason.INVALID_DATA, - "{}: on-error should be one of: {}".format( - provenance, ", ".join(valid_actions))) - @property def artifactcache(self): if not self._artifactcache: @@ -589,3 +616,30 @@ class Context(): os.environ['XDG_CONFIG_HOME'] = os.path.expanduser('~/.config') if not os.environ.get('XDG_DATA_HOME'): os.environ['XDG_DATA_HOME'] = os.path.expanduser('~/.local/share') + + +# _node_get_option_str() +# +# Like _yaml.node_get(), but also checks value is one of the allowed option +# strings. Fetches a value from a dictionary node, and makes sure it's one of +# the pre-defined options. +# +# Args: +# node (dict): The dictionary node +# key (str): The key to get a value for in node +# allowed_options (iterable): Only accept these values +# +# Returns: +# The value, if found in 'node'. +# +# Raises: +# LoadError, when the value is not of the expected type, or is not found. +# +def _node_get_option_str(node, key, allowed_options): + result = _yaml.node_get(node, str, key) + if result not in allowed_options: + provenance = _yaml.node_get_provenance(node, key) + raise LoadError(LoadErrorReason.INVALID_DATA, + "{}: {} should be one of: {}".format( + provenance, key, ", ".join(allowed_options))) + return result diff --git a/buildstream/_frontend/app.py b/buildstream/_frontend/app.py index b42b94bc1..4094eec17 100644 --- a/buildstream/_frontend/app.py +++ b/buildstream/_frontend/app.py @@ -222,9 +222,10 @@ class App(): # Let's automatically start a `bst init` session in this case if e.reason == LoadErrorReason.MISSING_PROJECT_CONF and self.interactive: click.echo("A project was not detected in the directory: {}".format(directory), err=True) - click.echo("", err=True) - if click.confirm("Would you like to create a new project here ?"): - self.init_project(None) + if self.context.prompt_auto_init: + click.echo("", err=True) + if click.confirm("Would you like to create a new project here?"): + self.init_project(None) self._error_exit(e, "Error loading project") diff --git a/buildstream/_frontend/cli.py b/buildstream/_frontend/cli.py index 725dc8c1d..92abd96e8 100644 --- a/buildstream/_frontend/cli.py +++ b/buildstream/_frontend/cli.py @@ -772,7 +772,7 @@ def workspace_close(app, remove_dir, all_, elements): if nonexisting: raise AppError("Workspace does not exist", detail="\n".join(nonexisting)) - if app.interactive and remove_dir: + if app.interactive and remove_dir and app.context.prompt_workspace_close_remove_dir: if not click.confirm('This will remove all your changes, are you sure?'): click.echo('Aborting', err=True) sys.exit(-1) @@ -806,7 +806,7 @@ def workspace_reset(app, soft, track_, all_, elements): if all_ and not app.stream.workspace_exists(): raise AppError("No open workspaces to reset") - if app.interactive and not soft: + if app.interactive and not soft and app.context.prompt_workspace_reset_hard: if not click.confirm('This will remove all your changes, are you sure?'): click.echo('Aborting', err=True) sys.exit(-1) diff --git a/buildstream/_yaml.py b/buildstream/_yaml.py index f44572ca5..c8f11bc96 100644 --- a/buildstream/_yaml.py +++ b/buildstream/_yaml.py @@ -351,6 +351,7 @@ _sentinel = object() # expected_type (type): The expected type for the value being searched # key (str): The key to get a value for in node # indices (list of ints): Optionally decend into lists of lists +# default_value: Optionally return this value if the key is not found # # Returns: # The value if found in node, otherwise default_value is returned diff --git a/buildstream/data/userconfig.yaml b/buildstream/data/userconfig.yaml index f540a97f6..dfc18545e 100644 --- a/buildstream/data/userconfig.yaml +++ b/buildstream/data/userconfig.yaml @@ -100,3 +100,35 @@ logging: [%{elapsed}][%{key}][%{element}] %{action} %{message} +# +# Prompt overrides +# +# Here you can suppress 'are you sure?' and other kinds of prompts by supplying +# override values. Note that e.g. 'yes' and 'no' have the same meaning here as +# they do in the actual cli prompt. +# +prompt: + + # Whether to create a project with 'bst init' if we are invoked outside of a + # directory where we can resolve the project. + # + # ask - Prompt the user to choose. + # no - Never create the project. + # + auto-init: ask + + # Whether to really proceed with 'bst workspace close --remove-dir' removing + # a workspace directory, potentially losing changes. + # + # ask - Ask the user if they are sure. + # yes - Always remove, without asking. + # + really-workspace-close-remove-dir: ask + + # Whether to really proceed with 'bst workspace reset' doing a hard reset of + # a workspace, potentially losing changes. + # + # ask - Ask the user if they are sure. + # yes - Always hard reset, without asking. + # + really-workspace-reset-hard: ask |