|
7 | 7 | import json |
8 | 8 | import os |
9 | 9 | import pathlib |
10 | | -import re |
11 | 10 | import tempfile |
12 | 11 | import urllib.request as url_lib |
13 | 12 | import zipfile |
@@ -60,117 +59,96 @@ def install_bundled_libs(session): |
60 | 59 | ) |
61 | 60 | session.install("packaging") |
62 | 61 |
|
| 62 | + debugpy_info_json_path = pathlib.Path(__file__).parent / "debugpy_info.json" |
| 63 | + debugpy_info = json.loads(debugpy_info_json_path.read_text(encoding="utf-8")) |
| 64 | + |
63 | 65 | target = os.environ.get("VSCETARGET", "") |
64 | 66 | print("target:", target) |
65 | | - download_debugpy_via_pip(session, target) |
66 | | - |
67 | | - |
68 | | -def _infer_debugpy_version() -> str: |
69 | | - """Best-effort debugpy version selection. |
70 | | -
|
71 | | - Priority: |
72 | | - 1) DEBUGPY_VERSION env var |
73 | | - 2) Extract from debugpy_info.json (if present) |
74 | | - """ |
75 | | - |
76 | | - env_version = os.environ.get("DEBUGPY_VERSION") |
77 | | - if env_version: |
78 | | - return env_version |
| 67 | + if "darwin" in target: |
| 68 | + wheels = debugpy_info["macOS"] |
| 69 | + elif "win32-ia32" == target: |
| 70 | + wheels = debugpy_info.get("win32", debugpy_info["any"]) |
| 71 | + elif "win32-x64" == target: |
| 72 | + wheels = debugpy_info["win64"] |
| 73 | + elif "linux-x64" == target: |
| 74 | + wheels = debugpy_info["linux"] |
| 75 | + else: |
| 76 | + wheels = debugpy_info["any"] |
79 | 77 |
|
80 | | - debugpy_info_json_path = pathlib.Path(__file__).parent / "debugpy_info.json" |
81 | | - if not debugpy_info_json_path.exists(): |
82 | | - raise FileNotFoundError( |
83 | | - "Missing debugpy version source. Set DEBUGPY_VERSION or add debugpy_info.json." |
84 | | - ) |
| 78 | + # Use pip download when USE_PIP_DOWNLOAD is set (e.g., for Azure Artifacts feed) |
| 79 | + if os.environ.get("USE_PIP_DOWNLOAD"): |
| 80 | + download_debugpy_via_pip(session, wheels) |
| 81 | + else: |
| 82 | + download_url(wheels) |
85 | 83 |
|
86 | | - debugpy_info = json.loads(debugpy_info_json_path.read_text(encoding="utf-8")) |
87 | | - for platform_entries in debugpy_info.values(): |
88 | | - for entry in platform_entries: |
89 | | - match = re.search(r"/debugpy-([^/]+?)-", entry.get("url", "")) |
90 | | - if match: |
91 | | - return match.group(1) |
92 | | - |
93 | | - raise ValueError( |
94 | | - "Could not infer debugpy version from debugpy_info.json. Set DEBUGPY_VERSION." |
95 | | - ) |
96 | 84 |
|
| 85 | +def _parse_wheel_info(url: str) -> dict: |
| 86 | + """Parse version and platform info from a wheel URL. |
97 | 87 |
|
98 | | -def download_debugpy_via_pip(session: nox.Session, target: str) -> None: |
| 88 | + Example URL: .../debugpy-1.8.19-cp311-cp311-win_amd64.whl |
| 89 | + Returns: {"version": "1.8.19", "py_ver": "311", "abi": "cp311", "platform": "win_amd64"} |
| 90 | + """ |
| 91 | + import re |
| 92 | + |
| 93 | + filename = url.rsplit("/", 1)[-1] |
| 94 | + # Wheel filename format: {name}-{version}-{python}-{abi}-{platform}.whl |
| 95 | + match = re.match(r"debugpy-([^-]+)-cp(\d+)-([^-]+)-(.+)\.whl", filename) |
| 96 | + if match: |
| 97 | + return { |
| 98 | + "version": match.group(1), |
| 99 | + "py_ver": match.group(2), |
| 100 | + "abi": match.group(3), |
| 101 | + "platform": match.group(4), |
| 102 | + } |
| 103 | + # Fallback for py2.py3-none-any wheels |
| 104 | + match = re.match(r"debugpy-([^-]+)-py\d\.py\d-none-any\.whl", filename) |
| 105 | + if match: |
| 106 | + return {"version": match.group(1), "py_ver": None, "abi": "none", "platform": "any"} |
| 107 | + raise ValueError(f"Could not parse wheel filename: {filename}") |
| 108 | + |
| 109 | + |
| 110 | +def download_debugpy_via_pip(session: nox.Session, wheels: list) -> None: |
99 | 111 | """Downloads debugpy wheels via pip and extracts them into bundled/libs. |
100 | 112 |
|
101 | | - This respects pip configuration (index URLs, proxies, certs) and avoids hard-coded |
102 | | - direct downloads from files.pythonhosted.org. |
| 113 | + Uses pip to download by package name, allowing pip to use configured |
| 114 | + index URLs (e.g., Azure Artifacts feed) instead of direct PyPI URLs. |
103 | 115 | """ |
104 | | - |
105 | | - debugpy_version = _infer_debugpy_version() |
106 | 116 | libs_dir = pathlib.Path.cwd() / "bundled" / "libs" |
107 | 117 | libs_dir.mkdir(parents=True, exist_ok=True) |
108 | 118 |
|
109 | | - # Match prior behavior: bundle debugpy wheels for the target (or universal fallback). |
110 | | - # We download multiple wheels for multiple CPython versions, because the extension may |
111 | | - # be used with different interpreter versions. |
112 | | - # |
113 | | - # Format: (python_version, implementation, abi, platform) |
114 | | - if "darwin" in target: |
115 | | - wheel_requests = [ |
116 | | - ("310", "cp", "cp310", "macosx_15_0_x86_64"), |
117 | | - ("311", "cp", "cp311", "macosx_15_0_universal2"), |
118 | | - ("312", "cp", "cp312", "macosx_15_0_universal2"), |
119 | | - ] |
120 | | - elif target == "win32-ia32": |
121 | | - wheel_requests = [ |
122 | | - ("310", "cp", "cp310", "win32"), |
123 | | - ("311", "cp", "cp311", "win32"), |
124 | | - ("312", "cp", "cp312", "win32"), |
125 | | - ] |
126 | | - elif target == "win32-x64": |
127 | | - wheel_requests = [ |
128 | | - ("310", "cp", "cp310", "win_amd64"), |
129 | | - ("311", "cp", "cp311", "win_amd64"), |
130 | | - ("312", "cp", "cp312", "win_amd64"), |
131 | | - ] |
132 | | - elif target == "linux-x64": |
133 | | - wheel_requests = [ |
134 | | - ("310", "cp", "cp310", "manylinux_2_34_x86_64"), |
135 | | - ("311", "cp", "cp311", "manylinux_2_34_x86_64"), |
136 | | - ("312", "cp", "cp312", "manylinux_2_34_x86_64"), |
137 | | - ] |
138 | | - else: |
139 | | - # Universal fallback wheel (py2.py3-none-any). |
140 | | - wheel_requests = [("39", "cp", "none", "any")] |
| 119 | + # Parse version and platform info from wheel URLs |
| 120 | + parsed = [_parse_wheel_info(w["url"]) for w in wheels] |
| 121 | + version = parsed[0]["version"] |
141 | 122 |
|
142 | 123 | with tempfile.TemporaryDirectory(prefix="debugpy_wheels_") as tmp_dir: |
143 | 124 | tmp_path = pathlib.Path(tmp_dir) |
144 | | - for py_ver, impl, abi, platform_tag in wheel_requests: |
145 | | - session.run( |
146 | | - "python", |
147 | | - "-m", |
148 | | - "pip", |
149 | | - "download", |
150 | | - f"debugpy=={debugpy_version}", |
| 125 | + |
| 126 | + for info in parsed: |
| 127 | + args = [ |
| 128 | + "python", "-m", "pip", "download", |
| 129 | + f"debugpy=={version}", |
151 | 130 | "--no-deps", |
152 | | - "--only-binary", |
153 | | - ":all:", |
154 | | - "--dest", |
155 | | - str(tmp_path), |
156 | | - "--python-version", |
157 | | - py_ver, |
158 | | - "--implementation", |
159 | | - impl, |
160 | | - "--abi", |
161 | | - abi, |
162 | | - "--platform", |
163 | | - platform_tag, |
164 | | - ) |
| 131 | + "--only-binary", ":all:", |
| 132 | + "--dest", str(tmp_path), |
| 133 | + ] |
| 134 | + if info["py_ver"]: |
| 135 | + # Platform-specific wheel |
| 136 | + args.extend(["--python-version", info["py_ver"]]) |
| 137 | + args.extend(["--implementation", "cp"]) |
| 138 | + args.extend(["--abi", info["abi"]]) |
| 139 | + args.extend(["--platform", info["platform"]]) |
| 140 | + # For none-any wheels, no platform args needed |
| 141 | + |
| 142 | + session.run(*args) |
165 | 143 |
|
166 | 144 | wheel_paths = sorted(tmp_path.glob("debugpy-*.whl")) |
167 | 145 | if not wheel_paths: |
168 | 146 | raise FileNotFoundError( |
169 | | - f"pip download produced no debugpy wheels for version {debugpy_version}." |
| 147 | + f"pip download produced no debugpy wheels for version {version}." |
170 | 148 | ) |
171 | 149 |
|
172 | 150 | for wheel_path in wheel_paths: |
173 | | - print("Download:", wheel_path.name) |
| 151 | + print("Downloaded:", wheel_path.name) |
174 | 152 | with zipfile.ZipFile(wheel_path, "r") as wheel: |
175 | 153 | for zip_info in wheel.infolist(): |
176 | 154 | print("\t" + zip_info.filename) |
|
0 commit comments