Пример #1
0
    def update(self, *, prefix: str, distribution: str,
               snapshots: Optional[Sequence[Dict[str, str]]] = None, force_overwrite: bool = False,
               sign_skip: bool = False, sign_batch: bool = True, sign_gpgkey: Optional[str] = None,
               sign_keyring: Optional[str] = None, sign_secret_keyring: Optional[str] = None,
               sign_passphrase: Optional[str] = None, sign_passphrase_file: Optional[str] = None,
               skip_cleanup: Optional[bool] = False) -> PublishEndpoint:
        """
        Example:

        .. code-block:: python
            p.update(
                prefix="s3:maurusnet:nightly/stretch", distribution="mn-nightly",
                sign_batch=True, sign_gpgkey='A16BE921', sign_passphrase='***********'
            )
        """
        if sign_passphrase is not None and sign_passphrase_file is not None:
            raise AptlyAPIException("Can't use sign_passphrase and sign_passphrase_file at the same time")

        body = {}  # type: T_BodyDict

        if snapshots is not None:
            for source in snapshots:
                if "name" not in source and "Name" not in source:
                    raise AptlyAPIException("Each source in update() must contain the 'name' attribute")
            body["Snapshots"] = snapshots

        if force_overwrite:
            body["ForceOverwrite"] = True
        if skip_cleanup:
            body["SkipCleanup"] = True

        sign_dict = {}  # type: Dict[str, Union[bool,str]]
        if sign_skip:
            sign_dict["Skip"] = True
        else:
            sign_dict["Batch"] = sign_batch
            if sign_gpgkey is not None:
                sign_dict["GpgKey"] = sign_gpgkey
            if sign_keyring is not None:
                sign_dict["Keyring"] = sign_keyring
            if sign_secret_keyring is not None:
                sign_dict["SecretKeyring"] = sign_secret_keyring
            if sign_passphrase is not None:
                sign_dict["Passphrase"] = sign_passphrase
            if sign_passphrase_file is not None:
                sign_dict["PassphraseFile"] = sign_passphrase_file
        body["Signing"] = sign_dict

        resp = self.do_put("api/publish/%s/%s" %
                           (quote(self.escape_prefix(prefix)), quote(distribution),), json=body)
        return self.endpoint_from_response(resp.json())
Пример #2
0
    def search_packages(self,
                        reponame: str,
                        query: str = None,
                        with_deps: bool = False,
                        detailed: bool = False) -> Sequence[Package]:
        if query is None and with_deps:
            raise AptlyAPIException(
                "search_packages can't include dependencies (with_deps==True) without"
                "a query")
        params = {}
        if query:
            params["q"] = query

            if with_deps:
                params["withDeps"] = "1"

        if detailed:
            params["format"] = "details"

        resp = self.do_get("api/repos/%s/packages" % quote(reponame),
                           params=params)
        ret = []
        for rpkg in resp.json():
            ret.append(PackageAPISection.package_from_response(rpkg))
        return ret
Пример #3
0
 def version(self) -> str:
     resp = self.do_get("api/version")
     if "Version" in resp.json():
         return cast(str, resp.json()["Version"])
     else:
         raise AptlyAPIException(
             "Aptly server didn't return a valid response object:\n%s" %
             resp.text)
Пример #4
0
 def list(self, sort: str='name') -> Sequence[Snapshot]:
     if sort not in ['name', 'time']:
         raise AptlyAPIException("Snapshot LIST only supports two sort modes: 'name' and 'time'. %s is not "
                                 "supported." % sort)
     resp = self.do_get("/api/snapshots")
     ret = []
     for rsnap in resp.json():
         ret.append(self.snapshot_from_response(rsnap))
     return ret
Пример #5
0
    def update(self, snapshotname: str, newname: str=None, newdescription: str=None) -> Snapshot:
        if newname is None and newdescription is None:
            raise AptlyAPIException("When updating a Snapshot you must at lease provide either a new name or a "
                                    "new description.")
        body = {}  # type: Dict[str, Union[str, Sequence[str]]]
        if newname is not None:
            body["Name"] = newname

        if newdescription is not None:
            body["Description"] = newdescription

        resp = self.do_put("/api/snapshots/%s" % quote(snapshotname), json=body)
        return self.snapshot_from_response(resp.json())
