Angelos Evripiotis pushed to branch master at BuildStream / buildstream
Commits:
-
b498cce7
by Angelos Evripiotis at 2018-11-20T11:17:38Z
-
eb2d376f
by Angelos Evripiotis at 2018-11-20T11:17:38Z
-
b81c4333
by Angelos Evripiotis at 2018-11-20T11:17:38Z
-
27ca6593
by Angelos Evripiotis at 2018-11-20T11:19:33Z
-
7ae3a3d2
by Angelos Evripiotis at 2018-11-20T11:43:49Z
-
8071c00c
by Angelos Evripiotis at 2018-11-20T12:12:11Z
6 changed files:
- NEWS
- buildstream/_context.py
- buildstream/_frontend/app.py
- buildstream/_frontend/cli.py
- buildstream/_yaml.py
- buildstream/data/userconfig.yaml
Changes:
| ... | ... | @@ -45,6 +45,12 @@ buildstream 1.3.1 |
| 45 | 45 |
instead of just a specially-formatted build-root with a `root` and `scratch`
|
| 46 | 46 |
subdirectory.
|
| 47 | 47 |
|
| 48 |
+ o The buildstream.conf file learned new 'prompt.auto-init',
|
|
| 49 |
+ 'prompt.really-workspace-close-remove-dir', and
|
|
| 50 |
+ 'prompt.really-workspace-reset-hard' options. These allow users to suppress
|
|
| 51 |
+ certain confirmation prompts, e.g. double-checking that the user meant to
|
|
| 52 |
+ run the command as typed.
|
|
| 53 |
+ |
|
| 48 | 54 |
o Due to the element `build tree` being cached in the respective artifact their
|
| 49 | 55 |
size in some cases has significantly increased. In *most* cases the build trees
|
| 50 | 56 |
are not utilised when building targets, as such by default bst 'pull' & 'build'
|
| ... | ... | @@ -110,6 +110,18 @@ class Context(): |
| 110 | 110 |
# Whether or not to attempt to pull build trees globally
|
| 111 | 111 |
self.pull_buildtrees = None
|
| 112 | 112 |
|
| 113 |
+ # Boolean, whether to offer to create a project for the user, if we are
|
|
| 114 |
+ # invoked outside of a directory where we can resolve the project.
|
|
| 115 |
+ self.prompt_auto_init = None
|
|
| 116 |
+ |
|
| 117 |
+ # Boolean, whether we double-check with the user that they meant to
|
|
| 118 |
+ # remove a workspace directory.
|
|
| 119 |
+ self.prompt_workspace_close_remove_dir = None
|
|
| 120 |
+ |
|
| 121 |
+ # Boolean, whether we double-check with the user that they meant to do
|
|
| 122 |
+ # a hard reset of a workspace, potentially losing changes.
|
|
| 123 |
+ self.prompt_workspace_reset_hard = None
|
|
| 124 |
+ |
|
| 113 | 125 |
# Whether elements must be rebuilt when their dependencies have changed
|
| 114 | 126 |
self._strict_build_plan = None
|
| 115 | 127 |
|
| ... | ... | @@ -165,7 +177,7 @@ class Context(): |
| 165 | 177 |
_yaml.node_validate(defaults, [
|
| 166 | 178 |
'sourcedir', 'builddir', 'artifactdir', 'logdir',
|
| 167 | 179 |
'scheduler', 'artifacts', 'logging', 'projects',
|
| 168 |
- 'cache'
|
|
| 180 |
+ 'cache', 'prompt'
|
|
| 169 | 181 |
])
|
| 170 | 182 |
|
| 171 | 183 |
for directory in ['sourcedir', 'builddir', 'artifactdir', 'logdir']:
|
| ... | ... | @@ -214,12 +226,34 @@ class Context(): |
| 214 | 226 |
'on-error', 'fetchers', 'builders',
|
| 215 | 227 |
'pushers', 'network-retries'
|
| 216 | 228 |
])
|
| 217 |
- self.sched_error_action = _yaml.node_get(scheduler, str, 'on-error')
|
|
| 229 |
+ self.sched_error_action = _node_get_option_str(
|
|
| 230 |
+ scheduler, 'on-error', ['continue', 'quit', 'terminate'])
|
|
| 218 | 231 |
self.sched_fetchers = _yaml.node_get(scheduler, int, 'fetchers')
|
| 219 | 232 |
self.sched_builders = _yaml.node_get(scheduler, int, 'builders')
|
| 220 | 233 |
self.sched_pushers = _yaml.node_get(scheduler, int, 'pushers')
|
| 221 | 234 |
self.sched_network_retries = _yaml.node_get(scheduler, int, 'network-retries')
|
| 222 | 235 |
|
| 236 |
+ # Load prompt preferences
|
|
| 237 |
+ #
|
|
| 238 |
+ # We convert string options to booleans here, so we can be both user
|
|
| 239 |
+ # and coder-friendly. The string options are worded to match the
|
|
| 240 |
+ # responses the user would give at the cli, for least surprise. The
|
|
| 241 |
+ # booleans are converted here because it's easiest to eyeball that the
|
|
| 242 |
+ # strings are right.
|
|
| 243 |
+ #
|
|
| 244 |
+ prompt = _yaml.node_get(
|
|
| 245 |
+ defaults, Mapping, 'prompt')
|
|
| 246 |
+ _yaml.node_validate(prompt, [
|
|
| 247 |
+ 'auto-init', 'really-workspace-close-remove-dir',
|
|
| 248 |
+ 'really-workspace-reset-hard',
|
|
| 249 |
+ ])
|
|
| 250 |
+ self.prompt_auto_init = _node_get_option_str(
|
|
| 251 |
+ prompt, 'auto-init', ['ask', 'no']) == 'ask'
|
|
| 252 |
+ self.prompt_workspace_close_remove_dir = _node_get_option_str(
|
|
| 253 |
+ prompt, 'really-workspace-close-remove-dir', ['ask', 'yes']) == 'ask'
|
|
| 254 |
+ self.prompt_workspace_reset_hard = _node_get_option_str(
|
|
| 255 |
+ prompt, 'really-workspace-reset-hard', ['ask', 'yes']) == 'ask'
|
|
| 256 |
+ |
|
| 223 | 257 |
# Load per-projects overrides
|
| 224 | 258 |
self._project_overrides = _yaml.node_get(defaults, Mapping, 'projects', default_value={})
|
| 225 | 259 |
|
| ... | ... | @@ -230,13 +264,6 @@ class Context(): |
| 230 | 264 |
|
| 231 | 265 |
profile_end(Topics.LOAD_CONTEXT, 'load')
|
| 232 | 266 |
|
| 233 |
- valid_actions = ['continue', 'quit']
|
|
| 234 |
- if self.sched_error_action not in valid_actions:
|
|
| 235 |
- provenance = _yaml.node_get_provenance(scheduler, 'on-error')
|
|
| 236 |
- raise LoadError(LoadErrorReason.INVALID_DATA,
|
|
| 237 |
- "{}: on-error should be one of: {}".format(
|
|
| 238 |
- provenance, ", ".join(valid_actions)))
|
|
| 239 |
- |
|
| 240 | 267 |
@property
|
| 241 | 268 |
def artifactcache(self):
|
| 242 | 269 |
if not self._artifactcache:
|
| ... | ... | @@ -589,3 +616,30 @@ class Context(): |
| 589 | 616 |
os.environ['XDG_CONFIG_HOME'] = os.path.expanduser('~/.config')
|
| 590 | 617 |
if not os.environ.get('XDG_DATA_HOME'):
|
| 591 | 618 |
os.environ['XDG_DATA_HOME'] = os.path.expanduser('~/.local/share')
|
| 619 |
+ |
|
| 620 |
+ |
|
| 621 |
+# _node_get_option_str()
|
|
| 622 |
+#
|
|
| 623 |
+# Like _yaml.node_get(), but also checks value is one of the allowed option
|
|
| 624 |
+# strings. Fetches a value from a dictionary node, and makes sure it's one of
|
|
| 625 |
+# the pre-defined options.
|
|
| 626 |
+#
|
|
| 627 |
+# Args:
|
|
| 628 |
+# node (dict): The dictionary node
|
|
| 629 |
+# key (str): The key to get a value for in node
|
|
| 630 |
+# allowed_options (iterable): Only accept these values
|
|
| 631 |
+#
|
|
| 632 |
+# Returns:
|
|
| 633 |
+# The value, if found in 'node'.
|
|
| 634 |
+#
|
|
| 635 |
+# Raises:
|
|
| 636 |
+# LoadError, when the value is not of the expected type, or is not found.
|
|
| 637 |
+#
|
|
| 638 |
+def _node_get_option_str(node, key, allowed_options):
|
|
| 639 |
+ result = _yaml.node_get(node, str, key)
|
|
| 640 |
+ if result not in allowed_options:
|
|
| 641 |
+ provenance = _yaml.node_get_provenance(node, key)
|
|
| 642 |
+ raise LoadError(LoadErrorReason.INVALID_DATA,
|
|
| 643 |
+ "{}: {} should be one of: {}".format(
|
|
| 644 |
+ provenance, key, ", ".join(allowed_options)))
|
|
| 645 |
+ return result
|
| ... | ... | @@ -222,9 +222,10 @@ class App(): |
| 222 | 222 |
# Let's automatically start a `bst init` session in this case
|
| 223 | 223 |
if e.reason == LoadErrorReason.MISSING_PROJECT_CONF and self.interactive:
|
| 224 | 224 |
click.echo("A project was not detected in the directory: {}".format(directory), err=True)
|
| 225 |
- click.echo("", err=True)
|
|
| 226 |
- if click.confirm("Would you like to create a new project here ?"):
|
|
| 227 |
- self.init_project(None)
|
|
| 225 |
+ if self.context.prompt_auto_init:
|
|
| 226 |
+ click.echo("", err=True)
|
|
| 227 |
+ if click.confirm("Would you like to create a new project here?"):
|
|
| 228 |
+ self.init_project(None)
|
|
| 228 | 229 |
|
| 229 | 230 |
self._error_exit(e, "Error loading project")
|
| 230 | 231 |
|
| ... | ... | @@ -772,7 +772,7 @@ def workspace_close(app, remove_dir, all_, elements): |
| 772 | 772 |
if nonexisting:
|
| 773 | 773 |
raise AppError("Workspace does not exist", detail="\n".join(nonexisting))
|
| 774 | 774 |
|
| 775 |
- if app.interactive and remove_dir:
|
|
| 775 |
+ if app.interactive and remove_dir and app.context.prompt_workspace_close_remove_dir:
|
|
| 776 | 776 |
if not click.confirm('This will remove all your changes, are you sure?'):
|
| 777 | 777 |
click.echo('Aborting', err=True)
|
| 778 | 778 |
sys.exit(-1)
|
| ... | ... | @@ -806,7 +806,7 @@ def workspace_reset(app, soft, track_, all_, elements): |
| 806 | 806 |
if all_ and not app.stream.workspace_exists():
|
| 807 | 807 |
raise AppError("No open workspaces to reset")
|
| 808 | 808 |
|
| 809 |
- if app.interactive and not soft:
|
|
| 809 |
+ if app.interactive and not soft and app.context.prompt_workspace_reset_hard:
|
|
| 810 | 810 |
if not click.confirm('This will remove all your changes, are you sure?'):
|
| 811 | 811 |
click.echo('Aborting', err=True)
|
| 812 | 812 |
sys.exit(-1)
|
| ... | ... | @@ -351,6 +351,7 @@ _sentinel = object() |
| 351 | 351 |
# expected_type (type): The expected type for the value being searched
|
| 352 | 352 |
# key (str): The key to get a value for in node
|
| 353 | 353 |
# indices (list of ints): Optionally decend into lists of lists
|
| 354 |
+# default_value: Optionally return this value if the key is not found
|
|
| 354 | 355 |
#
|
| 355 | 356 |
# Returns:
|
| 356 | 357 |
# The value if found in node, otherwise default_value is returned
|
| ... | ... | @@ -100,3 +100,35 @@ logging: |
| 100 | 100 |
|
| 101 | 101 |
[%{elapsed}][%{key}][%{element}] %{action} %{message}
|
| 102 | 102 |
|
| 103 |
+#
|
|
| 104 |
+# Prompt overrides
|
|
| 105 |
+#
|
|
| 106 |
+# Here you can suppress 'are you sure?' and other kinds of prompts by supplying
|
|
| 107 |
+# override values. Note that e.g. 'yes' and 'no' have the same meaning here as
|
|
| 108 |
+# they do in the actual cli prompt.
|
|
| 109 |
+#
|
|
| 110 |
+prompt:
|
|
| 111 |
+ |
|
| 112 |
+ # Whether to create a project with 'bst init' if we are invoked outside of a
|
|
| 113 |
+ # directory where we can resolve the project.
|
|
| 114 |
+ #
|
|
| 115 |
+ # ask - Prompt the user to choose.
|
|
| 116 |
+ # no - Never create the project.
|
|
| 117 |
+ #
|
|
| 118 |
+ auto-init: ask
|
|
| 119 |
+ |
|
| 120 |
+ # Whether to really proceed with 'bst workspace close --remove-dir' removing
|
|
| 121 |
+ # a workspace directory, potentially losing changes.
|
|
| 122 |
+ #
|
|
| 123 |
+ # ask - Ask the user if they are sure.
|
|
| 124 |
+ # yes - Always remove, without asking.
|
|
| 125 |
+ #
|
|
| 126 |
+ really-workspace-close-remove-dir: ask
|
|
| 127 |
+ |
|
| 128 |
+ # Whether to really proceed with 'bst workspace reset' doing a hard reset of
|
|
| 129 |
+ # a workspace, potentially losing changes.
|
|
| 130 |
+ #
|
|
| 131 |
+ # ask - Ask the user if they are sure.
|
|
| 132 |
+ # yes - Always hard reset, without asking.
|
|
| 133 |
+ #
|
|
| 134 |
+ really-workspace-reset-hard: ask
|
