Skip to content

Commit c4f50ab

Browse files
committed
Better support no installed JDKs on macOS (#48)
What happens if there is no JDK installed on macOS? $ mv ~/Library/Developer/Xamarin/jdk ~/Library/Developer/Xamarin/jdk.bk $ sudo mv /Library/Java/JavaVirtualMachines /Library/Java/JavaVirtualMachines.bk `JdkInfo` doesn't like this, which is to be expected, but *how* it doesn't like it is...bad: $ csharp -r:bin/Debug/Xamarin.Android.Tools.AndroidSdk.dll csharp> Xamarin.Android.Tools.JdkInfo.GetKnownSystemJdkInfos(); Error getting SDK info: System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1. at System.Xml.XmlTextReaderImpl.Throw (System.Exception e) at System.Xml.XmlTextReaderImpl.Throw (System.String res, System.String arg) at System.Xml.XmlTextReaderImpl.Throw (System.String res) at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace () at System.Xml.XmlTextReaderImpl.ParseDocumentContent () at System.Xml.XmlTextReaderImpl.Read () at System.Xml.XmlReader.MoveToContent () at System.Xml.Linq.XElement.Load (System.Xml.XmlReader reader, System.Xml.Linq.LoadOptions options) at System.Xml.Linq.XElement.Parse (System.String text, System.Xml.Linq.LoadOptions options) at System.Xml.Linq.XElement.Parse (System.String text) at Xamarin.Android.Tools.JdkInfo+<GetLibexecJdkPaths>d__54.MoveNext () ... Er, what? The problem is the output of `/usr/libexec/java_home -X`: $ /usr/libexec/java_home -X Unable to find any JVMs matching version "(null)". <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array/> </plist> No Java runtime present, try --request to install. What's happening is that `java_home` is writing XML to stdout, and an error message to stderr. `ProcessUtils.Exec()`, meanwhile, was *merging **both*** `stdout` and `stderr` into *one* stream, and the result was *not* valid XML, hence the `XmlException`. The fix? Allow `stderr` to be separate from `stdout`, so that `JdkInfo.GetLibexecJdkPaths()` can get valid XML. Additionally, because I'm finding it increasingly annoying needing to provide the `logger` parameter to `AndroidSdkInfo`/etc., update the `AndroidSdkInfo` constructor so that `logger` is *optional*. If it isn't provided, we'll write our log messages to `System.Console`.
1 parent 66fea14 commit c4f50ab

File tree

4 files changed

+7
-13
lines changed

4 files changed

+7
-13
lines changed

src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ public class AndroidSdkInfo
1010
{
1111
AndroidSdkBase sdk;
1212

13-
public AndroidSdkInfo (Action<TraceLevel, string> logger, string androidSdkPath = null, string androidNdkPath = null, string javaSdkPath = null)
13+
public AndroidSdkInfo (Action<TraceLevel, string> logger = null, string androidSdkPath = null, string androidNdkPath = null, string javaSdkPath = null)
1414
{
15-
if (logger == null)
16-
throw new ArgumentNullException (nameof (logger));
15+
logger = logger ?? DefaultConsoleLogger;
1716

1817
sdk = CreateSdk (logger);
1918
sdk.Initialize (androidSdkPath, androidNdkPath, javaSdkPath);

src/Xamarin.Android.Tools.AndroidSdk/JdkInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ static IEnumerable<string> GetLibexecJdkPaths (Action<TraceLevel, string> logger
337337
if (string.IsNullOrEmpty (e.Data))
338338
return;
339339
xml.Append (e.Data);
340-
});
340+
}, includeStderr: false);
341341
var plist = XElement.Parse (xml.ToString ());
342342
foreach (var info in plist.Elements ("array").Elements ("dict")) {
343343
var JVMHomePath = (XNode) info.Elements ("key").FirstOrDefault (e => e.Value == "JVMHomePath");

src/Xamarin.Android.Tools.AndroidSdk/ProcessUtils.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public static Task<TResult> ExecuteToolAsync<TResult> (string exe, Func<string,
131131
return tcs.Task;
132132
}
133133

134-
internal static void Exec (ProcessStartInfo processStartInfo, DataReceivedEventHandler output)
134+
internal static void Exec (ProcessStartInfo processStartInfo, DataReceivedEventHandler output, bool includeStderr = true)
135135
{
136136
processStartInfo.UseShellExecute = false;
137137
processStartInfo.RedirectStandardInput = false;
@@ -144,7 +144,9 @@ internal static void Exec (ProcessStartInfo processStartInfo, DataReceivedEventH
144144
StartInfo = processStartInfo,
145145
};
146146
p.OutputDataReceived += output;
147-
p.ErrorDataReceived += output;
147+
if (includeStderr) {
148+
p.ErrorDataReceived += output;
149+
}
148150

149151
using (p) {
150152
p.Start ();

src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ public void FixtureTearDown ()
4242
Directory.Delete (PreferredJdksOverridePath, recursive: true);
4343
}
4444

45-
[Test]
46-
public void Constructor_NullLogger ()
47-
{
48-
Action<TraceLevel, string> logger = null;
49-
Assert.Throws<ArgumentNullException> (() => new AndroidSdkInfo (logger));
50-
}
51-
5245
[Test]
5346
public void Constructor_Paths ()
5447
{

0 commit comments

Comments
 (0)