Пример #6
0
    def upload(self, destination: str, *files: str) -> Sequence[str]:
        to_upload = []  # type: List[Tuple[str, BinaryIO]]
        for f in files:
            if not os.path.exists(f) or not os.access(f, os.R_OK):
                raise AptlyAPIException("File to upload %s can't be opened or read" % f)
            fh = open(f, mode="rb")
            to_upload.append((f, fh),)

        try:
            resp = self.do_post("api/files/%s" % destination,
                                files=to_upload)
        except AptlyAPIException:
            raise
        finally:
            for fn, to_close in to_upload:
                if not to_close.closed:
                    to_close.close()

        return cast(List[str], resp.json())
Пример #7
0
    def edit(self,
             reponame: str,
             comment: str = None,
             default_distribution: str = None,
             default_component: str = None) -> Repo:
        if comment is None and default_component is None and default_distribution is None:
            raise AptlyAPIException(
                "edit requires at least one of 'comment', 'default_distribution' or "
                "'default_component'.")

        body = {}
        if comment is not None:
            body["Comment"] = comment
        if default_distribution is not None:
            body["DefaultDistribution"] = default_distribution
        if default_component is not None:
            body["DefaultComponent"] = default_component

        resp = self.do_put("api/repos/%s" % quote(reponame), json=body)
        return self.repo_from_response(resp.json())
Пример #8
0
    def publish(self,
                *,
                source_kind: str = "local",
                sources: Sequence[Dict[str, str]],
                architectures: Sequence[str],
                prefix: str = None,
                distribution: str = None,
                label: str = None,
                origin: str = None,
                force_overwrite: bool = False,
                sign_skip: bool = False,
                sign_batch: bool = True,
                sign_gpgkey: str = None,
                sign_keyring: str = None,
                sign_secret_keyring: str = None,
                sign_passphrase: str = None,
                sign_passphrase_file: str = None) -> PublishEndpoint:
        """
        Example:

        .. code-block:: python
            p.publish(
                sources=[{'Name': 'aptly-repo'}], architectures=['amd64'],
                prefix='s3:myendpoint:test/a_1', distribution='test', sign_batch=True,
                sign_gpgkey='A16BE921', sign_passphrase='*********'
            )
        """
        if not sign_skip and not sign_gpgkey:
            raise AptlyAPIException(
                "Publish needs a gpgkey to sign with if sign_skip is False")
        if sign_passphrase is not None and sign_passphrase_file is not None:
            raise AptlyAPIException(
                "Can't use sign_passphrase and sign_passphrase_file at the same time"
            )

        for source in sources:
            if "name" not in source and "Name" not in source:
                raise AptlyAPIException(
                    "Each source in publish() must contain the 'name' attribute"
                )

        url = "/api/publish"
        if prefix is not None and prefix != "":
            url = "/api/publish/%s" % quote(self.escape_prefix(prefix))

        body = {
            "SourceKind": source_kind,
            "Sources": sources,
        }  # type: T_BodyDict

        if architectures is not None:
            body["Architectures"] = architectures
        if distribution is not None:
            body["Distribution"] = distribution
        if label is not None:
            body["Label"] = label
        if origin is not None:
            body["Origin"] = origin
        if force_overwrite:
            body["ForceOverwrite"] = True

        sign_dict = {}  # type: Dict[str, Union[bool,str]]
        if sign_skip:
            sign_dict["Skip"] = True
        else:
            sign_dict["Batch"] = sign_batch
            if sign_gpgkey is not None:
                sign_dict["GpgKey"] = sign_gpgkey
            if sign_keyring is not None:
                sign_dict["Keyring"] = sign_keyring
            if sign_secret_keyring is not None:
                sign_dict["SecretKeyring"] = sign_secret_keyring
            if sign_passphrase is not None:
                sign_dict["Passphrase"] = sign_passphrase
            if sign_passphrase_file is not None:
                sign_dict["PassphraseFile"] = sign_passphrase_file
        body["Signing"] = sign_dict

        resp = self.do_post(url, json=body)
        return self.endpoint_from_response(resp.json())