Jürg Billeter pushed to branch aevri/update_man at BuildStream / buildstream
Commits:
-
2e78e0d1
by Valentin David at 2018-11-29T13:18:17Z
-
a6144100
by Valentin David at 2018-11-29T13:18:17Z
-
f6c184f5
by Valentin David at 2018-11-29T16:15:56Z
-
1f31aefc
by Angelos Evripiotis at 2018-11-30T09:34:38Z
28 changed files:
- .gitlab-ci.yml
- buildstream/plugins/sources/_downloadablefilesource.py
- dev-requirements.txt
- + man/bst-artifact-server.1
- man/bst-build.1
- man/bst-checkout.1
- man/bst-fetch.1
- + man/bst-help.1
- man/bst-init.1
- man/bst-pull.1
- man/bst-push.1
- man/bst-shell.1
- man/bst-show.1
- man/bst-source-bundle.1
- + man/bst-source-checkout.1
- man/bst-track.1
- man/bst-workspace-close.1
- man/bst-workspace-list.1
- man/bst-workspace-open.1
- man/bst-workspace-reset.1
- man/bst-workspace.1
- man/bst.1
- tests/sources/remote.py
- tests/sources/tar.py
- tests/sources/zip.py
- + tests/testutils/file_server.py
- + tests/testutils/ftp_server.py
- + tests/testutils/http_server.py
Changes:
| 1 |
-image: buildstream/testsuite-debian:9-master-119-552f5fc6
|
|
| 1 |
+image: buildstream/testsuite-debian:9-master-123-7ce6581b
|
|
| 2 | 2 |
|
| 3 | 3 |
cache:
|
| 4 | 4 |
key: "$CI_JOB_NAME-"
|
| ... | ... | @@ -140,7 +140,7 @@ tests-unix: |
| 140 | 140 |
|
| 141 | 141 |
tests-fedora-missing-deps:
|
| 142 | 142 |
# Ensure that tests behave nicely while missing bwrap and ostree
|
| 143 |
- image: buildstream/testsuite-fedora:28-master-119-552f5fc6
|
|
| 143 |
+ image: buildstream/testsuite-fedora:28-master-123-7ce6581b
|
|
| 144 | 144 |
<<: *tests
|
| 145 | 145 |
|
| 146 | 146 |
script:
|
| ... | ... | @@ -5,16 +5,77 @@ import urllib.request |
| 5 | 5 |
import urllib.error
|
| 6 | 6 |
import contextlib
|
| 7 | 7 |
import shutil
|
| 8 |
+import netrc
|
|
| 8 | 9 |
|
| 9 | 10 |
from buildstream import Source, SourceError, Consistency
|
| 10 | 11 |
from buildstream import utils
|
| 11 | 12 |
|
| 12 | 13 |
|
| 14 |
+class _NetrcFTPOpener(urllib.request.FTPHandler):
|
|
| 15 |
+ |
|
| 16 |
+ def __init__(self, netrc_config):
|
|
| 17 |
+ self.netrc = netrc_config
|
|
| 18 |
+ |
|
| 19 |
+ def _split(self, netloc):
|
|
| 20 |
+ userpass, hostport = urllib.parse.splituser(netloc)
|
|
| 21 |
+ host, port = urllib.parse.splitport(hostport)
|
|
| 22 |
+ if userpass:
|
|
| 23 |
+ user, passwd = urllib.parse.splitpasswd(userpass)
|
|
| 24 |
+ else:
|
|
| 25 |
+ user = None
|
|
| 26 |
+ passwd = None
|
|
| 27 |
+ return host, port, user, passwd
|
|
| 28 |
+ |
|
| 29 |
+ def _unsplit(self, host, port, user, passwd):
|
|
| 30 |
+ if port:
|
|
| 31 |
+ host = '{}:{}'.format(host, port)
|
|
| 32 |
+ if user:
|
|
| 33 |
+ if passwd:
|
|
| 34 |
+ user = '{}:{}'.format(user, passwd)
|
|
| 35 |
+ host = '{}@{}'.format(user, host)
|
|
| 36 |
+ |
|
| 37 |
+ return host
|
|
| 38 |
+ |
|
| 39 |
+ def ftp_open(self, req):
|
|
| 40 |
+ host, port, user, passwd = self._split(req.host)
|
|
| 41 |
+ |
|
| 42 |
+ if user is None and self.netrc:
|
|
| 43 |
+ entry = self.netrc.authenticators(host)
|
|
| 44 |
+ if entry:
|
|
| 45 |
+ user, _, passwd = entry
|
|
| 46 |
+ |
|
| 47 |
+ req.host = self._unsplit(host, port, user, passwd)
|
|
| 48 |
+ |
|
| 49 |
+ return super().ftp_open(req)
|
|
| 50 |
+ |
|
| 51 |
+ |
|
| 52 |
+class _NetrcPasswordManager:
|
|
| 53 |
+ |
|
| 54 |
+ def __init__(self, netrc_config):
|
|
| 55 |
+ self.netrc = netrc_config
|
|
| 56 |
+ |
|
| 57 |
+ def add_password(self, realm, uri, user, passwd):
|
|
| 58 |
+ pass
|
|
| 59 |
+ |
|
| 60 |
+ def find_user_password(self, realm, authuri):
|
|
| 61 |
+ if not self.netrc:
|
|
| 62 |
+ return None, None
|
|
| 63 |
+ parts = urllib.parse.urlsplit(authuri)
|
|
| 64 |
+ entry = self.netrc.authenticators(parts.hostname)
|
|
| 65 |
+ if not entry:
|
|
| 66 |
+ return None, None
|
|
| 67 |
+ else:
|
|
| 68 |
+ login, _, password = entry
|
|
| 69 |
+ return login, password
|
|
| 70 |
+ |
|
| 71 |
+ |
|
| 13 | 72 |
class DownloadableFileSource(Source):
|
| 14 | 73 |
# pylint: disable=attribute-defined-outside-init
|
| 15 | 74 |
|
| 16 | 75 |
COMMON_CONFIG_KEYS = Source.COMMON_CONFIG_KEYS + ['url', 'ref', 'etag']
|
| 17 | 76 |
|
| 77 |
+ __urlopener = None
|
|
| 78 |
+ |
|
| 18 | 79 |
def configure(self, node):
|
| 19 | 80 |
self.original_url = self.node_get_member(node, str, 'url')
|
| 20 | 81 |
self.ref = self.node_get_member(node, str, 'ref', None)
|
| ... | ... | @@ -118,7 +179,8 @@ class DownloadableFileSource(Source): |
| 118 | 179 |
if etag and self.get_consistency() == Consistency.CACHED:
|
| 119 | 180 |
request.add_header('If-None-Match', etag)
|
| 120 | 181 |
|
| 121 |
- with contextlib.closing(urllib.request.urlopen(request)) as response:
|
|
| 182 |
+ opener = self.__get_urlopener()
|
|
| 183 |
+ with contextlib.closing(opener.open(request)) as response:
|
|
| 122 | 184 |
info = response.info()
|
| 123 | 185 |
|
| 124 | 186 |
etag = info['ETag'] if 'ETag' in info else None
|
| ... | ... | @@ -164,3 +226,19 @@ class DownloadableFileSource(Source): |
| 164 | 226 |
|
| 165 | 227 |
def _get_mirror_file(self, sha=None):
|
| 166 | 228 |
return os.path.join(self._get_mirror_dir(), sha or self.ref)
|
| 229 |
+ |
|
| 230 |
+ def __get_urlopener(self):
|
|
| 231 |
+ if not DownloadableFileSource.__urlopener:
|
|
| 232 |
+ try:
|
|
| 233 |
+ netrc_config = netrc.netrc()
|
|
| 234 |
+ except FileNotFoundError:
|
|
| 235 |
+ DownloadableFileSource.__urlopener = urllib.request.build_opener()
|
|
| 236 |
+ except netrc.NetrcParseError as e:
|
|
| 237 |
+ self.warn('{}: While reading .netrc: {}'.format(self, e))
|
|
| 238 |
+ return urllib.request.build_opener()
|
|
| 239 |
+ else:
|
|
| 240 |
+ netrc_pw_mgr = _NetrcPasswordManager(netrc_config)
|
|
| 241 |
+ http_auth = urllib.request.HTTPBasicAuthHandler(netrc_pw_mgr)
|
|
| 242 |
+ ftp_handler = _NetrcFTPOpener(netrc_config)
|
|
| 243 |
+ DownloadableFileSource.__urlopener = urllib.request.build_opener(http_auth, ftp_handler)
|
|
| 244 |
+ return DownloadableFileSource.__urlopener
|
| ... | ... | @@ -9,3 +9,4 @@ pytest-pep8 |
| 9 | 9 |
pytest-pylint
|
| 10 | 10 |
pytest-xdist
|
| 11 | 11 |
pytest-timeout
|
| 12 |
+pyftpdlib
|
| 1 |
+.TH "BST-ARTIFACT-SERVER" "1" "29-Nov-2018" "" "bst-artifact-server Manual"
|
|
| 2 |
+.SH NAME
|
|
| 3 |
+bst-artifact-server \- CAS Artifact Server
|
|
| 4 |
+.SH SYNOPSIS
|
|
| 5 |
+.B bst-artifact-server
|
|
| 6 |
+[OPTIONS] REPO
|
|
| 7 |
+.SH OPTIONS
|
|
| 8 |
+.TP
|
|
| 9 |
+\fB\-p,\fP \-\-port INTEGER
|
|
| 10 |
+Port number [required]
|
|
| 11 |
+.TP
|
|
| 12 |
+\fB\-\-server\-key\fP TEXT
|
|
| 13 |
+Private server key for TLS (PEM-encoded)
|
|
| 14 |
+.TP
|
|
| 15 |
+\fB\-\-server\-cert\fP TEXT
|
|
| 16 |
+Public server certificate for TLS (PEM-encoded)
|
|
| 17 |
+.TP
|
|
| 18 |
+\fB\-\-client\-certs\fP TEXT
|
|
| 19 |
+Public client certificates for TLS (PEM-encoded)
|
|
| 20 |
+.TP
|
|
| 21 |
+\fB\-\-enable\-push\fP
|
|
| 22 |
+Allow clients to upload blobs and update artifact cache
|
|
| \ No newline at end of file |
| 1 |
-.TH "BST BUILD" "1" "26-Apr-2018" "" "bst build Manual"
|
|
| 1 |
+.TH "BST BUILD" "1" "29-Nov-2018" "" "bst build Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-build \- Build elements in a pipeline
|
| 4 | 4 |
.SH SYNOPSIS
|
| 1 |
-.TH "BST CHECKOUT" "1" "26-Apr-2018" "" "bst checkout Manual"
|
|
| 1 |
+.TH "BST CHECKOUT" "1" "29-Nov-2018" "" "bst checkout Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-checkout \- Checkout a built artifact
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -12,7 +12,7 @@ Checkout a built artifact to the specified location |
| 12 | 12 |
\fB\-f,\fP \-\-force
|
| 13 | 13 |
Allow files to be overwritten
|
| 14 | 14 |
.TP
|
| 15 |
-\fB\-f,\fP \-\-deps
|
|
| 15 |
+\fB\-d,\fP \-\-deps [run|none]
|
|
| 16 | 16 |
The dependencies to checkout (default: run)
|
| 17 | 17 |
.TP
|
| 18 | 18 |
\fB\-\-integrate\fP / \-\-no\-integrate
|
| ... | ... | @@ -22,5 +22,4 @@ Whether to run integration commands |
| 22 | 22 |
Checkout hardlinks instead of copies (handle with care)
|
| 23 | 23 |
.TP
|
| 24 | 24 |
\fB\-\-tar\fP
|
| 25 |
-Create a tarball from the artifact contents instead of a file tree. If
|
|
| 26 |
-LOCATION is '-', the tarball will be dumped to the standard output.
|
|
| 25 |
+Create a tarball from the artifact contents instead of a file tree. If LOCATION is '-', the tarball will be dumped to the standard output.
|
|
| \ No newline at end of file |
| 1 |
-.TH "BST FETCH" "1" "26-Apr-2018" "" "bst fetch Manual"
|
|
| 1 |
+.TH "BST FETCH" "1" "29-Nov-2018" "" "bst fetch Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-fetch \- Fetch sources in a pipeline
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -6,14 +6,14 @@ bst\-fetch \- Fetch sources in a pipeline |
| 6 | 6 |
[OPTIONS] [ELEMENTS]...
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Fetch sources required to build the pipeline
|
| 9 |
- |
|
| 9 |
+.PP
|
|
| 10 | 10 |
By default this will only try to fetch sources which are
|
| 11 | 11 |
required for the build plan of the specified target element,
|
| 12 | 12 |
omitting sources for any elements which are already built
|
| 13 | 13 |
and available in the artifact cache.
|
| 14 |
- |
|
| 14 |
+.PP
|
|
| 15 | 15 |
Specify `--deps` to control which sources to fetch:
|
| 16 |
- |
|
| 16 |
+.PP
|
|
| 17 | 17 |
|
| 18 | 18 |
none: No dependencies, just the element itself
|
| 19 | 19 |
plan: Only dependencies required for the build plan
|
| 1 |
+.TH "BST HELP" "1" "29-Nov-2018" "" "bst help Manual"
|
|
| 2 |
+.SH NAME
|
|
| 3 |
+bst\-help \- Print usage information
|
|
| 4 |
+.SH SYNOPSIS
|
|
| 5 |
+.B bst help
|
|
| 6 |
+[OPTIONS] COMMAND
|
|
| 7 |
+.SH DESCRIPTION
|
|
| 8 |
+Print usage information about a given command
|
|
| 9 |
+
|
|
| \ No newline at end of file |
| 1 |
-.TH "BST INIT" "1" "26-Apr-2018" "" "bst init Manual"
|
|
| 1 |
+.TH "BST INIT" "1" "29-Nov-2018" "" "bst init Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-init \- Initialize a new BuildStream project
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -6,10 +6,10 @@ bst\-init \- Initialize a new BuildStream project |
| 6 | 6 |
[OPTIONS]
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Initialize a new BuildStream project
|
| 9 |
- |
|
| 9 |
+.PP
|
|
| 10 | 10 |
Creates a new BuildStream project.conf in the project
|
| 11 | 11 |
directory.
|
| 12 |
- |
|
| 12 |
+.PP
|
|
| 13 | 13 |
Unless `--project-name` is specified, this will be an
|
| 14 | 14 |
interactive session.
|
| 15 | 15 |
.SH OPTIONS
|
| ... | ... | @@ -18,7 +18,7 @@ interactive session. |
| 18 | 18 |
The project name to use
|
| 19 | 19 |
.TP
|
| 20 | 20 |
\fB\-\-format\-version\fP INTEGER
|
| 21 |
-The required format version (default: 8)
|
|
| 21 |
+The required format version (default: 18)
|
|
| 22 | 22 |
.TP
|
| 23 | 23 |
\fB\-\-element\-path\fP PATH
|
| 24 | 24 |
The subdirectory to store elements in (default: elements)
|
| 1 |
-.TH "BST PULL" "1" "26-Apr-2018" "" "bst pull Manual"
|
|
| 1 |
+.TH "BST PULL" "1" "29-Nov-2018" "" "bst pull Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-pull \- Pull a built artifact
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -6,13 +6,13 @@ bst\-pull \- Pull a built artifact |
| 6 | 6 |
[OPTIONS] [ELEMENTS]...
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Pull a built artifact from the configured remote artifact cache.
|
| 9 |
- |
|
| 9 |
+.PP
|
|
| 10 | 10 |
By default the artifact will be pulled one of the configured caches
|
| 11 | 11 |
if possible, following the usual priority order. If the `--remote` flag
|
| 12 | 12 |
is given, only the specified cache will be queried.
|
| 13 |
- |
|
| 13 |
+.PP
|
|
| 14 | 14 |
Specify `--deps` to control which artifacts to pull:
|
| 15 |
- |
|
| 15 |
+.PP
|
|
| 16 | 16 |
|
| 17 | 17 |
none: No dependencies, just the element itself
|
| 18 | 18 |
all: All dependencies
|
| 1 |
-.TH "BST PUSH" "1" "26-Apr-2018" "" "bst push Manual"
|
|
| 1 |
+.TH "BST PUSH" "1" "29-Nov-2018" "" "bst push Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-push \- Push a built artifact
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -6,12 +6,12 @@ bst\-push \- Push a built artifact |
| 6 | 6 |
[OPTIONS] [ELEMENTS]...
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Push a built artifact to a remote artifact cache.
|
| 9 |
- |
|
| 9 |
+.PP
|
|
| 10 | 10 |
The default destination is the highest priority configured cache. You can
|
| 11 | 11 |
override this by passing a different cache URL with the `--remote` flag.
|
| 12 |
- |
|
| 12 |
+.PP
|
|
| 13 | 13 |
Specify `--deps` to control which artifacts to push:
|
| 14 |
- |
|
| 14 |
+.PP
|
|
| 15 | 15 |
|
| 16 | 16 |
none: No dependencies, just the element itself
|
| 17 | 17 |
all: All dependencies
|
| 1 |
-.TH "BST SHELL" "1" "26-Apr-2018" "" "bst shell Manual"
|
|
| 1 |
+.TH "BST SHELL" "1" "29-Nov-2018" "" "bst shell Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-shell \- Shell into an element's sandbox environment
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -6,18 +6,18 @@ bst\-shell \- Shell into an element's sandbox environment |
| 6 | 6 |
[OPTIONS] ELEMENT [COMMAND]...
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Run a command in the target element's sandbox environment
|
| 9 |
- |
|
| 9 |
+.PP
|
|
| 10 | 10 |
This will stage a temporary sysroot for running the target
|
| 11 | 11 |
element, assuming it has already been built and all required
|
| 12 | 12 |
artifacts are in the local cache.
|
| 13 |
- |
|
| 13 |
+.PP
|
|
| 14 | 14 |
Use the --build option to create a temporary sysroot for
|
| 15 | 15 |
building the element instead.
|
| 16 |
- |
|
| 16 |
+.PP
|
|
| 17 | 17 |
Use the --sysroot option with an existing failed build
|
| 18 | 18 |
directory or with a checkout of the given target, in order
|
| 19 | 19 |
to use a specific sysroot.
|
| 20 |
- |
|
| 20 |
+.PP
|
|
| 21 | 21 |
If no COMMAND is specified, the default is to attempt
|
| 22 | 22 |
to run an interactive shell.
|
| 23 | 23 |
.SH OPTIONS
|
| 1 |
-.TH "BST SHOW" "1" "26-Apr-2018" "" "bst show Manual"
|
|
| 1 |
+.TH "BST SHOW" "1" "29-Nov-2018" "" "bst show Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-show \- Show elements in the pipeline
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -6,25 +6,25 @@ bst\-show \- Show elements in the pipeline |
| 6 | 6 |
[OPTIONS] [ELEMENTS]...
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Show elements in the pipeline
|
| 9 |
- |
|
| 9 |
+.PP
|
|
| 10 | 10 |
By default this will show all of the dependencies of the
|
| 11 | 11 |
specified target element.
|
| 12 |
- |
|
| 12 |
+.PP
|
|
| 13 | 13 |
Specify `--deps` to control which elements to show:
|
| 14 |
- |
|
| 14 |
+.PP
|
|
| 15 | 15 |
|
| 16 | 16 |
none: No dependencies, just the element itself
|
| 17 | 17 |
plan: Dependencies required for a build plan
|
| 18 | 18 |
run: Runtime dependencies, including the element itself
|
| 19 | 19 |
build: Build time dependencies, excluding the element itself
|
| 20 | 20 |
all: All dependencies
|
| 21 |
- |
|
| 21 |
+.PP
|
|
| 22 | 22 |
|
| 23 | 23 |
FORMAT
|
| 24 | 24 |
~~~~~~
|
| 25 | 25 |
The --format option controls what should be printed for each element,
|
| 26 | 26 |
the following symbols can be used in the format string:
|
| 27 |
- |
|
| 27 |
+.PP
|
|
| 28 | 28 |
|
| 29 | 29 |
%{name} The element name
|
| 30 | 30 |
%{key} The abbreviated cache key (if all sources are consistent)
|
| ... | ... | @@ -36,17 +36,17 @@ the following symbols can be used in the format string: |
| 36 | 36 |
%{public} Public domain data
|
| 37 | 37 |
%{workspaced} If the element is workspaced
|
| 38 | 38 |
%{workspace-dirs} A list of workspace directories
|
| 39 |
- |
|
| 39 |
+.PP
|
|
| 40 | 40 |
The value of the %{symbol} without the leading '%' character is understood
|
| 41 | 41 |
as a pythonic formatting string, so python formatting features apply,
|
| 42 | 42 |
examle:
|
| 43 |
- |
|
| 43 |
+.PP
|
|
| 44 | 44 |
|
| 45 | 45 |
bst show target.bst --format \
|
| 46 | 46 |
'Name: %{name: ^20} Key: %{key: ^8} State: %{state}'
|
| 47 |
- |
|
| 47 |
+.PP
|
|
| 48 | 48 |
If you want to use a newline in a format string in bash, use the '$' modifier:
|
| 49 |
- |
|
| 49 |
+.PP
|
|
| 50 | 50 |
|
| 51 | 51 |
bst show target.bst --format \
|
| 52 | 52 |
$'---------- %{name} ----------\n%{vars}'
|
| ... | ... | @@ -62,7 +62,4 @@ The dependencies to show (default: all) |
| 62 | 62 |
Staging or alphabetic ordering of dependencies
|
| 63 | 63 |
.TP
|
| 64 | 64 |
\fB\-f,\fP \-\-format FORMAT
|
| 65 |
-Format string for each element
|
|
| 66 |
-.TP
|
|
| 67 |
-\fB\-\-downloadable\fP
|
|
| 68 |
-Refresh downloadable state
|
|
| \ No newline at end of file | ||
| 65 |
+Format string for each element
|
|
| \ No newline at end of file |
| 1 |
-.TH "BST SOURCE-BUNDLE" "1" "26-Apr-2018" "" "bst source-bundle Manual"
|
|
| 1 |
+.TH "BST SOURCE-BUNDLE" "1" "29-Nov-2018" "" "bst source-bundle Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-source-bundle \- Produce a build bundle to be manually executed
|
| 4 | 4 |
.SH SYNOPSIS
|
| 5 | 5 |
.B bst source-bundle
|
| 6 |
-[OPTIONS] TARGET
|
|
| 6 |
+[OPTIONS] ELEMENT
|
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Produce a source bundle to be manually executed
|
| 9 | 9 |
|
| ... | ... | @@ -16,10 +16,10 @@ Elements to except from the tarball |
| 16 | 16 |
Compress the tar file using the given algorithm.
|
| 17 | 17 |
.TP
|
| 18 | 18 |
\fB\-\-track\fP
|
| 19 |
-Track new source references before building
|
|
| 19 |
+Track new source references before bundling
|
|
| 20 | 20 |
.TP
|
| 21 | 21 |
\fB\-f,\fP \-\-force
|
| 22 |
-Overwrite files existing in checkout directory
|
|
| 22 |
+Overwrite an existing tarball
|
|
| 23 | 23 |
.TP
|
| 24 | 24 |
\fB\-\-directory\fP TEXT
|
| 25 | 25 |
The directory to write the tarball to
|
| \ No newline at end of file |
| 1 |
+.TH "BST SOURCE-CHECKOUT" "1" "29-Nov-2018" "" "bst source-checkout Manual"
|
|
| 2 |
+.SH NAME
|
|
| 3 |
+bst\-source-checkout \- Checkout sources for an element
|
|
| 4 |
+.SH SYNOPSIS
|
|
| 5 |
+.B bst source-checkout
|
|
| 6 |
+[OPTIONS] ELEMENT LOCATION
|
|
| 7 |
+.SH DESCRIPTION
|
|
| 8 |
+Checkout sources of an element to the specified location
|
|
| 9 |
+
|
|
| 10 |
+.SH OPTIONS
|
|
| 11 |
+.TP
|
|
| 12 |
+\fB\-\-except\fP PATH
|
|
| 13 |
+Except certain dependencies
|
|
| 14 |
+.TP
|
|
| 15 |
+\fB\-d,\fP \-\-deps [build|none|run|all]
|
|
| 16 |
+The dependencies whose sources to checkout (default: none)
|
|
| 17 |
+.TP
|
|
| 18 |
+\fB\-\-fetch\fP
|
|
| 19 |
+Fetch elements if they are not fetched
|
|
| \ No newline at end of file |
| 1 |
-.TH "BST TRACK" "1" "26-Apr-2018" "" "bst track Manual"
|
|
| 1 |
+.TH "BST TRACK" "1" "29-Nov-2018" "" "bst track Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-track \- Track new source references
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -7,12 +7,12 @@ bst\-track \- Track new source references |
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Consults the specified tracking branches for new versions available
|
| 9 | 9 |
to build and updates the project with any newly available references.
|
| 10 |
- |
|
| 10 |
+.PP
|
|
| 11 | 11 |
By default this will track just the specified element, but you can also
|
| 12 | 12 |
update a whole tree of dependencies in one go.
|
| 13 |
- |
|
| 13 |
+.PP
|
|
| 14 | 14 |
Specify `--deps` to control which sources to track:
|
| 15 |
- |
|
| 15 |
+.PP
|
|
| 16 | 16 |
|
| 17 | 17 |
none: No dependencies, just the specified elements
|
| 18 | 18 |
all: All dependencies of all specified elements
|
| 1 |
-.TH "BST WORKSPACE CLOSE" "1" "26-Apr-2018" "" "bst workspace close Manual"
|
|
| 1 |
+.TH "BST WORKSPACE CLOSE" "1" "29-Nov-2018" "" "bst workspace close Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-workspace\-close \- Close workspaces
|
| 4 | 4 |
.SH SYNOPSIS
|
| 1 |
-.TH "BST WORKSPACE LIST" "1" "26-Apr-2018" "" "bst workspace list Manual"
|
|
| 1 |
+.TH "BST WORKSPACE LIST" "1" "29-Nov-2018" "" "bst workspace list Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-workspace\-list \- List open workspaces
|
| 4 | 4 |
.SH SYNOPSIS
|
| 5 | 5 |
.B bst workspace list
|
| 6 | 6 |
[OPTIONS]
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 |
-List open workspaces
|
|
| \ No newline at end of file | ||
| 8 |
+List open workspaces
|
| 1 |
-.TH "BST WORKSPACE OPEN" "1" "26-Apr-2018" "" "bst workspace open Manual"
|
|
| 1 |
+.TH "BST WORKSPACE OPEN" "1" "29-Nov-2018" "" "bst workspace open Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-workspace\-open \- Open a new workspace
|
| 4 | 4 |
.SH SYNOPSIS
|
| 5 | 5 |
.B bst workspace open
|
| 6 |
-[OPTIONS] ELEMENT DIRECTORY
|
|
| 6 |
+[OPTIONS] ELEMENTS...
|
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Open a workspace for manual source modification
|
| 9 | 9 |
.SH OPTIONS
|
| ... | ... | @@ -12,7 +12,10 @@ Open a workspace for manual source modification |
| 12 | 12 |
Do not checkout the source, only link to the given directory
|
| 13 | 13 |
.TP
|
| 14 | 14 |
\fB\-f,\fP \-\-force
|
| 15 |
-Overwrite files existing in checkout directory
|
|
| 15 |
+The workspace will be created even if the directory in which it will be created is not empty or if a workspace for that element already exists
|
|
| 16 | 16 |
.TP
|
| 17 | 17 |
\fB\-\-track\fP
|
| 18 |
-Track and fetch new source references before checking out the workspace
|
|
| \ No newline at end of file | ||
| 18 |
+Track and fetch new source references before checking out the workspace
|
|
| 19 |
+.TP
|
|
| 20 |
+\fB\-\-directory\fP DIRECTORY
|
|
| 21 |
+Only for use when a single Element is given: Set the directory to use to create the workspace
|
|
| \ No newline at end of file |
| 1 |
-.TH "BST WORKSPACE RESET" "1" "26-Apr-2018" "" "bst workspace reset Manual"
|
|
| 1 |
+.TH "BST WORKSPACE RESET" "1" "29-Nov-2018" "" "bst workspace reset Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-workspace\-reset \- Reset a workspace to its original state
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -8,6 +8,9 @@ bst\-workspace\-reset \- Reset a workspace to its original state |
| 8 | 8 |
Reset a workspace to its original state
|
| 9 | 9 |
.SH OPTIONS
|
| 10 | 10 |
.TP
|
| 11 |
+\fB\-\-soft\fP
|
|
| 12 |
+Reset workspace state without affecting its contents
|
|
| 13 |
+.TP
|
|
| 11 | 14 |
\fB\-\-track\fP
|
| 12 | 15 |
Track and fetch the latest source before resetting
|
| 13 | 16 |
.TP
|
| 1 |
-.TH "BST WORKSPACE" "1" "26-Apr-2018" "" "bst workspace Manual"
|
|
| 1 |
+.TH "BST WORKSPACE" "1" "29-Nov-2018" "" "bst workspace Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst\-workspace \- Manipulate developer workspaces
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -11,18 +11,15 @@ Manipulate developer workspaces |
| 11 | 11 |
\fBopen\fP
|
| 12 | 12 |
Open a new workspace
|
| 13 | 13 |
See \fBbst workspace-open(1)\fP for full documentation on the \fBopen\fP command.
|
| 14 |
- |
|
| 15 |
-.PP
|
|
| 16 |
-\fBlist\fP
|
|
| 17 |
- List open workspaces
|
|
| 18 |
- See \fBbst workspace-list(1)\fP for full documentation on the \fBlist\fP command.
|
|
| 19 |
- |
|
| 20 | 14 |
.PP
|
| 21 | 15 |
\fBclose\fP
|
| 22 | 16 |
Close workspaces
|
| 23 | 17 |
See \fBbst workspace-close(1)\fP for full documentation on the \fBclose\fP command.
|
| 24 |
- |
|
| 25 | 18 |
.PP
|
| 26 | 19 |
\fBreset\fP
|
| 27 | 20 |
Reset a workspace to its original state
|
| 28 | 21 |
See \fBbst workspace-reset(1)\fP for full documentation on the \fBreset\fP command.
|
| 22 |
+.PP
|
|
| 23 |
+\fBlist\fP
|
|
| 24 |
+ List open workspaces
|
|
| 25 |
+ See \fBbst workspace-list(1)\fP for full documentation on the \fBlist\fP command.
|
|
| \ No newline at end of file |
| 1 |
-.TH "BST" "1" "26-Apr-2018" "" "bst Manual"
|
|
| 1 |
+.TH "BST" "1" "29-Nov-2018" "" "bst Manual"
|
|
| 2 | 2 |
.SH NAME
|
| 3 | 3 |
bst \- Build and manipulate BuildStream projects...
|
| 4 | 4 |
.SH SYNOPSIS
|
| ... | ... | @@ -6,15 +6,15 @@ bst \- Build and manipulate BuildStream projects... |
| 6 | 6 |
[OPTIONS] COMMAND [ARGS]...
|
| 7 | 7 |
.SH DESCRIPTION
|
| 8 | 8 |
Build and manipulate BuildStream projects
|
| 9 |
- |
|
| 9 |
+.PP
|
|
| 10 | 10 |
Most of the main options override options in the
|
| 11 | 11 |
user preferences configuration file.
|
| 12 | 12 |
.SH OPTIONS
|
| 13 | 13 |
.TP
|
| 14 | 14 |
\fB\-\-version\fP
|
| 15 |
- |
|
| 15 |
+.PP
|
|
| 16 | 16 |
.TP
|
| 17 |
-\fB\-c,\fP \-\-config PATH
|
|
| 17 |
+\fB\-c,\fP \-\-config FILE
|
|
| 18 | 18 |
Configuration file to use
|
| 19 | 19 |
.TP
|
| 20 | 20 |
\fB\-C,\fP \-\-directory DIRECTORY
|
| ... | ... | @@ -61,58 +61,62 @@ Elements must be rebuilt when their dependencies have changed |
| 61 | 61 |
.TP
|
| 62 | 62 |
\fB\-o,\fP \-\-option OPTION VALUE
|
| 63 | 63 |
Specify a project option
|
| 64 |
+.TP
|
|
| 65 |
+\fB\-\-default\-mirror\fP TEXT
|
|
| 66 |
+The mirror to fetch from first, before attempting other mirrors
|
|
| 67 |
+.TP
|
|
| 68 |
+\fB\-\-pull\-buildtrees\fP
|
|
| 69 |
+Include an element's build tree when pulling remote element artifacts
|
|
| 64 | 70 |
.SH COMMANDS
|
| 65 | 71 |
.PP
|
| 66 |
-\fBcheckout\fP
|
|
| 67 |
- Checkout a built artifact
|
|
| 68 |
- See \fBbst-checkout(1)\fP for full documentation on the \fBcheckout\fP command.
|
|
| 69 |
- |
|
| 70 |
-.PP
|
|
| 71 |
-\fBfetch\fP
|
|
| 72 |
- Fetch sources in a pipeline
|
|
| 73 |
- See \fBbst-fetch(1)\fP for full documentation on the \fBfetch\fP command.
|
|
| 74 |
- |
|
| 75 |
-.PP
|
|
| 76 |
-\fBsource-bundle\fP
|
|
| 77 |
- Produce a build bundle to be manually executed
|
|
| 78 |
- See \fBbst-source-bundle(1)\fP for full documentation on the \fBsource-bundle\fP command.
|
|
| 79 |
- |
|
| 80 |
-.PP
|
|
| 81 |
-\fBshow\fP
|
|
| 82 |
- Show elements in the pipeline
|
|
| 83 |
- See \fBbst-show(1)\fP for full documentation on the \fBshow\fP command.
|
|
| 84 |
- |
|
| 85 |
-.PP
|
|
| 86 |
-\fBworkspace\fP
|
|
| 87 |
- Manipulate developer workspaces
|
|
| 88 |
- See \fBbst-workspace(1)\fP for full documentation on the \fBworkspace\fP command.
|
|
| 89 |
- |
|
| 90 |
-.PP
|
|
| 91 |
-\fBtrack\fP
|
|
| 92 |
- Track new source references
|
|
| 93 |
- See \fBbst-track(1)\fP for full documentation on the \fBtrack\fP command.
|
|
| 94 |
- |
|
| 72 |
+\fBhelp\fP
|
|
| 73 |
+ Print usage information
|
|
| 74 |
+ See \fBbst-help(1)\fP for full documentation on the \fBhelp\fP command.
|
|
| 95 | 75 |
.PP
|
| 96 | 76 |
\fBinit\fP
|
| 97 | 77 |
Initialize a new BuildStream project
|
| 98 | 78 |
See \fBbst-init(1)\fP for full documentation on the \fBinit\fP command.
|
| 99 |
- |
|
| 100 |
-.PP
|
|
| 101 |
-\fBshell\fP
|
|
| 102 |
- Shell into an element's sandbox environment
|
|
| 103 |
- See \fBbst-shell(1)\fP for full documentation on the \fBshell\fP command.
|
|
| 104 |
- |
|
| 105 | 79 |
.PP
|
| 106 | 80 |
\fBbuild\fP
|
| 107 | 81 |
Build elements in a pipeline
|
| 108 | 82 |
See \fBbst-build(1)\fP for full documentation on the \fBbuild\fP command.
|
| 109 |
- |
|
| 83 |
+.PP
|
|
| 84 |
+\fBfetch\fP
|
|
| 85 |
+ Fetch sources in a pipeline
|
|
| 86 |
+ See \fBbst-fetch(1)\fP for full documentation on the \fBfetch\fP command.
|
|
| 87 |
+.PP
|
|
| 88 |
+\fBtrack\fP
|
|
| 89 |
+ Track new source references
|
|
| 90 |
+ See \fBbst-track(1)\fP for full documentation on the \fBtrack\fP command.
|
|
| 110 | 91 |
.PP
|
| 111 | 92 |
\fBpull\fP
|
| 112 | 93 |
Pull a built artifact
|
| 113 | 94 |
See \fBbst-pull(1)\fP for full documentation on the \fBpull\fP command.
|
| 114 |
- |
|
| 115 | 95 |
.PP
|
| 116 | 96 |
\fBpush\fP
|
| 117 | 97 |
Push a built artifact
|
| 118 | 98 |
See \fBbst-push(1)\fP for full documentation on the \fBpush\fP command.
|
| 99 |
+.PP
|
|
| 100 |
+\fBshow\fP
|
|
| 101 |
+ Show elements in the pipeline
|
|
| 102 |
+ See \fBbst-show(1)\fP for full documentation on the \fBshow\fP command.
|
|
| 103 |
+.PP
|
|
| 104 |
+\fBshell\fP
|
|
| 105 |
+ Shell into an element's sandbox environment
|
|
| 106 |
+ See \fBbst-shell(1)\fP for full documentation on the \fBshell\fP command.
|
|
| 107 |
+.PP
|
|
| 108 |
+\fBcheckout\fP
|
|
| 109 |
+ Checkout a built artifact
|
|
| 110 |
+ See \fBbst-checkout(1)\fP for full documentation on the \fBcheckout\fP command.
|
|
| 111 |
+.PP
|
|
| 112 |
+\fBsource-checkout\fP
|
|
| 113 |
+ Checkout sources for an element
|
|
| 114 |
+ See \fBbst-source-checkout(1)\fP for full documentation on the \fBsource-checkout\fP command.
|
|
| 115 |
+.PP
|
|
| 116 |
+\fBworkspace\fP
|
|
| 117 |
+ Manipulate developer workspaces
|
|
| 118 |
+ See \fBbst-workspace(1)\fP for full documentation on the \fBworkspace\fP command.
|
|
| 119 |
+.PP
|
|
| 120 |
+\fBsource-bundle\fP
|
|
| 121 |
+ Produce a build bundle to be manually executed
|
|
| 122 |
+ See \fBbst-source-bundle(1)\fP for full documentation on the \fBsource-bundle\fP command.
|
|
| \ No newline at end of file |
| ... | ... | @@ -5,6 +5,7 @@ import pytest |
| 5 | 5 |
from buildstream._exceptions import ErrorDomain
|
| 6 | 6 |
from buildstream import _yaml
|
| 7 | 7 |
from tests.testutils import cli
|
| 8 |
+from tests.testutils.file_server import create_file_server
|
|
| 8 | 9 |
|
| 9 | 10 |
DATA_DIR = os.path.join(
|
| 10 | 11 |
os.path.dirname(os.path.realpath(__file__)),
|
| ... | ... | @@ -22,6 +23,16 @@ def generate_project(project_dir, tmpdir): |
| 22 | 23 |
}, project_file)
|
| 23 | 24 |
|
| 24 | 25 |
|
| 26 |
+def generate_project_file_server(server, project_dir):
|
|
| 27 |
+ project_file = os.path.join(project_dir, "project.conf")
|
|
| 28 |
+ _yaml.dump({
|
|
| 29 |
+ 'name': 'foo',
|
|
| 30 |
+ 'aliases': {
|
|
| 31 |
+ 'tmpdir': server.base_url()
|
|
| 32 |
+ }
|
|
| 33 |
+ }, project_file)
|
|
| 34 |
+ |
|
| 35 |
+ |
|
| 25 | 36 |
# Test that without ref, consistency is set appropriately.
|
| 26 | 37 |
@pytest.mark.datafiles(os.path.join(DATA_DIR, 'no-ref'))
|
| 27 | 38 |
def test_no_ref(cli, tmpdir, datafiles):
|
| ... | ... | @@ -164,3 +175,35 @@ def test_executable(cli, tmpdir, datafiles): |
| 164 | 175 |
assert (mode & stat.S_IEXEC)
|
| 165 | 176 |
# Assert executable by anyone
|
| 166 | 177 |
assert(mode & (stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH))
|
| 178 |
+ |
|
| 179 |
+ |
|
| 180 |
+@pytest.mark.parametrize('server_type', ('FTP', 'HTTP'))
|
|
| 181 |
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'single-file'))
|
|
| 182 |
+def test_use_netrc(cli, datafiles, server_type, tmpdir):
|
|
| 183 |
+ fake_home = os.path.join(str(tmpdir), 'fake_home')
|
|
| 184 |
+ os.makedirs(fake_home, exist_ok=True)
|
|
| 185 |
+ project = str(datafiles)
|
|
| 186 |
+ checkoutdir = os.path.join(str(tmpdir), 'checkout')
|
|
| 187 |
+ |
|
| 188 |
+ os.environ['HOME'] = fake_home
|
|
| 189 |
+ with open(os.path.join(fake_home, '.netrc'), 'wb') as f:
|
|
| 190 |
+ os.fchmod(f.fileno(), 0o700)
|
|
| 191 |
+ f.write(b'machine 127.0.0.1\n')
|
|
| 192 |
+ f.write(b'login testuser\n')
|
|
| 193 |
+ f.write(b'password 12345\n')
|
|
| 194 |
+ |
|
| 195 |
+ with create_file_server(server_type) as server:
|
|
| 196 |
+ server.add_user('testuser', '12345', project)
|
|
| 197 |
+ generate_project_file_server(server, project)
|
|
| 198 |
+ |
|
| 199 |
+ server.start()
|
|
| 200 |
+ |
|
| 201 |
+ result = cli.run(project=project, args=['fetch', 'target.bst'])
|
|
| 202 |
+ result.assert_success()
|
|
| 203 |
+ result = cli.run(project=project, args=['build', 'target.bst'])
|
|
| 204 |
+ result.assert_success()
|
|
| 205 |
+ result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir])
|
|
| 206 |
+ result.assert_success()
|
|
| 207 |
+ |
|
| 208 |
+ checkout_file = os.path.join(checkoutdir, 'file')
|
|
| 209 |
+ assert(os.path.exists(checkout_file))
|
| ... | ... | @@ -3,11 +3,13 @@ import pytest |
| 3 | 3 |
import tarfile
|
| 4 | 4 |
import tempfile
|
| 5 | 5 |
import subprocess
|
| 6 |
+import urllib.parse
|
|
| 6 | 7 |
from shutil import copyfile, rmtree
|
| 7 | 8 |
|
| 8 | 9 |
from buildstream._exceptions import ErrorDomain
|
| 9 | 10 |
from buildstream import _yaml
|
| 10 | 11 |
from tests.testutils import cli
|
| 12 |
+from tests.testutils.file_server import create_file_server
|
|
| 11 | 13 |
from tests.testutils.site import HAVE_LZIP
|
| 12 | 14 |
from . import list_dir_contents
|
| 13 | 15 |
|
| ... | ... | @@ -49,6 +51,16 @@ def generate_project(project_dir, tmpdir): |
| 49 | 51 |
}, project_file)
|
| 50 | 52 |
|
| 51 | 53 |
|
| 54 |
+def generate_project_file_server(base_url, project_dir):
|
|
| 55 |
+ project_file = os.path.join(project_dir, "project.conf")
|
|
| 56 |
+ _yaml.dump({
|
|
| 57 |
+ 'name': 'foo',
|
|
| 58 |
+ 'aliases': {
|
|
| 59 |
+ 'tmpdir': base_url
|
|
| 60 |
+ }
|
|
| 61 |
+ }, project_file)
|
|
| 62 |
+ |
|
| 63 |
+ |
|
| 52 | 64 |
# Test that without ref, consistency is set appropriately.
|
| 53 | 65 |
@pytest.mark.datafiles(os.path.join(DATA_DIR, 'no-ref'))
|
| 54 | 66 |
def test_no_ref(cli, tmpdir, datafiles):
|
| ... | ... | @@ -302,3 +314,77 @@ def test_read_only_dir(cli, tmpdir, datafiles): |
| 302 | 314 |
else:
|
| 303 | 315 |
os.remove(path)
|
| 304 | 316 |
rmtree(str(tmpdir), onerror=make_dir_writable)
|
| 317 |
+ |
|
| 318 |
+ |
|
| 319 |
+@pytest.mark.parametrize('server_type', ('FTP', 'HTTP'))
|
|
| 320 |
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'fetch'))
|
|
| 321 |
+def test_use_netrc(cli, datafiles, server_type, tmpdir):
|
|
| 322 |
+ file_server_files = os.path.join(str(tmpdir), 'file_server')
|
|
| 323 |
+ fake_home = os.path.join(str(tmpdir), 'fake_home')
|
|
| 324 |
+ os.makedirs(file_server_files, exist_ok=True)
|
|
| 325 |
+ os.makedirs(fake_home, exist_ok=True)
|
|
| 326 |
+ project = str(datafiles)
|
|
| 327 |
+ checkoutdir = os.path.join(str(tmpdir), 'checkout')
|
|
| 328 |
+ |
|
| 329 |
+ os.environ['HOME'] = fake_home
|
|
| 330 |
+ with open(os.path.join(fake_home, '.netrc'), 'wb') as f:
|
|
| 331 |
+ os.fchmod(f.fileno(), 0o700)
|
|
| 332 |
+ f.write(b'machine 127.0.0.1\n')
|
|
| 333 |
+ f.write(b'login testuser\n')
|
|
| 334 |
+ f.write(b'password 12345\n')
|
|
| 335 |
+ |
|
| 336 |
+ with create_file_server(server_type) as server:
|
|
| 337 |
+ server.add_user('testuser', '12345', file_server_files)
|
|
| 338 |
+ generate_project_file_server(server.base_url(), project)
|
|
| 339 |
+ |
|
| 340 |
+ src_tar = os.path.join(file_server_files, 'a.tar.gz')
|
|
| 341 |
+ _assemble_tar(os.path.join(str(datafiles), 'content'), 'a', src_tar)
|
|
| 342 |
+ |
|
| 343 |
+ server.start()
|
|
| 344 |
+ |
|
| 345 |
+ result = cli.run(project=project, args=['track', 'target.bst'])
|
|
| 346 |
+ result.assert_success()
|
|
| 347 |
+ result = cli.run(project=project, args=['fetch', 'target.bst'])
|
|
| 348 |
+ result.assert_success()
|
|
| 349 |
+ result = cli.run(project=project, args=['build', 'target.bst'])
|
|
| 350 |
+ result.assert_success()
|
|
| 351 |
+ result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir])
|
|
| 352 |
+ result.assert_success()
|
|
| 353 |
+ |
|
| 354 |
+ original_dir = os.path.join(str(datafiles), 'content', 'a')
|
|
| 355 |
+ original_contents = list_dir_contents(original_dir)
|
|
| 356 |
+ checkout_contents = list_dir_contents(checkoutdir)
|
|
| 357 |
+ assert(checkout_contents == original_contents)
|
|
| 358 |
+ |
|
| 359 |
+ |
|
| 360 |
+@pytest.mark.parametrize('server_type', ('FTP', 'HTTP'))
|
|
| 361 |
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'fetch'))
|
|
| 362 |
+def test_netrc_already_specified_user(cli, datafiles, server_type, tmpdir):
|
|
| 363 |
+ file_server_files = os.path.join(str(tmpdir), 'file_server')
|
|
| 364 |
+ fake_home = os.path.join(str(tmpdir), 'fake_home')
|
|
| 365 |
+ os.makedirs(file_server_files, exist_ok=True)
|
|
| 366 |
+ os.makedirs(fake_home, exist_ok=True)
|
|
| 367 |
+ project = str(datafiles)
|
|
| 368 |
+ checkoutdir = os.path.join(str(tmpdir), 'checkout')
|
|
| 369 |
+ |
|
| 370 |
+ os.environ['HOME'] = fake_home
|
|
| 371 |
+ with open(os.path.join(fake_home, '.netrc'), 'wb') as f:
|
|
| 372 |
+ os.fchmod(f.fileno(), 0o700)
|
|
| 373 |
+ f.write(b'machine 127.0.0.1\n')
|
|
| 374 |
+ f.write(b'login testuser\n')
|
|
| 375 |
+ f.write(b'password 12345\n')
|
|
| 376 |
+ |
|
| 377 |
+ with create_file_server(server_type) as server:
|
|
| 378 |
+ server.add_user('otheruser', '12345', file_server_files)
|
|
| 379 |
+ parts = urllib.parse.urlsplit(server.base_url())
|
|
| 380 |
+ base_url = urllib.parse.urlunsplit([parts[0]] + ['otheruser@{}'.format(parts[1])] + list(parts[2:]))
|
|
| 381 |
+ generate_project_file_server(base_url, project)
|
|
| 382 |
+ |
|
| 383 |
+ src_tar = os.path.join(file_server_files, 'a.tar.gz')
|
|
| 384 |
+ _assemble_tar(os.path.join(str(datafiles), 'content'), 'a', src_tar)
|
|
| 385 |
+ |
|
| 386 |
+ server.start()
|
|
| 387 |
+ |
|
| 388 |
+ result = cli.run(project=project, args=['track', 'target.bst'])
|
|
| 389 |
+ result.assert_main_error(ErrorDomain.STREAM, None)
|
|
| 390 |
+ result.assert_task_error(ErrorDomain.SOURCE, None)
|
| ... | ... | @@ -5,6 +5,7 @@ import zipfile |
| 5 | 5 |
from buildstream._exceptions import ErrorDomain
|
| 6 | 6 |
from buildstream import _yaml
|
| 7 | 7 |
from tests.testutils import cli
|
| 8 |
+from tests.testutils.file_server import create_file_server
|
|
| 8 | 9 |
from . import list_dir_contents
|
| 9 | 10 |
|
| 10 | 11 |
DATA_DIR = os.path.join(
|
| ... | ... | @@ -35,6 +36,16 @@ def generate_project(project_dir, tmpdir): |
| 35 | 36 |
}, project_file)
|
| 36 | 37 |
|
| 37 | 38 |
|
| 39 |
+def generate_project_file_server(server, project_dir):
|
|
| 40 |
+ project_file = os.path.join(project_dir, "project.conf")
|
|
| 41 |
+ _yaml.dump({
|
|
| 42 |
+ 'name': 'foo',
|
|
| 43 |
+ 'aliases': {
|
|
| 44 |
+ 'tmpdir': server.base_url()
|
|
| 45 |
+ }
|
|
| 46 |
+ }, project_file)
|
|
| 47 |
+ |
|
| 48 |
+ |
|
| 38 | 49 |
# Test that without ref, consistency is set appropriately.
|
| 39 | 50 |
@pytest.mark.datafiles(os.path.join(DATA_DIR, 'no-ref'))
|
| 40 | 51 |
def test_no_ref(cli, tmpdir, datafiles):
|
| ... | ... | @@ -176,3 +187,44 @@ def test_stage_explicit_basedir(cli, tmpdir, datafiles): |
| 176 | 187 |
original_contents = list_dir_contents(original_dir)
|
| 177 | 188 |
checkout_contents = list_dir_contents(checkoutdir)
|
| 178 | 189 |
assert(checkout_contents == original_contents)
|
| 190 |
+ |
|
| 191 |
+ |
|
| 192 |
+@pytest.mark.parametrize('server_type', ('FTP', 'HTTP'))
|
|
| 193 |
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'fetch'))
|
|
| 194 |
+def test_use_netrc(cli, datafiles, server_type, tmpdir):
|
|
| 195 |
+ file_server_files = os.path.join(str(tmpdir), 'file_server')
|
|
| 196 |
+ fake_home = os.path.join(str(tmpdir), 'fake_home')
|
|
| 197 |
+ os.makedirs(file_server_files, exist_ok=True)
|
|
| 198 |
+ os.makedirs(fake_home, exist_ok=True)
|
|
| 199 |
+ project = str(datafiles)
|
|
| 200 |
+ checkoutdir = os.path.join(str(tmpdir), 'checkout')
|
|
| 201 |
+ |
|
| 202 |
+ os.environ['HOME'] = fake_home
|
|
| 203 |
+ with open(os.path.join(fake_home, '.netrc'), 'wb') as f:
|
|
| 204 |
+ os.fchmod(f.fileno(), 0o700)
|
|
| 205 |
+ f.write(b'machine 127.0.0.1\n')
|
|
| 206 |
+ f.write(b'login testuser\n')
|
|
| 207 |
+ f.write(b'password 12345\n')
|
|
| 208 |
+ |
|
| 209 |
+ with create_file_server(server_type) as server:
|
|
| 210 |
+ server.add_user('testuser', '12345', file_server_files)
|
|
| 211 |
+ generate_project_file_server(server, project)
|
|
| 212 |
+ |
|
| 213 |
+ src_zip = os.path.join(file_server_files, 'a.zip')
|
|
| 214 |
+ _assemble_zip(os.path.join(str(datafiles), 'content'), src_zip)
|
|
| 215 |
+ |
|
| 216 |
+ server.start()
|
|
| 217 |
+ |
|
| 218 |
+ result = cli.run(project=project, args=['track', 'target.bst'])
|
|
| 219 |
+ result.assert_success()
|
|
| 220 |
+ result = cli.run(project=project, args=['fetch', 'target.bst'])
|
|
| 221 |
+ result.assert_success()
|
|
| 222 |
+ result = cli.run(project=project, args=['build', 'target.bst'])
|
|
| 223 |
+ result.assert_success()
|
|
| 224 |
+ result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir])
|
|
| 225 |
+ result.assert_success()
|
|
| 226 |
+ |
|
| 227 |
+ original_dir = os.path.join(str(datafiles), 'content', 'a')
|
|
| 228 |
+ original_contents = list_dir_contents(original_dir)
|
|
| 229 |
+ checkout_contents = list_dir_contents(checkoutdir)
|
|
| 230 |
+ assert(checkout_contents == original_contents)
|
| 1 |
+from contextlib import contextmanager
|
|
| 2 |
+ |
|
| 3 |
+from .ftp_server import SimpleFtpServer
|
|
| 4 |
+from .http_server import SimpleHttpServer
|
|
| 5 |
+ |
|
| 6 |
+ |
|
| 7 |
+@contextmanager
|
|
| 8 |
+def create_file_server(file_server_type):
|
|
| 9 |
+ if file_server_type == 'FTP':
|
|
| 10 |
+ server = SimpleFtpServer()
|
|
| 11 |
+ elif file_server_type == 'HTTP':
|
|
| 12 |
+ server = SimpleHttpServer()
|
|
| 13 |
+ else:
|
|
| 14 |
+ assert False
|
|
| 15 |
+ |
|
| 16 |
+ try:
|
|
| 17 |
+ yield server
|
|
| 18 |
+ finally:
|
|
| 19 |
+ server.stop()
|
| 1 |
+import multiprocessing
|
|
| 2 |
+ |
|
| 3 |
+from pyftpdlib.authorizers import DummyAuthorizer
|
|
| 4 |
+from pyftpdlib.handlers import FTPHandler
|
|
| 5 |
+from pyftpdlib.servers import FTPServer
|
|
| 6 |
+ |
|
| 7 |
+ |
|
| 8 |
+class SimpleFtpServer(multiprocessing.Process):
|
|
| 9 |
+ def __init__(self):
|
|
| 10 |
+ super().__init__()
|
|
| 11 |
+ self.authorizer = DummyAuthorizer()
|
|
| 12 |
+ handler = FTPHandler
|
|
| 13 |
+ handler.authorizer = self.authorizer
|
|
| 14 |
+ self.server = FTPServer(('127.0.0.1', 0), handler)
|
|
| 15 |
+ |
|
| 16 |
+ def run(self):
|
|
| 17 |
+ self.server.serve_forever()
|
|
| 18 |
+ |
|
| 19 |
+ def stop(self):
|
|
| 20 |
+ self.server.close_all()
|
|
| 21 |
+ self.server.close()
|
|
| 22 |
+ self.terminate()
|
|
| 23 |
+ self.join()
|
|
| 24 |
+ |
|
| 25 |
+ def allow_anonymous(self, cwd):
|
|
| 26 |
+ self.authorizer.add_anonymous(cwd)
|
|
| 27 |
+ |
|
| 28 |
+ def add_user(self, user, password, cwd):
|
|
| 29 |
+ self.authorizer.add_user(user, password, cwd, perm='elradfmwMT')
|
|
| 30 |
+ |
|
| 31 |
+ def base_url(self):
|
|
| 32 |
+ return 'ftp://127.0.0.1:{}'.format(self.server.address[1])
|
| 1 |
+import multiprocessing
|
|
| 2 |
+import os
|
|
| 3 |
+import posixpath
|
|
| 4 |
+import html
|
|
| 5 |
+import threading
|
|
| 6 |
+import base64
|
|
| 7 |
+from http.server import SimpleHTTPRequestHandler, HTTPServer, HTTPStatus
|
|
| 8 |
+ |
|
| 9 |
+ |
|
| 10 |
+class Unauthorized(Exception):
|
|
| 11 |
+ pass
|
|
| 12 |
+ |
|
| 13 |
+ |
|
| 14 |
+class RequestHandler(SimpleHTTPRequestHandler):
|
|
| 15 |
+ |
|
| 16 |
+ def get_root_dir(self):
|
|
| 17 |
+ authorization = self.headers.get('authorization')
|
|
| 18 |
+ if not authorization:
|
|
| 19 |
+ if not self.server.anonymous_dir:
|
|
| 20 |
+ raise Unauthorized('unauthorized')
|
|
| 21 |
+ return self.server.anonymous_dir
|
|
| 22 |
+ else:
|
|
| 23 |
+ authorization = authorization.split()
|
|
| 24 |
+ if len(authorization) != 2 or authorization[0].lower() != 'basic':
|
|
| 25 |
+ raise Unauthorized('unauthorized')
|
|
| 26 |
+ try:
|
|
| 27 |
+ decoded = base64.decodebytes(authorization[1].encode('ascii'))
|
|
| 28 |
+ user, password = decoded.decode('ascii').split(':')
|
|
| 29 |
+ expected_password, directory = self.server.users[user]
|
|
| 30 |
+ if password == expected_password:
|
|
| 31 |
+ return directory
|
|
| 32 |
+ except:
|
|
| 33 |
+ raise Unauthorized('unauthorized')
|
|
| 34 |
+ return None
|
|
| 35 |
+ |
|
| 36 |
+ def unauthorized(self):
|
|
| 37 |
+ shortmsg, longmsg = self.responses[HTTPStatus.UNAUTHORIZED]
|
|
| 38 |
+ self.send_response(HTTPStatus.UNAUTHORIZED, shortmsg)
|
|
| 39 |
+ self.send_header('Connection', 'close')
|
|
| 40 |
+ |
|
| 41 |
+ content = (self.error_message_format % {
|
|
| 42 |
+ 'code': HTTPStatus.UNAUTHORIZED,
|
|
| 43 |
+ 'message': html.escape(longmsg, quote=False),
|
|
| 44 |
+ 'explain': html.escape(longmsg, quote=False)
|
|
| 45 |
+ })
|
|
| 46 |
+ body = content.encode('UTF-8', 'replace')
|
|
| 47 |
+ self.send_header('Content-Type', self.error_content_type)
|
|
| 48 |
+ self.send_header('Content-Length', str(len(body)))
|
|
| 49 |
+ self.send_header('WWW-Authenticate', 'Basic realm="{}"'.format(self.server.realm))
|
|
| 50 |
+ self.end_headers()
|
|
| 51 |
+ self.end_headers()
|
|
| 52 |
+ |
|
| 53 |
+ if self.command != 'HEAD' and body:
|
|
| 54 |
+ self.wfile.write(body)
|
|
| 55 |
+ |
|
| 56 |
+ def do_GET(self):
|
|
| 57 |
+ try:
|
|
| 58 |
+ super().do_GET()
|
|
| 59 |
+ except Unauthorized:
|
|
| 60 |
+ self.unauthorized()
|
|
| 61 |
+ |
|
| 62 |
+ def do_HEAD(self):
|
|
| 63 |
+ try:
|
|
| 64 |
+ super().do_HEAD()
|
|
| 65 |
+ except Unauthorized:
|
|
| 66 |
+ self.unauthorized()
|
|
| 67 |
+ |
|
| 68 |
+ def translate_path(self, path):
|
|
| 69 |
+ path = path.split('?', 1)[0]
|
|
| 70 |
+ path = path.split('#', 1)[0]
|
|
| 71 |
+ path = posixpath.normpath(path)
|
|
| 72 |
+ assert(posixpath.isabs(path))
|
|
| 73 |
+ path = posixpath.relpath(path, '/')
|
|
| 74 |
+ return os.path.join(self.get_root_dir(), path)
|
|
| 75 |
+ |
|
| 76 |
+ |
|
| 77 |
+class AuthHTTPServer(HTTPServer):
|
|
| 78 |
+ def __init__(self, *args, **kwargs):
|
|
| 79 |
+ self.users = {}
|
|
| 80 |
+ self.anonymous_dir = None
|
|
| 81 |
+ self.realm = 'Realm'
|
|
| 82 |
+ super().__init__(*args, **kwargs)
|
|
| 83 |
+ |
|
| 84 |
+ |
|
| 85 |
+class SimpleHttpServer(multiprocessing.Process):
|
|
| 86 |
+ def __init__(self):
|
|
| 87 |
+ self.__stop = multiprocessing.Queue()
|
|
| 88 |
+ super().__init__()
|
|
| 89 |
+ self.server = AuthHTTPServer(('127.0.0.1', 0), RequestHandler)
|
|
| 90 |
+ self.started = False
|
|
| 91 |
+ |
|
| 92 |
+ def start(self):
|
|
| 93 |
+ self.started = True
|
|
| 94 |
+ super().start()
|
|
| 95 |
+ |
|
| 96 |
+ def run(self):
|
|
| 97 |
+ t = threading.Thread(target=self.server.serve_forever)
|
|
| 98 |
+ t.start()
|
|
| 99 |
+ self.__stop.get()
|
|
| 100 |
+ self.server.shutdown()
|
|
| 101 |
+ t.join()
|
|
| 102 |
+ |
|
| 103 |
+ def stop(self):
|
|
| 104 |
+ if not self.started:
|
|
| 105 |
+ return
|
|
| 106 |
+ self.__stop.put(None)
|
|
| 107 |
+ self.terminate()
|
|
| 108 |
+ self.join()
|
|
| 109 |
+ |
|
| 110 |
+ def allow_anonymous(self, cwd):
|
|
| 111 |
+ self.server.anonymous_dir = cwd
|
|
| 112 |
+ |
|
| 113 |
+ def add_user(self, user, password, cwd):
|
|
| 114 |
+ self.server.users[user] = (password, cwd)
|
|
| 115 |
+ |
|
| 116 |
+ def base_url(self):
|
|
| 117 |
+ return 'http://127.0.0.1:{}'.format(self.server.server_port)
|
