Skip to content

Commit 12208de

Browse files
rmarinhoCopilot
andcommitted
Use xcrun xcodebuild, file-scoped namespaces, sync all fixes
- Use xcrun xcodebuild instead of resolving path inside Xcode bundle - Remove xcodePath parameter from EnsureFirstLaunch (now uses xcrun) - Add InvalidOperationException catches throughout - Adopt file-scoped namespaces and flat usings on all new files - Sync all fixed files from PRs #158, #159, #160 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 07190ba commit 12208de

9 files changed

Lines changed: 815 additions & 892 deletions

Xamarin.MacDev/AppleInstaller.cs

Lines changed: 87 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -3,144 +3,119 @@
33

44
using System;
55
using System.Collections.Generic;
6-
76
using Xamarin.MacDev.Models;
87

98
#nullable enable
109

11-
namespace Xamarin.MacDev {
10+
namespace Xamarin.MacDev;
11+
12+
/// <summary>
13+
/// Orchestrates Apple development environment setup. Checks the current
14+
/// state via <see cref="EnvironmentChecker"/> and installs missing
15+
/// components (Command Line Tools, Xcode first-launch packages, and
16+
/// simulator runtimes).
17+
/// </summary>
18+
public class AppleInstaller {
19+
20+
readonly ICustomLogger log;
21+
22+
public AppleInstaller (ICustomLogger log)
23+
{
24+
this.log = log ?? throw new ArgumentNullException (nameof (log));
25+
}
1226

1327
/// <summary>
14-
/// Orchestrates Apple development environment setup. Checks the current
15-
/// state via <see cref="EnvironmentChecker"/> and installs missing
16-
/// components (Command Line Tools, Xcode first-launch packages, and
17-
/// simulator runtimes).
28+
/// Ensures the Apple development environment is ready.
29+
/// When <paramref name="dryRun"/> is true, reports what would be
30+
/// installed without making any changes.
1831
/// </summary>
19-
public class AppleInstaller {
20-
21-
readonly ICustomLogger log;
32+
public EnvironmentCheckResult Install (IEnumerable<string>? requestedPlatforms = null, bool dryRun = false)
33+
{
34+
var checker = new EnvironmentChecker (log);
2235

23-
public AppleInstaller (ICustomLogger log)
24-
{
25-
this.log = log ?? throw new ArgumentNullException (nameof (log));
26-
}
36+
log.LogInfo ("Running initial environment check...");
37+
var result = checker.Check ();
2738

28-
/// <summary>
29-
/// Ensures the Apple development environment is ready.
30-
/// When <paramref name="dryRun"/> is true, reports what would be
31-
/// installed without making any changes.
32-
/// Returns the final <see cref="EnvironmentCheckResult"/>.
33-
/// </summary>
34-
/// <param name="requestedPlatforms">
35-
/// Platforms to ensure runtimes for (e.g. "iOS", "tvOS").
36-
/// If null or empty, only existing runtimes are verified.
37-
/// </param>
38-
/// <param name="dryRun">
39-
/// When true, logs planned actions but does not execute them.
40-
/// </param>
41-
public EnvironmentCheckResult Install (IEnumerable<string>? requestedPlatforms = null, bool dryRun = false)
42-
{
43-
var checker = new EnvironmentChecker (log);
44-
45-
// 1. Initial check
46-
log.LogInfo ("Running initial environment check...");
47-
var result = checker.Check ();
48-
49-
// 2. Ensure Command Line Tools
50-
EnsureCommandLineTools (result.CommandLineTools, dryRun);
51-
52-
// 3. Ensure Xcode first-launch packages
53-
if (result.Xcode is not null)
54-
EnsureFirstLaunch (checker, result.Xcode.Path, dryRun);
55-
else
56-
log.LogInfo ("No Xcode found — skipping first-launch check.");
39+
EnsureCommandLineTools (result.CommandLineTools, dryRun);
5740

58-
// 4. Ensure requested runtimes
59-
if (requestedPlatforms is not null)
60-
EnsureRuntimes (result, requestedPlatforms, dryRun);
41+
if (result.Xcode is not null)
42+
EnsureFirstLaunch (checker, dryRun);
43+
else
44+
log.LogInfo ("No Xcode found — skipping first-launch check.");
6145

62-
// 5. Re-check and return
63-
if (!dryRun) {
64-
log.LogInfo ("Running final environment check...");
65-
result = checker.Check ();
66-
}
46+
if (requestedPlatforms is not null)
47+
EnsureRuntimes (result, requestedPlatforms, dryRun);
6748

68-
log.LogInfo ("Install complete. Status: {0}.", result.Status);
69-
return result;
49+
if (!dryRun) {
50+
log.LogInfo ("Running final environment check...");
51+
result = checker.Check ();
7052
}
7153

72-
/// <summary>
73-
/// Triggers CLT installation if not already present.
74-
/// Uses <c>xcode-select --install</c> to launch the macOS installer UI.
75-
/// </summary>
76-
void EnsureCommandLineTools (CommandLineToolsInfo clt, bool dryRun)
77-
{
78-
if (clt.IsInstalled) {
79-
log.LogInfo ("Command Line Tools already installed (v{0}).", clt.Version);
80-
return;
81-
}
54+
log.LogInfo ("Install complete. Status: {0}.", result.Status);
55+
return result;
56+
}
8257

83-
if (dryRun) {
84-
log.LogInfo ("[DRY RUN] Would trigger Command Line Tools installation.");
85-
return;
86-
}
58+
void EnsureCommandLineTools (CommandLineToolsInfo clt, bool dryRun)
59+
{
60+
if (clt.IsInstalled) {
61+
log.LogInfo ("Command Line Tools already installed (v{0}).", clt.Version);
62+
return;
63+
}
8764

88-
const string xcodeSelectPath = "/usr/bin/xcode-select";
89-
90-
log.LogInfo ("Command Line Tools not found. Triggering installation...");
91-
try {
92-
var (exitCode, _, stderr) = ProcessUtils.Exec (xcodeSelectPath, "--install");
93-
if (exitCode == 0)
94-
log.LogInfo ("Command Line Tools installer triggered. Complete the dialog to continue.");
95-
else
96-
log.LogInfo ("xcode-select --install failed (exit {0}): {1}", exitCode, stderr.Trim ());
97-
} catch (System.ComponentModel.Win32Exception ex) {
98-
log.LogInfo ("Could not run xcode-select: {0}", ex.Message);
99-
}
65+
if (dryRun) {
66+
log.LogInfo ("[DRY RUN] Would trigger Command Line Tools installation.");
67+
return;
10068
}
10169

102-
/// <summary>
103-
/// Ensures Xcode first-launch packages are installed.
104-
/// </summary>
105-
void EnsureFirstLaunch (EnvironmentChecker checker, string xcodePath, bool dryRun)
106-
{
107-
if (dryRun) {
108-
log.LogInfo ("[DRY RUN] Would run xcodebuild -runFirstLaunch.");
109-
return;
110-
}
70+
const string xcodeSelectPath = "/usr/bin/xcode-select";
11171

112-
checker.RunFirstLaunch (xcodePath);
72+
log.LogInfo ("Command Line Tools not found. Triggering installation...");
73+
try {
74+
var (exitCode, _, stderr) = ProcessUtils.Exec (xcodeSelectPath, "--install");
75+
if (exitCode == 0)
76+
log.LogInfo ("Command Line Tools installer triggered. Complete the dialog to continue.");
77+
else
78+
log.LogInfo ("xcode-select --install failed (exit {0}): {1}", exitCode, stderr.Trim ());
79+
} catch (System.ComponentModel.Win32Exception ex) {
80+
log.LogInfo ("Could not run xcode-select: {0}", ex.Message);
81+
} catch (InvalidOperationException ex) {
82+
log.LogInfo ("Could not run xcode-select: {0}", ex.Message);
11383
}
84+
}
11485

115-
/// <summary>
116-
/// Ensures simulator runtimes are available for the requested platforms.
117-
/// Downloads missing runtimes via <see cref="RuntimeService.DownloadPlatform"/>.
118-
/// </summary>
119-
void EnsureRuntimes (EnvironmentCheckResult result, IEnumerable<string> requestedPlatforms, bool dryRun)
120-
{
121-
// Build a set of available runtime platforms
122-
var available = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
123-
foreach (var rt in result.Runtimes) {
124-
if (!string.IsNullOrEmpty (rt.Platform))
125-
available.Add (rt.Platform);
126-
}
86+
void EnsureFirstLaunch (EnvironmentChecker checker, bool dryRun)
87+
{
88+
if (dryRun) {
89+
log.LogInfo ("[DRY RUN] Would run xcodebuild -runFirstLaunch.");
90+
return;
91+
}
12792

128-
var runtimeService = new RuntimeService (log);
93+
checker.RunFirstLaunch ();
94+
}
95+
96+
void EnsureRuntimes (EnvironmentCheckResult result, IEnumerable<string> requestedPlatforms, bool dryRun)
97+
{
98+
var available = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
99+
foreach (var rt in result.Runtimes) {
100+
if (!string.IsNullOrEmpty (rt.Platform))
101+
available.Add (rt.Platform);
102+
}
129103

130-
foreach (var platform in requestedPlatforms) {
131-
if (available.Contains (platform)) {
132-
log.LogInfo ("Runtime for '{0}' is already available.", platform);
133-
continue;
134-
}
104+
var runtimeService = new RuntimeService (log);
135105

136-
if (dryRun) {
137-
log.LogInfo ("[DRY RUN] Would download runtime for '{0}'.", platform);
138-
continue;
139-
}
106+
foreach (var platform in requestedPlatforms) {
107+
if (available.Contains (platform)) {
108+
log.LogInfo ("Runtime for '{0}' is already available.", platform);
109+
continue;
110+
}
140111

141-
log.LogInfo ("Downloading runtime for '{0}'...", platform);
142-
runtimeService.DownloadPlatform (platform);
112+
if (dryRun) {
113+
log.LogInfo ("[DRY RUN] Would download runtime for '{0}'.", platform);
114+
continue;
143115
}
116+
117+
log.LogInfo ("Downloading runtime for '{0}'...", platform);
118+
runtimeService.DownloadPlatform (platform);
144119
}
145120
}
146121
}

0 commit comments

Comments
 (0)