Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 10 additions & 54 deletions Xamarin.MacDev/AppleSdkSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
using System.IO;

namespace Xamarin.MacDev {
[Obsolete ("Use 'XcodeLocator' instead, this class keeps static state, which causes various problems when the state isn't updated.")]
public static class AppleSdkSettings {
static readonly string SettingsPath;

Expand Down Expand Up @@ -104,23 +105,11 @@ public static void SetConfiguredSdkLocation (string location)

public static string GetConfiguredSdkLocation ()
{
PDictionary plist = null;
PString value;

try {
if (File.Exists (SettingsPath))
plist = PDictionary.FromFile (SettingsPath, out var _);
} catch (FileNotFoundException) {
}

// First try the configured location in Visual Studio
if (plist != null && plist.TryGetValue ("AppleSdkRoot", out value) && !string.IsNullOrEmpty (value?.Value)) {
LoggingService.LogInfo (string.Format ("An Xcode location was found in the file '{0}': {1}", SettingsPath, value.Value));
return value.Value;
}
if (XcodeLocator.TryReadSettingsPath (LoggingServiceLogger.Instance, SettingsPath, out var path))
return path;

// Then check the system's default Xcode
if (TryGetSystemXcode (out var path))
if (TryGetSystemXcode (out path))
return path;

// Finally return the hardcoded default
Expand All @@ -143,14 +132,11 @@ static void SetInvalid ()

static AppleSdkSettings ()
{
var home = Environment.GetFolderPath (Environment.SpecialFolder.UserProfile);

SettingsPath = Path.Combine (home, "Library", "Preferences", "maui", "Settings.plist");

if (!File.Exists (SettingsPath)) {
var oldSettings = Path.Combine (home, "Library", "Preferences", "Xamarin", "Settings.plist");
if (File.Exists (oldSettings))
SettingsPath = oldSettings;
foreach (var path in XcodeLocator.SettingsPathCandidates) {
if (!File.Exists (path))
continue;
SettingsPath = path;
break;
}

Directory.CreateDirectory (Path.GetDirectoryName (SettingsPath));
Expand All @@ -160,37 +146,7 @@ static AppleSdkSettings ()

public static bool TryGetSystemXcode (out string path)
{
path = null;
if (!File.Exists ("/usr/bin/xcode-select"))
return false;

try {
using var process = new Process ();
process.StartInfo.FileName = "/usr/bin/xcode-select";
process.StartInfo.Arguments = "--print-path";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.Start ();
var stdout = process.StandardOutput.ReadToEnd ();
process.WaitForExit ();

stdout = stdout.Trim ();
if (Directory.Exists (stdout)) {
if (stdout.EndsWith ("/Contents/Developer", StringComparison.Ordinal))
stdout = stdout.Substring (0, stdout.Length - "/Contents/Developer".Length);

path = stdout;
LoggingService.LogInfo (string.Format ("Using the Xcode location configured for this system (found using 'xcode-select -p'): {0}", path));
return true;
}

LoggingService.LogInfo ("The system's Xcode location {0} does not exist", stdout);

return false;
} catch (Exception e) {
LoggingService.LogInfo ("Could not get the system's Xcode location: {0}", e);
return false;
}
return XcodeLocator.TryGetSystemXcode (LoggingServiceLogger.Instance, out path);
}

public static void Init ()
Expand Down
58 changes: 57 additions & 1 deletion Xamarin.MacDev/LoggingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,63 @@ public static void LogDebug (string messageFormat, params object [] args)
public interface ICustomLogger {
void LogError (string message, Exception ex);
void LogWarning (string messageFormat, params object [] args);
void LogInfo (string messageFormat, object [] args);
void LogInfo (string messageFormat, params object [] args);
void LogDebug (string messageFormat, params object [] args);
}

#nullable enable
// This is a logger that prints to Console.[Error.]WriteLine.
public class ConsoleLogger : ICustomLogger {
public static ConsoleLogger Instance = new ();

public void LogError (string message, Exception? ex)
{
if (ex is null) {
Console.Error.WriteLine ($"Error: {message}");
} else {
Console.Error.WriteLine ($"Error: {message} ({ex})");
}
}

public void LogWarning (string messageFormat, params object [] args)
{
Console.WriteLine ("Warning: " + messageFormat, args);
}

public void LogInfo (string messageFormat, params object [] args)
{
Console.WriteLine ("Info: " + messageFormat, args);
}

public void LogDebug (string messageFormat, params object [] args)
{
Console.WriteLine ("Debug: " + messageFormat, args);
}
}

// This is a logger that just calls the static LoggingService class.
// To be used only until all code can switch away from static state.
public class LoggingServiceLogger : ICustomLogger {
public static LoggingServiceLogger Instance = new ();

public void LogError (string message, Exception? ex)
{
LoggingService.LogError (message, ex);
}

public void LogWarning (string messageFormat, params object [] args)
{
LoggingService.LogWarning (messageFormat, args);
}

public void LogInfo (string messageFormat, params object [] args)
{
LoggingService.LogInfo (messageFormat, args);
}

public void LogDebug (string messageFormat, params object [] args)
{
LoggingService.LogDebug (messageFormat, args);
}
}
}
80 changes: 80 additions & 0 deletions Xamarin.MacDev/PathUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.IO;
using System.Runtime.InteropServices;

#nullable enable

namespace Xamarin.MacDev {
internal static class PathUtils {
struct Timespec {
public IntPtr tv_sec;
public IntPtr tv_nsec;
}

struct Stat { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
public uint st_dev;
public ushort st_mode;
public ushort st_nlink;
public ulong st_ino;
public uint st_uid;
public uint st_gid;
public uint st_rdev;
public Timespec st_atimespec;
public Timespec st_mtimespec;
public Timespec st_ctimespec;
public Timespec st_birthtimespec;
public ulong st_size;
public ulong st_blocks;
public uint st_blksize;
public uint st_flags;
public uint st_gen;
public uint st_lspare;
public ulong st_qspare_1;
public ulong st_qspare_2;
}

[DllImport ("/usr/lib/libc.dylib", EntryPoint = "lstat$INODE64", SetLastError = true)]
static extern int lstat_x64 (string file_name, out Stat buf);

[DllImport ("/usr/lib/libc.dylib", EntryPoint = "lstat", SetLastError = true)]
static extern int lstat_arm64 (string file_name, out Stat buf);

static int lstat (string path, out Stat buf)
{
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) {
return lstat_arm64 (path, out buf);
} else {
return lstat_x64 (path, out buf);
}
}

public static bool IsSymlink (string file)
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
var attr = File.GetAttributes (file);
return attr.HasFlag (FileAttributes.ReparsePoint);
}
Stat buf;
var rv = lstat (file, out buf);
if (rv != 0)
throw new Exception (string.Format ("Could not lstat '{0}': {1}", file, Marshal.GetLastWin32Error ()));
const int S_IFLNK = 40960;
return (buf.st_mode & S_IFLNK) == S_IFLNK;
}

public static bool IsSymlinkOrHasParentSymlink (string directoryOrFile)
{
if (IsSymlink (directoryOrFile))
return true;

if (!Directory.Exists (directoryOrFile))
return false;

var parentDirectory = Path.GetDirectoryName (directoryOrFile);
if (string.IsNullOrEmpty (parentDirectory) || parentDirectory == directoryOrFile)
return false;

return IsSymlinkOrHasParentSymlink (parentDirectory);
}
}
}
Loading