Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • willsalmon/buildstream
  • CumHoleZH/buildstream
  • tchaik/buildstream
  • DCotyPortfolio/buildstream
  • jesusoctavioas/buildstream
  • patrickmmartin/buildstream
  • franred/buildstream
  • tintou/buildstream
  • alatiera/buildstream
  • martinblanchard/buildstream
  • neverdie22042524/buildstream
  • Mattlk13/buildstream
  • PServers/buildstream
  • phamnghia610909/buildstream
  • chiaratolentino/buildstream
  • eysz7-x-x/buildstream
  • kerrick1/buildstream
  • matthew-yates/buildstream
  • twofeathers/buildstream
  • mhadjimichael/buildstream
  • pointswaves/buildstream
  • Mr.JackWilson/buildstream
  • Tw3akG33k/buildstream
  • AlexFazakas/buildstream
  • eruidfkiy/buildstream
  • clamotion2/buildstream
  • nanonyme/buildstream
  • wickyjaaa/buildstream
  • nmanchev/buildstream
  • bojorquez.ja/buildstream
  • mostynb/buildstream
  • highpit74/buildstream
  • Demo112/buildstream
  • ba2014sheer/buildstream
  • tonimadrino/buildstream
  • usuario2o/buildstream
  • Angelika123456/buildstream
  • neo355/buildstream
  • corentin-ferlay/buildstream
  • coldtom/buildstream
  • wifitvbox81/buildstream
  • 358253885/buildstream
  • seanborg/buildstream
  • SotK/buildstream
  • DouglasWinship/buildstream
  • karansthr97/buildstream
  • louib/buildstream
  • bwh-ct/buildstream
  • robjh/buildstream
  • we88c0de/buildstream
  • zhengxian5555/buildstream
51 results
Show changes
Commits on Source (2)
  • Phillip Smyth's avatar
    Adding build tree extraction functionality · f1fac4d4
    Phillip Smyth authored
    tests/completions/completions.py: Adding caching build tree flag to list of recognised flags in test
    _frontend/cli.py: Adding caching build tree flags to cli
    _artifactcache/artifactcache.py: Adding abstract get_buildtree_dir function
    _artifactcache/cascache.py: Adding get_buildtree_dir function
    element.py: Adding function to return build tree path
    
    Adding functionality to allow the use of a cached build tree in a workspace
    
    _stream.py: Adding staging of cached build tree
    f1fac4d4
  • Phillip Smyth's avatar
    tests/integration/workspace.py: Adding tests for caching of build tree and... · 8b8d06d6
    Phillip Smyth authored
    tests/integration/workspace.py: Adding tests for caching of build tree and using them in a workspace
    
    Adding Makefiles
    Updating expected keys
    8b8d06d6
