Skip to content
Snippets Groups Projects
Commit c3eb6006 authored by Jonathan Maw's avatar Jonathan Maw
Browse files

Make specifying elements optional in bst commands

Known issues:
* `bst shell` works, but `bst shell COMMANDS...` doesn't, because click
  has no way of separating optional args from variable-length args.
* `bst checkout`'s usage string marks LOCATION as an optional argument.
  Because click gets confused if there's an optional argument before a
  mandatory argument, I had to mark LOCATION as optional internally.
* `bst workspace open` makes no sense with element being optional, so
  I skipped it.
* `bst workspace close` will probably need to be revisited when multiple
  projects can own one workspace.
* `bst workspace reset` will happily delete the directory you're
  currently in, requiring you to `cd $PWD` to see the contents of your
  directory.
  I could exclude the top-level directory of the workspace being
  deleted, but it is entirely valid to run workspace commands from deeper
  in the workspace.
* `bst source-bundle` does not work if a workspace is open at all, and
  according to #672 is scoped for deprecation, so I have left it alone.

This is a part of #222
parent ff0d91a0
No related branches found
No related tags found
No related merge requests found
......@@ -47,9 +47,13 @@ from .plugin import _plugin_lookup
# verbosity levels and basically anything pertaining to the context
# in which BuildStream was invoked.
#
# Args:
# workspace_project_cache (WorkspaceProjectCache): A WorkspaceProjectCache
# for this invocation
#
class Context():
def __init__(self):
def __init__(self, workspace_project_cache=None):
# Filename indicating which configuration file was used, or None for the defaults
self.config_origin = None
......@@ -144,7 +148,7 @@ class Context():
self._projects = []
self._project_overrides = {}
self._workspaces = None
self._workspace_project_cache = WorkspaceProjectCache()
self._workspace_project_cache = workspace_project_cache or WorkspaceProjectCache()
self._log_handle = None
self._log_filename = None
self._cascache = None
......
......@@ -39,6 +39,7 @@ from .._stream import Stream
from .._versions import BST_FORMAT_VERSION
from .. import _yaml
from .._scheduler import ElementJob
from .._workspaces import WorkspaceProjectCache
# Import frontend assets
from . import Profile, LogLine, Status
......@@ -79,6 +80,7 @@ class App():
self._fail_messages = {} # Failure messages by unique plugin id
self._interactive_failures = None # Whether to handle failures interactively
self._started = False # Whether a session has started
self._workspace_project_cache = WorkspaceProjectCache() # A collection of workspace local data
# UI Colors Profiles
self._content_profile = Profile(fg='yellow')
......@@ -164,7 +166,7 @@ class App():
# Load the Context
#
try:
self.context = Context()
self.context = Context(self._workspace_project_cache)
self.context.load(config)
except BstError as e:
self._error_exit(e, "Error loading user configuration")
......@@ -402,6 +404,20 @@ class App():
if self.stream:
self.stream.cleanup()
# guess_element()
#
# Attempts to interpret which element the user intended to run commands on
#
# Returns:
# (str) The name of the element, or an empty string
def guess_element(self):
directory = self._main_options['directory']
workspace_project = self._workspace_project_cache.get(directory)
if workspace_project:
return workspace_project.get_default_element()
else:
return ""
############################################################
# Abstract Class Methods #
############################################################
......
......@@ -316,6 +316,12 @@ def build(app, elements, all_, track_, track_save, track_all, track_except, trac
if track_save:
click.echo("WARNING: --track-save is deprecated, saving is now unconditional", err=True)
if not all_ and not elements:
# Attempt to divine the element from the workspace you're in
guessed_target = app.guess_element()
if guessed_target:
elements = (guessed_target,)
if track_all:
track_ = elements
......@@ -370,6 +376,12 @@ def fetch(app, elements, deps, track_, except_, track_cross_junctions):
"Since tracking modifies the build plan, all elements will be tracked.", err=True)
deps = PipelineSelection.ALL
if not elements:
# Attempt to divine the element from the workspace you're in
guessed_target = app.guess_element()
if guessed_target:
elements = (guessed_target,)
with app.initialized(session_name="Fetch"):
app.stream.fetch(elements,
selection=deps,
......@@ -406,6 +418,12 @@ def track(app, elements, deps, except_, cross_junctions):
none: No dependencies, just the specified elements
all: All dependencies of all specified elements
"""
if not elements:
# Attempt to divine the element from the workspace you're in
guessed_target = app.guess_element()
if guessed_target:
elements = (guessed_target,)
with app.initialized(session_name="Track"):
# Substitute 'none' for 'redirect' so that element redirections
# will be done
......@@ -442,6 +460,12 @@ def pull(app, elements, deps, remote):
none: No dependencies, just the element itself
all: All dependencies
"""
if not elements:
# Attempt to divine the element from the workspace you're in
guessed_target = app.guess_element()
if guessed_target:
elements = (guessed_target,)
with app.initialized(session_name="Pull"):
app.stream.pull(elements, selection=deps, remote=remote)
......@@ -474,6 +498,11 @@ def push(app, elements, deps, remote):
none: No dependencies, just the element itself
all: All dependencies
"""
if not elements:
# Attempt to divine the element from the workspace you're in
guessed_target = app.guess_element()
if guessed_target:
elements = (guessed_target,)
with app.initialized(session_name="Push"):
app.stream.push(elements, selection=deps, remote=remote)
......@@ -544,6 +573,12 @@ def show(app, elements, deps, except_, order, format_):
bst show target.bst --format \\
$'---------- %{name} ----------\\n%{vars}'
"""
if not elements:
# Attempt to divine the element from the workspace you're in
guessed_target = app.guess_element()
if guessed_target:
elements = (guessed_target,)
with app.initialized():
dependencies = app.stream.load_selection(elements,
selection=deps,
......@@ -573,7 +608,7 @@ def show(app, elements, deps, except_, order, format_):
help="Mount a file or directory into the sandbox")
@click.option('--isolate', is_flag=True, default=False,
help='Create an isolated build sandbox')
@click.argument('element',
@click.argument('element', required=False,
type=click.Path(readable=False))
@click.argument('command', type=click.STRING, nargs=-1)
@click.pass_obj
......@@ -604,6 +639,14 @@ def shell(app, element, sysroot, mount, isolate, build_, command):
scope = Scope.RUN
with app.initialized():
if not element:
# Attempt to divine the element from the workspace you're in
guessed_target = app.guess_element()
if guessed_target:
element = guessed_target
else:
raise AppError('Error: Missing argument "ELEMENT".')
dependencies = app.stream.load_selection((element,), selection=PipelineSelection.NONE)
element = dependencies[0]
prompt = app.shell_prompt(element)
......@@ -641,15 +684,28 @@ def shell(app, element, sysroot, mount, isolate, build_, command):
help="Create a tarball from the artifact contents instead "
"of a file tree. If LOCATION is '-', the tarball "
"will be dumped to the standard output.")
@click.argument('element',
@click.argument('element', required=False,
type=click.Path(readable=False))
@click.argument('location', type=click.Path())
@click.argument('location', type=click.Path(), required=False)
@click.pass_obj
def checkout(app, element, location, force, deps, integrate, hardlinks, tar):
"""Checkout a built artifact to the specified location
"""
from ..element import Scope
if not element and not location:
click.echo("ERROR: LOCATION is not specified", err=True)
sys.exit(-1)
if element and not location:
# Nasty hack to get around click's optional args
location = element
element = app.guess_element()
if not element:
click.echo("ERROR: ELEMENT is not specified", err=True)
sys.exit(-1)
if hardlinks and tar:
click.echo("ERROR: options --hardlinks and --tar conflict", err=True)
sys.exit(-1)
......@@ -748,8 +804,14 @@ def workspace_close(app, remove_dir, all_, elements):
"""Close a workspace"""
if not (all_ or elements):
click.echo('ERROR: no elements specified', err=True)
sys.exit(-1)
# NOTE: I may need to revisit this when implementing multiple projects
# opening one workspace.
element = app.guess_element()
if element:
elements = (element,)
else:
click.echo('ERROR: no elements specified', err=True)
sys.exit(-1)
with app.initialized():
......@@ -807,7 +869,11 @@ def workspace_reset(app, soft, track_, all_, elements):
with app.initialized():
if not (all_ or elements):
raise AppError('No elements specified to reset')
element = app.guess_element()
if element:
elements = (element,)
else:
raise AppError('No elements specified to reset')
if all_ and not app.stream.workspace_exists():
raise AppError("No open workspaces to reset")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment