Skip to content

Commit 44f9c87

Browse files
authored
Refactor installation of maui workload + logging (#4985)
1 parent 107f6b4 commit 44f9c87

File tree

2 files changed

+107
-18
lines changed

2 files changed

+107
-18
lines changed

src/scenarios/shared/mauisharedpython.py

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,15 @@ def install_versioned_maui(precommands: PreCommands):
9696

9797
precommands.install_workload('maui', workload_install_args)
9898

99-
def extract_latest_dotnet_feed_from_nuget_config(path: str) -> str:
99+
def extract_latest_dotnet_feed_from_nuget_config(path: str, offset: int = 0) -> str:
100100
'''
101101
Extract the latest dotnet feed from the NuGet.config file.
102102
The latest feed is the one that has the highest version number.
103103
Supports only single number versioning (dotnet9, dotnet10, etc.)
104+
105+
Args:
106+
path: Path to the NuGet.config file
107+
offset: Offset from the latest version (0 = latest, 1 = second latest, etc.)
104108
'''
105109
tree = ET.parse(path)
106110
root = tree.getroot()
@@ -121,14 +125,19 @@ def extract_latest_dotnet_feed_from_nuget_config(path: str) -> str:
121125
version = int(match.group(1))
122126
dotnet_feeds[version] = value
123127

124-
# Find the highest version
128+
# Find the requested version based on offset
125129
if not dotnet_feeds:
126130
raise ValueError("No dotnet feeds found in NuGet.config")
127131

128-
latest_version = max(dotnet_feeds.keys())
129-
latest_feed = dotnet_feeds[latest_version]
132+
sorted_versions = sorted(dotnet_feeds.keys(), reverse=True)
133+
134+
if offset >= len(sorted_versions):
135+
raise ValueError(f"Offset {offset} is too large. Only {len(sorted_versions)} dotnet feeds available")
136+
137+
target_version = sorted_versions[offset]
138+
target_feed = dotnet_feeds[target_version]
130139

131-
return latest_feed
140+
return target_feed
132141

133142
def install_latest_maui(
134143
precommands: PreCommands,
@@ -139,6 +148,8 @@ def install_latest_maui(
139148
This function will create a rollback file and install the maui workload using that file.
140149
'''
141150

151+
getLogger().info("########## Installing latest MAUI workload ##########")
152+
142153
if precommands.has_workload:
143154
getLogger().info("Skipping maui installation due to --has-workload=true")
144155
return
@@ -156,57 +167,106 @@ def install_latest_maui(
156167

157168
# Get the latest published version of the maui workloads
158169
for workload in maui_rollback_dict.keys():
159-
packages = precommands.get_packages_for_sdk_from_feed(workload, feed)
160-
170+
getLogger().info(f"Processing workload: {workload}")
161171
try:
162-
packages = json.loads(packages)["searchResult"][0]['packages']
163-
except json.JSONDecodeError as e:
164-
raise Exception(f"Error parsing JSON output: {e}")
172+
packages = precommands.get_packages_for_sdk_from_feed(workload, feed)
173+
except Exception as e:
174+
getLogger().warning(f"Failed to get packages for {workload} from latest feed: {e}")
175+
getLogger().info("Trying second latest feed as fallback")
176+
fallback_feed = extract_latest_dotnet_feed_from_nuget_config(
177+
path=os.path.join(get_repo_root_path(), "NuGet.config"),
178+
offset=1
179+
)
180+
getLogger().info(f"Using fallback feed: {fallback_feed}")
181+
packages = precommands.get_packages_for_sdk_from_feed(workload, fallback_feed)
182+
183+
# Log all package IDs before filtering
184+
getLogger().debug(f"All package IDs for {workload}: {[pkg['id'] for pkg in packages]}")
165185

166186
# Filter out packages that have ID that matches the pattern 'Microsoft.NET.Sdk.<workload>.Manifest-<version>'
167-
packages = [pkg for pkg in packages if re.match(r'Microsoft\.NET\.Sdk\..*\.Manifest\-\d+\.\d+\.\d+(\-(preview|rc|alpha)\.\d+)?$', pkg['id'])]
187+
pattern = r'Microsoft\.NET\.Sdk\..*\.Manifest\-\d+\.\d+\.\d+(\-(preview|rc|alpha)\.\d+)?$'
188+
packages = [pkg for pkg in packages if re.match(pattern, pkg['id'])]
189+
getLogger().info(f"After manifest pattern filtering, found {len(packages)} packages for {workload}")
190+
getLogger().debug(f"Filtered package IDs for {workload}: {[pkg['id'] for pkg in packages]}")
168191

169192
# Extract the .NET version from the package ID (Manifest-<version>($|-<preview|rc|alpha>.*))
170193
for package in packages:
194+
getLogger().debug(f"Processing package ID: {package['id']}")
171195
match = re.search(r'Manifest-(.+)$', package["id"])
172196
if match:
173197
sdk_version = match.group(1)
174198
package['sdk_version'] = sdk_version
199+
getLogger().debug(f"Extracted SDK version '{sdk_version}' from package {package['id']}")
175200

176201
# Extract the .NET version from sdk_version (first integer)
177202
match = re.search(r'^\d+\.\d+', sdk_version)
178203
if match:
179204
dotnet_version = match.group(0)
180205
package['dotnet_version'] = dotnet_version
206+
getLogger().debug(f"Extracted .NET version '{dotnet_version}' from SDK version '{sdk_version}'")
181207
else:
208+
getLogger().error(f"Unable to find .NET version in SDK version '{sdk_version}' for package {package['id']}")
182209
raise Exception("Unable to find .NET version in SDK version")
183210
else:
211+
getLogger().error(f"Unable to find .NET SDK version in package ID: {package['id']}")
184212
raise Exception("Unable to find .NET SDK version in package ID")
185213

186214
# Filter out packages that have lower 'dotnet_version' than the rest of the packages
187215
# Sometimes feed can contain packages from previous release versions, so we need to filter them out
188-
highest_dotnet_version = max(float(pkg['dotnet_version']) for pkg in packages)
216+
dotnet_versions = [float(pkg['dotnet_version']) for pkg in packages]
217+
getLogger().debug(f"Found .NET versions for {workload}: {dotnet_versions}")
218+
highest_dotnet_version = max(dotnet_versions)
219+
getLogger().info(f"Highest .NET version for {workload}: {highest_dotnet_version}")
220+
packages_before_version_filter = len(packages)
189221
packages = [pkg for pkg in packages if float(pkg['dotnet_version']) == highest_dotnet_version]
222+
getLogger().info(f"After .NET version filtering for {workload}: {len(packages)} packages (was {packages_before_version_filter})")
223+
224+
pkg_details = [f"{pkg['id']} (v{pkg['dotnet_version']})" for pkg in packages]
225+
getLogger().debug(f"Packages after .NET version filter: {pkg_details}")
190226

191227
# Check if we have non-preview packages available and use them
192-
non_preview_packages = [pkg for pkg in packages if not re.search(r'\-(preview|rc|alpha)\.\d+$', pkg['id'])]
228+
preview_pattern = r'\-(preview|rc|alpha)\.\d+$'
229+
non_preview_packages = [pkg for pkg in packages if not re.search(preview_pattern, pkg['id'])]
230+
getLogger().info(f"Found {len(non_preview_packages)} non-preview packages for {workload} out of {len(packages)} total")
231+
232+
preview_packages = [pkg['id'] for pkg in packages if re.search(preview_pattern, pkg['id'])]
233+
getLogger().debug(f"Preview packages: {preview_packages}")
234+
getLogger().debug(f"Non-preview packages: {[pkg['id'] for pkg in non_preview_packages]}")
235+
193236
if non_preview_packages:
237+
getLogger().info(f"Using non-preview packages for {workload}")
194238
packages = non_preview_packages
239+
else:
240+
getLogger().info(f"No non-preview packages available for {workload}, using all packages")
195241

196242
# Sort the packages by 'sdk_version'
243+
before_sort = [f"{pkg['id']} (sdk_v{pkg['sdk_version']})" for pkg in packages]
244+
newline = '\n'
245+
getLogger().debug(f"Packages before sorting for {workload}: {newline.join(before_sort)}")
197246
packages.sort(key=lambda x: x['sdk_version'], reverse=True)
247+
after_sort = [f"{pkg['id']} (sdk_v{pkg['sdk_version']})" for pkg in packages]
248+
getLogger().debug(f"Packages after sorting for {workload}: {newline.join(after_sort)}")
198249

199250
# Get the latest package
251+
if not packages:
252+
getLogger().error(f"No packages available for {workload} after filtering")
253+
raise Exception(f"No packages available for {workload} after filtering")
254+
200255
latest_package = packages[0]
201256

202-
getLogger().info(f"Latest package for {workload} found: {latest_package['id']} {latest_package['latestVersion']}")
257+
getLogger().info(f"Latest package details for {workload}: ID={latest_package['id']}, Version={latest_package['latestVersion']}, SDK_Version={latest_package['sdk_version']}, .NET_Version={latest_package['dotnet_version']}")
203258

204-
maui_rollback_dict[workload] = f"{latest_package['latestVersion']}/{latest_package['sdk_version']}"
259+
rollback_value = f"{latest_package['latestVersion']}/{latest_package['sdk_version']}"
260+
maui_rollback_dict[workload] = rollback_value
261+
getLogger().info(f"Set rollback for {workload}: {rollback_value}")
205262

206263
# Create the rollback file
264+
getLogger().info(f"Final rollback dictionary: {maui_rollback_dict}")
207265
with open("rollback_maui.json", "w", encoding="utf-8") as f:
208266
f.write(json.dumps(maui_rollback_dict, indent=4))
267+
getLogger().info("Created rollback_maui.json file")
209268

210269
# Install the workload using the rollback file
211270
getLogger().info("Installing maui workload with rollback file")
212271
precommands.install_workload('maui', ['--from-rollback-file', 'rollback_maui.json'])
272+
getLogger().info("########## Finished installing latest MAUI workload ##########")

src/scenarios/shared/precommands.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import shutil
88
import subprocess
9+
import json
910
from logging import getLogger
1011
from argparse import ArgumentParser
1112
from typing import List, Optional
@@ -276,7 +277,12 @@ def install_workload(self, workloadid: str, install_args: List[str] = ["--skip-m
276277
if not self.has_workload:
277278
if self.readonly_dotnet:
278279
raise Exception('workload needed to build, but has_workload=false, and readonly_dotnet=true')
279-
subprocess.run(["dotnet", "workload", "install", workloadid] + install_args, check=True)
280+
try:
281+
subprocess.run(["dotnet", "workload", "install", workloadid] + install_args, check=True)
282+
getLogger().info(f"Successfully installed workload {workloadid}")
283+
except Exception as e:
284+
getLogger().error(f"Error installing workload {workloadid}: {e}")
285+
raise
280286

281287
def uninstall_workload(self, workloadid: str):
282288
'Uninstalls the workload, if possible'
@@ -299,7 +305,7 @@ def print_dotnet_info(self):
299305

300306

301307
def get_packages_for_sdk_from_feed(self, sdk_name: str, feed: str):
302-
'Gets the packages for the given sdk from the given feed'
308+
'Gets the packages for the given sdk from the given feed and returns parsed package list'
303309

304310
getLogger().debug(f"dotnet package search {sdk_name} --prerelease --take 999 --format json --source {feed}")
305311

@@ -308,9 +314,32 @@ def get_packages_for_sdk_from_feed(self, sdk_name: str, feed: str):
308314
["dotnet", "package", "search", sdk_name, "--prerelease", "--take", "999", "--format", "json", "--source", feed], check=True, capture_output=True, text=True)
309315

310316
if result.returncode != 0:
317+
getLogger().error(f"Package search command failed: {result.stderr}")
311318
raise Exception(f"Error querying package feed: {result.stderr}")
312319

313-
return result.stdout
320+
getLogger().debug(f"Raw packages response for {sdk_name}: {result.stdout}")
321+
322+
try:
323+
parsed_response = json.loads(result.stdout)
324+
getLogger().debug(f"Parsed JSON response for {sdk_name}: {parsed_response}")
325+
326+
if not parsed_response.get("searchResult") or len(parsed_response["searchResult"]) == 0:
327+
getLogger().error(f"No search results found for {sdk_name} in feed {feed}")
328+
raise Exception(f"No search results found for {sdk_name} in feed {feed}")
329+
330+
packages = parsed_response["searchResult"][0].get('packages', [])
331+
getLogger().info(f"Found {len(packages)} total packages for {sdk_name}")
332+
333+
if not packages:
334+
getLogger().error(f"No packages found for SDK {sdk_name} in feed {feed}")
335+
raise Exception(f"No packages found for SDK {sdk_name} in feed {feed}")
336+
337+
return packages
338+
339+
except json.JSONDecodeError as e:
340+
getLogger().error(f"Failed to parse JSON response for {sdk_name}: {e}")
341+
getLogger().debug(f"Raw response that failed to parse: {result.stdout}")
342+
raise Exception(f"Error parsing JSON output for {sdk_name}: {e}")
314343

315344
def _addstaticmsbuildproperty(self, projectfile: str):
316345
'Insert static msbuild property in the specified project file'

0 commit comments

Comments
 (0)