Skip to content
Snippets Groups Projects
Commit 1ba92c1a authored by Ed Baunton's avatar Ed Baunton
Browse files

remote.py: Add support for marking downloaded files executable

Add an optional flag to make files executable after having downloaded them.
parent 4e1160a9
No related branches found
No related tags found
No related merge requests found
......@@ -35,6 +35,10 @@ remote - stage files from remote urls
# If not specified, the basename of the url will be used.
# filename: customfilename
# Optionally specify whether the downloaded file should be
# marked executable.
# executable: true
# Specify the url. Using an alias defined in your project
# configuration is encouraged. 'bst track' will update the
# sha256sum in 'ref' to the downloaded file's sha256sum.
......@@ -43,12 +47,15 @@ remote - stage files from remote urls
# Specify the ref. It's a sha256sum of the file you download.
ref: 6c9f6f68a131ec6381da82f2bff978083ed7f4f7991d931bfa767b7965ebc94b
.. note::
The ``remote`` plugin is available since :ref:`format version 10 <project_format_version>`
"""
import os
import stat
from buildstream import SourceError, utils
from ._downloadablefilesource import DownloadableFileSource
......@@ -60,22 +67,28 @@ class RemoteSource(DownloadableFileSource):
super().configure(node)
self.filename = self.node_get_member(node, str, 'filename', os.path.basename(self.url))
self.executable = self.node_get_member(node, bool, 'executable', False)
if os.sep in self.filename:
raise SourceError('{}: filename parameter cannot contain directories'.format(self),
reason="filename-contains-directory")
self.node_validate(node, DownloadableFileSource.COMMON_CONFIG_KEYS + ['filename'])
self.node_validate(node, DownloadableFileSource.COMMON_CONFIG_KEYS + ['filename', 'executable'])
def get_unique_key(self):
return super().get_unique_key() + [self.filename]
return super().get_unique_key() + [self.filename, self.executable]
def stage(self, directory):
# Same as in local plugin, don't use hardlinks to stage sources, they
# are not write protected in the sandbox.
dest = os.path.join(directory, self.filename)
with self.timed_activity("Staging remote file to {}".format(dest)):
utils.safe_copy(self._get_mirror_file(), dest)
if self.executable:
st = os.stat(dest)
os.chmod(dest, st.st_mode | stat.S_IEXEC)
def setup():
return RemoteSource
import os
import stat
import pytest
from buildstream._exceptions import ErrorDomain
......@@ -82,7 +83,10 @@ def test_simple_file_build(cli, tmpdir, datafiles):
result.assert_success()
# Note that the url of the file in target.bst is actually /dir/file
# but this tests confirms we take the basename
assert(os.path.exists(os.path.join(checkoutdir, 'file')))
checkout_file = os.path.join(checkoutdir, 'file')
assert(os.path.exists(checkout_file))
assert(not (os.stat(checkout_file).st_mode & stat.S_IEXEC))
@pytest.mark.datafiles(os.path.join(DATA_DIR, 'single-file-custom-name'))
......@@ -119,6 +123,7 @@ def test_unique_key(cli, tmpdir, datafiles):
generate_project(project, tmpdir)
assert cli.get_element_state(project, 'target.bst') == "fetch needed"
assert cli.get_element_state(project, 'target-custom.bst') == "fetch needed"
assert cli.get_element_state(project, 'target-custom-executable.bst') == "fetch needed"
# Try to fetch it
result = cli.run(project=project, args=[
'fetch', 'target.bst'
......@@ -127,7 +132,30 @@ def test_unique_key(cli, tmpdir, datafiles):
# We should download the file only once
assert cli.get_element_state(project, 'target.bst') == 'buildable'
assert cli.get_element_state(project, 'target-custom.bst') == 'buildable'
assert cli.get_element_state(project, 'target-custom-executable.bst') == 'buildable'
# But the cache key is different because the 'filename' is different.
assert cli.get_element_key(project, 'target.bst') != \
cli.get_element_key(project, 'target-custom.bst')
cli.get_element_key(project, 'target-custom.bst') != \
cli.get_element_key(project, 'target-custom-executable.bst')
@pytest.mark.datafiles(os.path.join(DATA_DIR, 'unique-keys'))
def test_executable(cli, tmpdir, datafiles):
'''This test confirms that the 'ecxecutable' parameter is honoured.
'''
project = os.path.join(datafiles.dirname, datafiles.basename)
generate_project(project, tmpdir)
checkoutdir = os.path.join(str(tmpdir), "checkout")
assert cli.get_element_state(project, 'target-custom-executable.bst') == "fetch needed"
# Try to fetch it
result = cli.run(project=project, args=[
'build', 'target-custom-executable.bst'
])
result = cli.run(project=project, args=[
'checkout', 'target-custom-executable.bst', checkoutdir
])
assert (os.stat(
os.path.join(checkoutdir, 'some-custom-file')).st_mode & stat.S_IEXEC)
kind: import
description: test
sources:
- kind: remote
url: tmpdir:/dir/file
ref: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
filename: some-custom-file
executable: true
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