summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJürg Billeter <j@bitron.ch>2019-01-21 13:58:55 +0100
committerJürg Billeter <j@bitron.ch>2019-01-24 14:37:28 +0100
commitab72d384a0b79b55543e1e7facd00f4778bbc780 (patch)
treec930e804572f646c13bd94d7aa926848930e355c
parent3850274b423fff404ed3acaf1a21f271b07c6a08 (diff)
downloadbuildstream-ab72d384a0b79b55543e1e7facd00f4778bbc780.tar.gz
_project.py: Add get_default_target() and get_default_targets() methods
_frontend/cli.py: Use new methods. Based on patches by Phillip Smyth.
-rw-r--r--buildstream/_context.py16
-rw-r--r--buildstream/_frontend/cli.py93
-rw-r--r--buildstream/_project.py47
3 files changed, 115 insertions, 41 deletions
diff --git a/buildstream/_context.py b/buildstream/_context.py
index 8b9f47bd6..f14f6b746 100644
--- a/buildstream/_context.py
+++ b/buildstream/_context.py
@@ -32,7 +32,7 @@ from ._message import Message, MessageType
from ._profile import Topics, profile_start, profile_end
from ._artifactcache import ArtifactCache
from ._cas import CASCache
-from ._workspaces import Workspaces, WorkspaceProjectCache, WORKSPACE_PROJECT_FILE
+from ._workspaces import Workspaces, WorkspaceProjectCache
from .plugin import _plugin_lookup
from .sandbox import SandboxRemote
@@ -657,20 +657,6 @@ class Context():
self._cascache = CASCache(self.artifactdir)
return self._cascache
- # guess_element()
- #
- # Attempts to interpret which element the user intended to run commands on
- #
- # Returns:
- # (str) The name of the element, or None if no element can be guessed
- def guess_element(self):
- workspace_project_dir, _ = utils._search_upward_for_files(self._directory, [WORKSPACE_PROJECT_FILE])
- if workspace_project_dir:
- workspace_project = self._workspace_project_cache.get(workspace_project_dir)
- return workspace_project.get_default_element()
- else:
- return None
-
# _node_get_option_str()
#
diff --git a/buildstream/_frontend/cli.py b/buildstream/_frontend/cli.py
index 36711e7fb..43b827f18 100644
--- a/buildstream/_frontend/cli.py
+++ b/buildstream/_frontend/cli.py
@@ -342,7 +342,15 @@ def init(app, project_name, format_version, element_path, force):
type=click.Path(readable=False))
@click.pass_obj
def build(app, elements, all_, track_, track_save, track_all, track_except, track_cross_junctions):
- """Build elements in a pipeline"""
+ """Build elements in a pipeline
+
+ Specifying no elements will result in building the default targets
+ of the project. If no default targets are configured, all project
+ elements will be built.
+
+ When this command is executed from a workspace directory, the default
+ is to build the workspace element.
+ """
if (track_except or track_cross_junctions) and not (track_ or track_all):
click.echo("ERROR: The --track-except and --track-cross-junctions options "
@@ -354,9 +362,7 @@ def build(app, elements, all_, track_, track_save, track_all, track_except, trac
with app.initialized(session_name="Build"):
if not elements:
- guessed_target = app.context.guess_element()
- if guessed_target:
- elements = (guessed_target,)
+ elements = app.project.get_default_targets()
if track_all:
track_ = elements
@@ -390,6 +396,13 @@ def build(app, elements, all_, track_, track_save, track_all, track_except, trac
def show(app, elements, deps, except_, order, format_):
"""Show elements in the pipeline
+ Specifying no elements will result in showing the default targets
+ of the project. If no default targets are configured, all project
+ elements will be shown.
+
+ When this command is executed from a workspace directory, the default
+ is to show the workspace element.
+
By default this will show all of the dependencies of the
specified target element.
@@ -436,9 +449,7 @@ def show(app, elements, deps, except_, order, format_):
"""
with app.initialized():
if not elements:
- guessed_target = app.context.guess_element()
- if guessed_target:
- elements = (guessed_target,)
+ elements = app.project.get_default_targets()
dependencies = app.stream.load_selection(elements,
selection=deps,
@@ -478,6 +489,9 @@ def show(app, elements, deps, except_, order, format_):
def shell(app, element, sysroot, mount, isolate, build_, cli_buildtree, command):
"""Run a command in the target element's sandbox environment
+ When this command is executed from a workspace directory, the default
+ is to shell into the workspace element.
+
This will stage a temporary sysroot for running the target
element, assuming it has already been built and all required
artifacts are in the local cache.
@@ -511,7 +525,7 @@ def shell(app, element, sysroot, mount, isolate, build_, cli_buildtree, command)
with app.initialized():
if not element:
- element = app.context.guess_element()
+ element = app.project.get_default_target()
if not element:
raise AppError('Missing argument "ELEMENT".')
@@ -581,6 +595,13 @@ def source():
def source_fetch(app, elements, deps, track_, except_, track_cross_junctions):
"""Fetch sources required to build the pipeline
+ Specifying no elements will result in fetching the default targets
+ of the project. If no default targets are configured, all project
+ elements will be fetched.
+
+ When this command is executed from a workspace directory, the default
+ is to fetch the workspace element.
+
By default this will only try to fetch sources which are
required for the build plan of the specified target element,
omitting sources for any elements which are already built
@@ -606,9 +627,7 @@ def source_fetch(app, elements, deps, track_, except_, track_cross_junctions):
with app.initialized(session_name="Fetch"):
if not elements:
- guessed_target = app.context.guess_element()
- if guessed_target:
- elements = (guessed_target,)
+ elements = app.project.get_default_targets()
app.stream.fetch(elements,
selection=deps,
@@ -636,6 +655,15 @@ def source_track(app, elements, deps, except_, cross_junctions):
"""Consults the specified tracking branches for new versions available
to build and updates the project with any newly available references.
+ Specifying no elements will result in tracking the default targets
+ of the project. If no default targets are configured, all project
+ elements will be tracked.
+
+ When this command is executed from a workspace directory, the default
+ is to track the workspace element.
+
+ If no default is declared, all elements in the project will be tracked
+
By default this will track just the specified element, but you can also
update a whole tree of dependencies in one go.
@@ -647,9 +675,7 @@ def source_track(app, elements, deps, except_, cross_junctions):
"""
with app.initialized(session_name="Track"):
if not elements:
- guessed_target = app.context.guess_element()
- if guessed_target:
- elements = (guessed_target,)
+ elements = app.project.get_default_targets()
# Substitute 'none' for 'redirect' so that element redirections
# will be done
@@ -685,6 +711,9 @@ def source_track(app, elements, deps, except_, cross_junctions):
def source_checkout(app, element, location, force, deps, fetch_, except_,
tar, build_scripts):
"""Checkout sources of an element to the specified location
+
+ When this command is executed from a workspace directory, the default
+ is to checkout the sources of the workspace element.
"""
if not element and not location:
click.echo("ERROR: LOCATION is not specified", err=True)
@@ -697,7 +726,7 @@ def source_checkout(app, element, location, force, deps, fetch_, except_,
with app.initialized():
if not element:
- element = app.context.guess_element()
+ element = app.project.get_default_target()
if not element:
raise AppError('Missing argument "ELEMENT".')
@@ -763,7 +792,7 @@ def workspace_close(app, remove_dir, all_, elements):
if not (all_ or elements):
# NOTE: I may need to revisit this when implementing multiple projects
# opening one workspace.
- element = app.context.guess_element()
+ element = app.project.get_default_target()
if element:
elements = (element,)
else:
@@ -824,7 +853,7 @@ def workspace_reset(app, soft, track_, all_, elements):
with app.initialized():
if not (all_ or elements):
- element = app.context.guess_element()
+ element = app.project.get_default_target()
if element:
elements = (element,)
else:
@@ -921,7 +950,11 @@ def artifact():
type=click.Path(readable=False))
@click.pass_obj
def artifact_checkout(app, force, deps, integrate, hardlinks, tar, directory, element):
- """Checkout contents of an artifact"""
+ """Checkout contents of an artifact
+
+ When this command is executed from a workspace directory, the default
+ is to checkout the artifact of the workspace element.
+ """
from ..element import Scope
if hardlinks and tar is not None:
@@ -952,7 +985,7 @@ def artifact_checkout(app, force, deps, integrate, hardlinks, tar, directory, el
with app.initialized():
if not element:
- element = app.context.guess_element()
+ element = app.project.get_default_target()
if not element:
raise AppError('Missing argument "ELEMENT".')
@@ -980,6 +1013,13 @@ def artifact_checkout(app, force, deps, integrate, hardlinks, tar, directory, el
def artifact_pull(app, elements, deps, remote):
"""Pull a built artifact from the configured remote artifact cache.
+ Specifying no elements will result in pulling the default targets
+ of the project. If no default targets are configured, all project
+ elements will be pulled.
+
+ When this command is executed from a workspace directory, the default
+ is to pull the workspace element.
+
By default the artifact will be pulled one of the configured caches
if possible, following the usual priority order. If the `--remote` flag
is given, only the specified cache will be queried.
@@ -993,9 +1033,7 @@ def artifact_pull(app, elements, deps, remote):
with app.initialized(session_name="Pull"):
if not elements:
- guessed_target = app.context.guess_element()
- if guessed_target:
- elements = (guessed_target,)
+ elements = app.project.get_default_targets()
app.stream.pull(elements, selection=deps, remote=remote)
@@ -1015,6 +1053,13 @@ def artifact_pull(app, elements, deps, remote):
def artifact_push(app, elements, deps, remote):
"""Push a built artifact to a remote artifact cache.
+ Specifying no elements will result in pushing the default targets
+ of the project. If no default targets are configured, all project
+ elements will be pushed.
+
+ When this command is executed from a workspace directory, the default
+ is to push the workspace element.
+
The default destination is the highest priority configured cache. You can
override this by passing a different cache URL with the `--remote` flag.
@@ -1030,9 +1075,7 @@ def artifact_push(app, elements, deps, remote):
"""
with app.initialized(session_name="Push"):
if not elements:
- guessed_target = app.context.guess_element()
- if guessed_target:
- elements = (guessed_target,)
+ elements = app.project.get_default_targets()
app.stream.push(elements, selection=deps, remote=remote)
diff --git a/buildstream/_project.py b/buildstream/_project.py
index 1492fde77..3ec141d58 100644
--- a/buildstream/_project.py
+++ b/buildstream/_project.py
@@ -104,6 +104,9 @@ class Project():
# Absolute path to where elements are loaded from within the project
self.element_path = None
+ # Default target elements
+ self._default_targets = None
+
# ProjectRefs for the main refs and also for junctions
self.refs = ProjectRefs(self.directory, 'project.refs')
self.junction_refs = ProjectRefs(self.directory, 'junction.refs')
@@ -228,7 +231,7 @@ class Project():
'element-path', 'variables',
'environment', 'environment-nocache',
'split-rules', 'elements', 'plugins',
- 'aliases', 'name',
+ 'aliases', 'name', 'defaults',
'artifacts', 'options',
'fail-on-overlap', 'shell', 'fatal-warnings',
'ref-storage', 'sandbox', 'mirrors', 'remote-execution',
@@ -391,6 +394,44 @@ class Project():
# Reset the element loader state
Element._reset_load_state()
+ # get_default_target()
+ #
+ # Attempts to interpret which element the user intended to run a command on.
+ # This is for commands that only accept a single target element and thus,
+ # this only uses the workspace element (if invoked from workspace directory)
+ # and does not use the project default targets.
+ #
+ def get_default_target(self):
+ return self._invoked_from_workspace_element
+
+ # get_default_targets()
+ #
+ # Attempts to interpret which elements the user intended to run a command on.
+ # This is for commands that accept multiple target elements.
+ #
+ def get_default_targets(self):
+
+ # If _invoked_from_workspace_element has a value,
+ # a workspace element was found before a project config
+ # Therefore the workspace does not contain a project
+ if self._invoked_from_workspace_element:
+ return (self._invoked_from_workspace_element,)
+
+ # Default targets from project configuration
+ if self._default_targets:
+ return tuple(self._default_targets)
+
+ # If default targets are not configured, default to all project elements
+ default_targets = []
+ for root, _, files in os.walk(self.element_path):
+ for file in files:
+ if file.endswith(".bst"):
+ rel_dir = os.path.relpath(root, self.element_path)
+ rel_file = os.path.join(rel_dir, file).lstrip("./")
+ default_targets.append(rel_file)
+
+ return tuple(default_targets)
+
# _load():
#
# Loads the project configuration file in the project
@@ -456,6 +497,10 @@ class Project():
self.config.options = OptionPool(self.element_path)
self.first_pass_config.options = OptionPool(self.element_path)
+ defaults = _yaml.node_get(pre_config_node, Mapping, 'defaults')
+ _yaml.node_validate(defaults, ['targets'])
+ self._default_targets = _yaml.node_get(defaults, list, "targets")
+
# Fatal warnings
self._fatal_warnings = _yaml.node_get(pre_config_node, list, 'fatal-warnings', default_value=[])