......@@ -366,7 +366,7 @@ class ArtifactCache():
#
# Returns: path to extracted artifact
#
def extract(self, element, key):
def extract(self, element, key, dest=None):
raise ImplError("Cache '{kind}' does not implement extract()"
.format(kind=type(self).__name__))
......@@ -483,6 +483,21 @@ class ArtifactCache():
raise ImplError("Cache '{kind}' does not implement calculate_cache_size()"
.format(kind=type(self).__name__))
# does get_buildtree_dir():
#
# Returns build tree from cache if exists
#
# Args:
# element (Element): The Element whose cache is being checked
# key: the related cache key
# directory: the directory to return if exists
# Returns:
# string: directory path or None
#
def get_buildtree_dir(self, element, key):
raise ImplError("Cache '{kind}' does not implement get_buildtree_dir()"
.format(kind=type(self).__name__))
################################################
# Local Private Methods #
################################################
......
......@@ -75,12 +75,14 @@ class CASCache(ArtifactCache):
# This assumes that the repository doesn't have any dangling pointers
return os.path.exists(refpath)
def extract(self, element, key):
def extract(self, element, key, dest=None):
ref = self.get_artifact_fullname(element, key)
tree = self.resolve_ref(ref, update_mtime=True)
dest = os.path.join(self.extractdir, element._get_project().name, element.normal_name, tree.hash)
if dest is None:
dest = os.path.join(self.extractdir, element._get_project().name, element.normal_name, tree.hash)
if os.path.isdir(dest):
# artifact has already been extracted
return dest
......@@ -106,6 +108,9 @@ class CASCache(ArtifactCache):
return dest
def get_buildtree_dir(self, element, key):
return os.path.join(self.extract(element, key), "buildtree")
def commit(self, element, content, keys):
refs = [self.get_artifact_fullname(element, key) for key in keys]
......
......@@ -446,7 +446,9 @@ def pull(app, elements, deps, remote):
all: All dependencies
"""
with app.initialized(session_name="Pull"):
app.stream.pull(elements, selection=deps, remote=remote)
app.stream.pull(elements,
selection=deps,
remote=remote)
##################################################################
......@@ -681,11 +683,14 @@ def workspace():
help="Overwrite files existing in checkout directory")
@click.option('--track', 'track_', default=False, is_flag=True,
help="Track and fetch new source references before checking out the workspace")
@click.option('--use-cached-buildtree', 'use_cached_buildtree', default='when-local',
type=click.Choice(['use-cached', 'ignore-cached', 'when-local']),
help="Using cached build trees")
@click.argument('element',
type=click.Path(readable=False))
@click.argument('directory', type=click.Path(file_okay=False))
@click.pass_obj
def workspace_open(app, no_checkout, force, track_, element, directory):
def workspace_open(app, no_checkout, force, track_, element, directory, use_cached_buildtree):
"""Open a workspace for manual source modification"""
if os.path.exists(directory):
......@@ -702,7 +707,8 @@ def workspace_open(app, no_checkout, force, track_, element, directory):
app.stream.workspace_open(element, directory,
no_checkout=no_checkout,
track_first=track_,
force=force)
force=force,
use_cached_buildtree=use_cached_buildtree)
##################################################################
......@@ -762,10 +768,13 @@ def workspace_close(app, remove_dir, all_, elements):
help="Track and fetch the latest source before resetting")
@click.option('--all', '-a', 'all_', default=False, is_flag=True,
help="Reset all open workspaces")
@click.option('--use-cached-buildtree', 'use_cached_buildtree', default='when-local',
type=click.Choice(['use-cached', 'ignore-cached', 'when-local']),
help="Using cached build trees")
@click.argument('elements', nargs=-1,
type=click.Path(readable=False))
@click.pass_obj
def workspace_reset(app, soft, track_, all_, elements):
def workspace_reset(app, soft, track_, all_, elements, use_cached_buildtree):
"""Reset a workspace to its original state"""
# Check that the workspaces in question exist
......@@ -785,7 +794,10 @@ def workspace_reset(app, soft, track_, all_, elements):
if all_:
elements = tuple(element_name for element_name, _ in app.context.get_workspaces().list())
app.stream.workspace_reset(elements, soft=soft, track_first=track_)
app.stream.workspace_reset(elements,
soft=soft,
track_first=track_,
use_cached_buildtree=use_cached_buildtree)
##################################################################
......
......@@ -435,6 +435,29 @@ class Stream():
raise StreamError("Error while staging dependencies into a sandbox"
": '{}'".format(e), detail=e.detail, reason=e.reason) from e
# __stage_cached_buildtree
#
# Stage a cached build tree if it exists
#
# Args:
# use_cached_buildtree (bool): Whether or not to use cached buildtrees
# element: element in use
# cache_activity, stage_activity, message: (str)
#
# Returns:
# (bool): True if the build tree was staged
#
def __stage_cached_buildtree(self, element, target_dir):
buildtree_path = None
if element._cached():
with element.timed_activity("Extracting cached build tree"):
buildtree_path = element._buildtree_path(element._get_cache_key())
if buildtree_path is not None:
with element.timed_activity("Staging cached build tree to {}".format(target_dir)):
shutil.copytree(buildtree_path, target_dir)
return True
return False
# workspace_open
#
# Open a project workspace
......@@ -445,11 +468,25 @@ class Stream():
# no_checkout (bool): Whether to skip checking out the source
# track_first (bool): Whether to track and fetch first
# force (bool): Whether to ignore contents in an existing directory
# use_cached_buildtree(str): Whether or not to use cached buildtrees
#
def workspace_open(self, target, directory, *,
no_checkout,
track_first,
force):
force,
use_cached_buildtree):
workspaces = self._context.get_workspaces()
assert use_cached_buildtree in ('use-cached', 'when-local', 'ignore-cached')
# Make cached_buildtree a boolean based on the flag assigned to it
# If flag was `when-local`, assigning value based on whether or not the project uses a remote cache
if use_cached_buildtree == 'use-cached':
use_cached_buildtree = True
elif use_cached_buildtree == 'when-local' and not self._artifacts.has_fetch_remotes():
use_cached_buildtree = True
else:
use_cached_buildtree = False
if track_first:
track_targets = (target,)
......@@ -462,22 +499,6 @@ class Stream():
target = elements[0]
workdir = os.path.abspath(directory)
if not list(target.sources()):
build_depends = [x.name for x in target.dependencies(Scope.BUILD, recurse=False)]
if not build_depends:
raise StreamError("The given element has no sources")
detail = "Try opening a workspace on one of its dependencies instead:\n"
detail += " \n".join(build_depends)
raise StreamError("The given element has no sources", detail=detail)
workspaces = self._context.get_workspaces()
# Check for workspace config
workspace = workspaces.get_workspace(target._get_full_name())
if workspace and not force:
raise StreamError("Workspace '{}' is already defined at: {}"
.format(target.name, workspace.path))
# If we're going to checkout, we need at least a fetch,
# if we were asked to track first, we're going to fetch anyway.
#
......@@ -487,6 +508,26 @@ class Stream():
track_elements = elements
self._fetch(elements, track_elements=track_elements)
# Check for workspace config
workspace = workspaces.get_workspace(target._get_full_name())
if workspace and not force:
raise StreamError("Workspace '{}' is already defined at: {}"
.format(target.name, workspace.path))
if use_cached_buildtree:
if self.__stage_cached_buildtree(target, workdir):
workspaces.save_config()
self._message(MessageType.INFO, "Saved workspace configuration")
return
if not list(target.sources()):
build_depends = [x.name for x in target.dependencies(Scope.BUILD, recurse=False)]
if not build_depends:
raise StreamError("The given element has no sources")
detail = "Try opening a workspace on one of its dependencies instead:\n"
detail += " \n".join(build_depends)
raise StreamError("The given element has no sources", detail=detail)
if not no_checkout and target._get_consistency() != Consistency.CACHED:
raise StreamError("Could not stage uncached source. " +
"Use `--track` to track and " +
......@@ -547,8 +588,9 @@ class Stream():
# targets (list of str): The target elements to reset the workspace for
# soft (bool): Only reset workspace state
# track_first (bool): Whether to also track the sources first
# use_cached_buildtree(str): Whether or not to use cached buildtrees
#
def workspace_reset(self, targets, *, soft, track_first):
def workspace_reset(self, targets, *, soft, track_first, use_cached_buildtree):
if track_first:
track_targets = targets
......@@ -592,6 +634,15 @@ class Stream():
workspaces.delete_workspace(element._get_full_name())
workspaces.create_workspace(element._get_full_name(), workspace.path)
if use_cached_buildtree == 'when-local':
use_cached_buildtree = os.path.isdir(os.path.join(workspace.path, 'buildtree'))
if use_cached_buildtree and self.__stage_cached_buildtree(element, workspace.path):
self._message(MessageType.INFO, "Reset workspace state for {} at: {}"
.format(element.name, workspace.path))
return
workspaces.create_workspace(element.name, workspace.path)
with element.timed_activity("Staging sources to {}".format(workspace.path)):
element._open_workspace()
......
......@@ -893,6 +893,13 @@ class Element(Plugin):
# Private Methods used in BuildStream #
#############################################################
# _buildtree_path():
#
# Returns the path of the cached build tree if it exists
#
def _buildtree_path(self, key):
return self.__artifacts.get_buildtree_dir(self, key)
# _new_from_meta():
#
# Recursively instantiate a new Element instance, it's sources
......
test:
touch test.o
test:
touch test.o
......@@ -5,6 +5,7 @@ from buildstream import _yaml
from tests.testutils import cli_integration as cli
from tests.testutils.site import IS_LINUX
from tests.testutils.integration import walk_dir
from tests.frontend import configure_project
pytestmark = pytest.mark.integration
......@@ -255,3 +256,119 @@ def test_incremental_configure_commands_run_only_once(cli, tmpdir, datafiles):
res = cli.run(project=project, args=['build', element_name])
res.assert_success()
assert not os.path.exists(os.path.join(workspace, 'prepared-again'))
@pytest.mark.integration
@pytest.mark.datafiles(DATA_DIR)
def test_use_cached_buildtree(cli, tmpdir, datafiles):
project = os.path.join(datafiles.dirname, datafiles.basename)
workspace = os.path.join(cli.directory, 'workspace')
element_path = os.path.join(project, 'elements')
element_name = 'workspace/workspace-use-cached-buildtree.bst'
element = {
'kind': 'manual',
'depends': [{
'filename': 'base.bst',
'type': 'build'
}],
'sources': [{
'kind': 'local',
'path': 'files/workspace-use-cached-buildtree'
}],
'config': {
'build-commands': [
'make'
]
}
}
os.makedirs(os.path.dirname(os.path.join(element_path, element_name)), exist_ok=True)
_yaml.dump(element, os.path.join(element_path, element_name))
res = cli.run(project=project, args=['build', element_name])
res.assert_success()
res = cli.run(project=project, args=['workspace', 'open', element_name, workspace])
res.assert_success()
assert os.path.isdir(workspace)
assert os.path.exists(os.path.join(workspace, "test.o"))
@pytest.mark.integration
@pytest.mark.datafiles(DATA_DIR)
def test_dont_use_cached_buildtree(cli, tmpdir, datafiles):
project = os.path.join(datafiles.dirname, datafiles.basename)
workspace = os.path.join(cli.directory, 'workspace')
element_path = os.path.join(project, 'elements')
element_name = 'workspace/workspace-use-cached-buildtree.bst'
element = {
'kind': 'manual',
'depends': [{
'filename': 'base.bst',
'type': 'build'
}],
'sources': [{
'kind': 'local',
'path': 'files/workspace-use-cached-buildtree'
}],
'config': {
'build-commands': [
'make'
]
}
}
os.makedirs(os.path.dirname(os.path.join(element_path, element_name)), exist_ok=True)
_yaml.dump(element, os.path.join(element_path, element_name))
res = cli.run(project=project, args=['build', element_name])
res.assert_success()
res = cli.run(project=project, args=['workspace', 'open',
'--use-cached-buildtree=ignore-cached',
element_name, workspace])
res.assert_success()
assert os.path.isdir(workspace)
assert not os.path.exists(os.path.join(workspace, "test.o"))
@pytest.mark.integration
@pytest.mark.datafiles(DATA_DIR)
# This tests the output if a build is done with the caching of build trees disabled
# and then is reenabled and a workspace is opened
def test_no_existing_cached_buildtree(cli, tmpdir, datafiles):
project = os.path.join(datafiles.dirname, datafiles.basename)
workspace = os.path.join(cli.directory, 'workspace')
element_path = os.path.join(project, 'elements')
element_name = 'workspace/workspace-no-existing-cached-buildtree.bst'
element = {
'kind': 'manual',
'depends': [{
'filename': 'base.bst',
'type': 'build'
}],
'sources': [{
'kind': 'local',
'path': 'files/workspace-no-existing-cached-buildtree'
}],
'config': {
'build-commands': [
'make'
]
}
}
os.makedirs(os.path.dirname(os.path.join(element_path, element_name)), exist_ok=True)
_yaml.dump(element, os.path.join(element_path, element_name))
res = cli.run(project=project,
project_config={'variables': {'cache-buildtree': False}},
args=['build', element_name])
res.assert_success()
res = cli.run(project=project,
project_config={'variables': {'cache-buildtrees': True}},
args=['workspace', 'open', element_name, workspace])
res.assert_success()
assert os.path.isdir(workspace)
assert not os.path.exists(os.path.join(workspace, "test.o"))