[Notes] [Git][BuildStream/buildstream][aevri/update_man] 4 commits: Add support for .netrc in remote/tar/zip plugins



Title: GitLab

Jürg Billeter pushed to branch aevri/update_man at BuildStream / buildstream

Commits:

28 changed files:

Changes:

  • .gitlab-ci.yml
    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:
    

  • buildstream/plugins/sources/_downloadablefilesource.py
    ... ... @@ -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

  • dev-requirements.txt
    ... ... @@ -9,3 +9,4 @@ pytest-pep8
    9 9
     pytest-pylint
    
    10 10
     pytest-xdist
    
    11 11
     pytest-timeout
    
    12
    +pyftpdlib

  • man/bst-artifact-server.1
    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

  • man/bst-build.1
    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
    

  • man/bst-checkout.1
    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

  • man/bst-fetch.1
    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
    

  • man/bst-help.1
    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

  • man/bst-init.1
    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)
    

  • man/bst-pull.1
    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
    

  • man/bst-push.1
    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
    

  • man/bst-shell.1
    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
    

  • man/bst-show.1
    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

  • man/bst-source-bundle.1
    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

  • man/bst-source-checkout.1
    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

  • man/bst-track.1
    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
    

  • man/bst-workspace-close.1
    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
    

  • man/bst-workspace-list.1
    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

  • man/bst-workspace-open.1
    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

  • man/bst-workspace-reset.1
    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
    

  • man/bst-workspace.1
    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

  • man/bst.1
    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

  • tests/sources/remote.py
    ... ... @@ -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))

  • tests/sources/tar.py
    ... ... @@ -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)

  • tests/sources/zip.py
    ... ... @@ -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)

  • tests/testutils/file_server.py
    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()

  • tests/testutils/ftp_server.py
    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])

  • tests/testutils/http_server.py
    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)



  • [Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]