File: CondaConfiguration.py

package info (click to toggle)
python-azure 20250603%2Bgit-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 851,724 kB
  • sloc: python: 7,362,925; ansic: 804; javascript: 287; makefile: 195; sh: 145; xml: 109
file content (159 lines) | stat: -rw-r--r-- 5,789 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from typing import List, Any, Optional
import os
import bs4
import urllib3
from ci_tools.variables import str_to_bool

http = urllib3.PoolManager()
# arguments: |
#       -c "${{ replace(convertToJson(parameters.CondaArtifacts), '"', '\"') }}"
#       -w "$(Build.SourcesDirectory)/conda/conda-recipes"
#
# # Sample configuration yaml. This is converted to json before being passed a blob to the invoking script. (see directly above for conversion)
#     - name: uamqp
#         common_root: uamqp
#         in_batch: true
#         conda_py_versions:
#         - "38"
#         - "39"
#         - "310"
#         - "311"
#         checkout:
#         - package: uamqp
#         download_uri: https://files.pythonhosted.org/packages/0b/d8/fc24d95e6f6c80851ae6738c78da081cd535c924b02c5a4928b108b9ed42/uamqp-1.6.5.tar.gz
#   - name: azure-core
#     common_root: azure
#     in_batch: ${{ parameters.release_azure_core }}
#     channels: "conda-forge"
#     checkout:
#     - package: azure-core
#       version: 1.24.0
#     - package: azure-core
#       version: 1.24.0
#   - name: azure-storage
#     common_root: azure
#     in_batch: ${{ parameters.release_azure_storage }}
#     checkout:
#     - package: azure-storage-blob
#       checkout_path: sdk/storage
#       version: 12.12.0
#     - package: azure-storage-queue
#       checkout_path: sdk/storage
#       version: 12.3.0
#     - package: azure-storage-file-share
#       checkout_path: sdk/storage
#       version: 12.8.0
#     - package: azure-storage-file-datalake
#       checkout_path: sdk/storage
#       version: 12.7.0


def get_package_sdist_url(package: str, version: str) -> str:
    url = f"https://pypi.org/pypi/{package}/{version}/json"
    response = http.request("GET", url)

    if response.status != 200:
        raise RuntimeError(f"Failed to fetch metadata for {package}@{version} from PyPI.")

    data = response.json()

    for file_info in data.get("urls", []):
        if file_info.get("packagetype") == "sdist":
            return file_info["url"]

    raise ValueError(f"Unable to find a source distribution for {package}@{version}.")


class CheckoutConfiguration:
    def __init__(self, raw_json: dict):
        # we should always have a package name

        if "package" in raw_json:
            self.package = raw_json["package"]
        else:
            raise ValueError("A checkout configuration MUST have a package name defined in key 'package'.")

        self.checkout_path = raw_json.get("checkout_path", None)
        self.version = raw_json.get("version", None)
        self.download_uri = raw_json.get("download_uri", None)

        if self.version and self.checkout_path is None:
            self.download_uri = get_package_sdist_url(self.package, self.version)

        if not self.checkout_path and not self.download_uri:
            raise ValueError(
                "When defining a checkout configuration, one must either have a valid PyPI download url"
                " (download_uri) or a path and version in the repo (checkout_path, version)."
            )

    def __str__(self) -> str:
        if self.download_uri:
            return f"""- {self.package} downloaded from pypi
  {self.download_uri}"""
        else:
            return f"""- {self.checkout_path}/{self.package} from git @ {self.version}"""


def parse_checkout_config(checkout_configs: List[Any]) -> List[CheckoutConfiguration]:
    configs = []
    for checkout_config in checkout_configs:
        configs.append(CheckoutConfiguration(checkout_config))

    return configs


class CondaConfiguration:
    def __init__(
        self,
        name: str,
        common_root: str,
        in_batch: bool,
        checkout: List[CheckoutConfiguration],
        created_sdist_path: Optional[str] = None,
        service: str = "",
        conda_py_versions: List[str] = [],
        channels: List[str] = [],
    ):
        self.name: str = name
        self.common_root: str = common_root
        self.in_batch: bool = in_batch
        self.checkout: List[CheckoutConfiguration] = checkout
        self.created_sdist_path: Optional[str] = created_sdist_path
        self.service: str = service
        self.conda_py_versions = conda_py_versions
        self.channels = channels

    @classmethod
    def from_json(cls, raw_json_blob: dict):
        name = raw_json_blob.get("name", None)
        common_root = raw_json_blob.get("common_root", None)
        in_batch = str_to_bool(raw_json_blob["in_batch"])
        checkout_config = parse_checkout_config(raw_json_blob.get("checkout", []))
        conda_py_versions = raw_json_blob.get("conda_py_versions", [])
        service = raw_json_blob.get("service", None)
        channels = raw_json_blob.get("channels", [])

        # default the service
        if any([a.checkout_path for a in checkout_config]) and not service:
            valid_checkout_config = next((x for x in checkout_config if x.checkout_path is not None), None)
            if valid_checkout_config:
                service = valid_checkout_config.checkout_path.split("/")[1].strip()

        if not service and name.startswith("azure"):
            raise ValueError(
                f"Tooling cannot auto-detect targeted service for conda package {name}, nor is there a checkout_path that we can parse the service from. Please correct and retry."
            )

        return cls(name, common_root, in_batch, checkout_config, None, service, conda_py_versions, channels)

    def __str__(self) -> str:
        checkout = f"{os.linesep}".join([str(c_config) for c_config in self.checkout])

        return f"""====================================
\"{self.name}\" generated from:
{checkout}
====================================
"""

    def prepare_local_folder(self) -> None:
        pass