コード例 #1
0
ファイル: Harness.cs プロジェクト: yizhang82/xamarin-macios
        public override void Convert(Harness harness)
        {
            var target = new MacBCLTarget()
            {
                Harness  = harness,
                MonoPath = harness.MONO_PATH,
                TestName = Name,
            };

            target.Convert();
        }
コード例 #2
0
ファイル: Harness.cs プロジェクト: hfossli/xamarin-macios
        public virtual void Convert(Harness harness)
        {
            var target = new BCLTarget()
            {
                Harness       = harness,
                MonoPath      = harness.MONO_PATH,
                TestName      = Name,
                WatchMonoPath = harness.WATCH_MONO_PATH
            };

            target.Convert();
        }
コード例 #3
0
ファイル: Program.cs プロジェクト: modulexcite/xamarin-macios
        public static int Main(string[] args)
        {
            var harness = new Harness();

            Action showHelp = null;
            var    os       = new OptionSet()
            {
                { "h|?|help", "Displays the help", (v) => showHelp() },
                { "v|verbose", "Show verbose output", (v) => harness.Verbosity++ },
                // Configure
                { "mac", "Configure for Xamarin.Mac instead of iOS.", (v) => harness.Mac = true },
                { "configure", "Creates project files and makefiles.", (v) => harness.Action = HarnessAction.Configure },
                { "autoconf", "Automatically decide what to configure.", (v) => harness.AutoConf = true },
                { "rootdir=", "The root directory for the tests.", (v) => harness.RootDirectory = v },
                { "project=", "Add a project file to process. This can be specified multiple times.", (v) => harness.TestProjects.Add(v) },
                { "watchos-container-template=", "The directory to use as a template for a watchos container app.", (v) => harness.WatchOSContainerTemplate = v },
                { "watchos-app-template=", "The directory to use as a template for a watchos app.", (v) => harness.WatchOSAppTemplate = v },
                // Run
                { "run=", "Executes a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Run;
                      harness.TestProjects.Add(v);
                  } },
                { "install=", "Installs a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Install;
                      harness.TestProjects.Add(v);
                  } },
                { "sdkroot=", "Where Xcode is", (v) => harness.SdkRoot = v },
                { "target=", "Where to run the project ([ios|watchos|tvos]-[device|simulator|simulator-32|simulator-64]).", (v) => harness.Target = v },
                { "configuration=", "Which configuration to run (defaults to Debug).", (v) => harness.Configuration = v },
                { "logfile=", "Where to store the log.", (v) => harness.LogFile = v },
                { "timeout=", "Timeout for a test run (in minutes). Default is 10 minutes.", (v) => harness.Timeout = double.Parse(v) },
            };

            showHelp = () => {
                os.WriteOptionDescriptions(Console.Out);
                System.Environment.Exit(0);
            };

            var input = os.Parse(args);

            if (input.Count > 0)
            {
                throw new Exception(string.Format("Unknown arguments: {0}", string.Join(", ", input.ToArray())));
            }
            if (harness.Action == HarnessAction.None)
            {
                showHelp();
            }
            return(harness.Execute());
        }
コード例 #4
0
        public static IEnumerable <string> GetLabels(Harness harness, int pull_request)
        {
            var info = DownloadPullRequestInfo(harness, pull_request);

            using (var reader = JsonReaderWriterFactory.CreateJsonReader(info, new XmlDictionaryReaderQuotas())) {
                var doc = new XmlDocument();
                doc.Load(reader);
                var rv = new List <string> ();
                foreach (XmlNode node in doc.SelectNodes("/root/labels/item/name"))
                {
                    rv.Add(node.InnerText);
                }
                return(rv);
            }
        }
コード例 #5
0
        void CreateTodayExtensionProject()
        {
            var csproj = inputProject;
            var suffix = Suffix + "-extension";

            csproj.SetProjectTypeGuids("{EE2C853D-36AF-4FDB-B1AD-8E90477E2198};" + LanguageGuid);
            csproj.SetOutputPath("bin\\$(Platform)\\$(Configuration)" + suffix);
            csproj.SetIntermediateOutputPath("obj\\$(Platform)\\$(Configuration)" + suffix);
            csproj.SetImport(IsFSharp ? "$(MSBuildExtensionsPath)\\Xamarin\\iOS\\Xamarin.iOS.AppExtension.FSharp.targets" : "$(MSBuildExtensionsPath)\\Xamarin\\iOS\\Xamarin.iOS.AppExtension.CSharp.targets");
            csproj.FixInfoPListInclude(suffix);
            csproj.SetOutputType("Library");
            csproj.AddAdditionalDefines("XAMCORE_2_0;XAMCORE_3_0;TODAY_EXTENSION");
            var ext = IsFSharp ? "fs" : "cs";

            csproj.AddCompileInclude("TodayExtensionMain." + ext, Path.Combine(Harness.TodayExtensionTemplate, "TodayExtensionMain." + ext), true);
            csproj.AddInterfaceDefinition(Path.Combine(Harness.TodayExtensionTemplate, "TodayView.storyboard").Replace('/', '\\'));
            csproj.SetExtraLinkerDefs("extra-linker-defs" + ExtraLinkerDefsSuffix + ".xml");
            csproj.FixProjectReferences("-today");
            if (MonoNativeInfo != null)
            {
                MonoNativeInfo.AddProjectDefines(csproj);
                csproj.AddAdditionalDefines("MONO_NATIVE_TODAY");
            }

            Harness.Save(csproj, TodayExtensionProjectPath);

            TodayExtensionGuid = csproj.GetProjectGuid();

            XmlDocument info_plist        = new XmlDocument();
            var         target_info_plist = Path.Combine(TargetDirectory, $"Info{suffix}.plist");

            info_plist.LoadWithoutNetworkAccess(Path.Combine(TargetDirectory, "Info.plist"));
            BundleIdentifier = info_plist.GetCFBundleIdentifier() + "-today";
            info_plist.SetCFBundleIdentifier(BundleIdentifier + ".todayextension");
            info_plist.SetMinimumOSVersion(GetMinimumOSVersion("8.0"));
            info_plist.AddPListStringValue("CFBundlePackageType", "XPC!");
            info_plist.SetCFBundleDisplayName(Name);
            info_plist.AddPListKeyValuePair("NSExtension", "dict",
                                            @"
        <key>NSExtensionMainStoryboard</key>
        <string>TodayView</string>
        <key>NSExtensionPointIdentifier</key>
        <string>com.apple.widget-extension</string>
    ");
            Harness.Save(info_plist, target_info_plist);
        }
コード例 #6
0
        public void Convert()
        {
            var inputProject = new XmlDocument();

            var xml = File.ReadAllText(TemplatePath);

            inputProject.LoadXmlWithoutNetworkAccess(xml);
            inputProject.SetOutputPath("bin\\$(Platform)\\$(Configuration)" + FlavorSuffix);
            inputProject.SetIntermediateOutputPath("obj\\$(Platform)\\$(Configuration)" + FlavorSuffix);
            inputProject.SetAssemblyName(inputProject.GetAssemblyName() + FlavorSuffix);

            AddProjectDefines(inputProject);

            Convert(inputProject);

            Harness.Save(inputProject, ProjectPath);
        }
コード例 #7
0
        public override void Convert()
        {
            var inputProject = new XmlDocument();

            var xml = File.ReadAllText(TemplatePath);

            xml = xml.Replace("#FILES#", GetFileList());
            inputProject.LoadXmlWithoutNetworkAccess(xml);

            // The csproj template is Xamarin.Mac/Full, so make it Modern instead
            inputProject.SetTargetFrameworkIdentifier("Xamarin.Mac");
            inputProject.SetTargetFrameworkVersion("v2.0");
            inputProject.RemoveNode("UseXamMacFullFramework");
            inputProject.AddAdditionalDefines("MOBILE;XAMMAC");
            inputProject.AddReference("Mono.Security");

            Harness.Save(inputProject, ProjectPath);
        }
コード例 #8
0
        void CreateWatchOSLibraryProject()
        {
            var csproj = inputProject;

            csproj.SetProjectTypeGuids("{FC940695-DFE0-4552-9F25-99AF4A5619A1};" + LanguageGuid);
            csproj.SetOutputPath("bin\\$(Platform)\\$(Configuration)" + Suffix);
            csproj.SetIntermediateOutputPath("obj\\$(Platform)\\$(Configuration)" + Suffix);
            csproj.RemoveTargetFrameworkIdentifier();
            csproj.SetPlatformAssembly("Xamarin.WatchOS");
            csproj.SetImport(IsBindingProject ? BindingsImports : Imports);
            csproj.AddAdditionalDefines("XAMCORE_2_0;XAMCORE_3_0");
            csproj.FixProjectReferences(Suffix);
            csproj.SetExtraLinkerDefs("extra-linker-defs" + Suffix + ".xml");
            csproj.FixTestLibrariesReferences(Platform);
            Harness.Save(csproj, WatchOSProjectPath);

            WatchOSGuid = csproj.GetProjectGuid();
        }
コード例 #9
0
        public static string GetPullRequestTargetBranch(Harness harness, int pull_request)
        {
            if (pull_request <= 0)
            {
                return(string.Empty);
            }

            var info = DownloadPullRequestInfo(harness, pull_request);

            if (info.Length == 0)
            {
                return(string.Empty);
            }

            using (var reader = JsonReaderWriterFactory.CreateJsonReader(info, new XmlDictionaryReaderQuotas())) {
                var doc = new XmlDocument();
                doc.Load(reader);
                return(doc.SelectSingleNode("/root/base/ref").InnerText);
            }
        }
コード例 #10
0
ファイル: BCLTarget.cs プロジェクト: zippo227/xamarin-macios
        public override void Convert()
        {
            var testName          = TestName == "mscorlib" ? "corlib" : TestName;
            var main_test_sources = Path.Combine(MonoPath, "mcs", "class", testName, testName + "_test.dll.sources");
            var main_test_files   = File.ReadAllLines(main_test_sources);

            var template_path = Path.Combine(Harness.RootDirectory, "bcl-test", TestName, TestName + "-mac.csproj.template");
            var csproj_input  = File.ReadAllText(template_path);

            var project_path  = Path.Combine(Harness.RootDirectory, "bcl-test", TestName, TestName + "-mac.csproj");
            var csproj_output = project_path;

            var sb = new StringBuilder[2] {
                new StringBuilder(), new StringBuilder()
            };

            Process(main_test_sources, main_test_files, "", sb, 1);

            Harness.Save(csproj_input.Replace("#FILES#", sb[0].ToString()), csproj_output);
        }
コード例 #11
0
ファイル: MonoNativeInfo.cs プロジェクト: wjk/xamarin-macios
        public void Convert()
        {
            var inputProject = new XmlDocument();

            var xml = File.ReadAllText(TemplatePath);

            inputProject.LoadXmlWithoutNetworkAccess(xml);
            inputProject.SetOutputPath("bin\\$(Platform)\\$(Configuration)" + FlavorSuffix);
            inputProject.SetIntermediateOutputPath("obj\\$(Platform)\\$(Configuration)" + FlavorSuffix);
            inputProject.SetAssemblyName(inputProject.GetAssemblyName() + FlavorSuffix);

            var template_info_plist = Path.Combine(Path.GetDirectoryName(TemplatePath), inputProject.GetInfoPListInclude());
            var target_info_plist   = Path.Combine(Path.GetDirectoryName(template_info_plist), "Info" + TemplateSuffix + FlavorSuffix + ".plist");

            SetInfoPListMinimumOSVersion(template_info_plist, target_info_plist);
            inputProject.FixInfoPListInclude(FlavorSuffix, newName: Path.GetFileName(target_info_plist));

            AddProjectDefines(inputProject);

            Harness.Save(inputProject, ProjectPath);
        }
コード例 #12
0
        void CreateWatchOSContainerProject()
        {
            var csproj = new XmlDocument();

            csproj.LoadWithoutNetworkAccess(Path.Combine(Harness.WatchOSContainerTemplate, "Container.csproj"));

            csproj.FindAndReplace("%CONTAINER_PATH%", Path.GetFullPath(Harness.WatchOSContainerTemplate).Replace('/', '\\') + "\\");
            csproj.FindAndReplace("%WATCHAPP_CSPROJ%", Path.GetFileName(WatchOSAppProjectPath));
            csproj.SetProjectReferenceValue(Path.GetFileName(WatchOSAppProjectPath), "Name", Path.GetFileNameWithoutExtension(WatchOSAppProjectPath));
            WatchOSGuid = "{" + Harness.NewStableGuid().ToString().ToUpper() + "}";
            csproj.SetProjectGuid(WatchOSGuid);
            Harness.Save(csproj, WatchOSProjectPath);

            XmlDocument info_plist        = new XmlDocument();
            var         target_info_plist = Path.Combine(TargetDirectory, "Info-watchos.plist");

            info_plist.LoadWithoutNetworkAccess(Path.Combine(Harness.WatchOSContainerTemplate, "Info.plist"));
            info_plist.SetCFBundleIdentifier(BundleIdentifier);
            info_plist.SetCFBundleName(Name);
            Harness.Save(info_plist, target_info_plist);
        }
コード例 #13
0
        static byte[] DownloadPullRequestInfo(Harness harness, int pull_request)
        {
            var path = Path.Combine(harness.LogDirectory, "pr" + pull_request + ".log");

            if (!File.Exists(path))
            {
                Directory.CreateDirectory(harness.LogDirectory);
                using (var client = CreateClient()) {
                    byte [] data;
                    try {
                        data = client.DownloadData($"https://api.github.com/repos/xamarin/xamarin-macios/pulls/{pull_request}");
                        File.WriteAllBytes(path, data);
                        return(data);
                    } catch (WebException we) {
                        harness.Log("Could not load pull request info: {0}\n{1}", we, new StreamReader(we.Response.GetResponseStream()).ReadToEnd());
                        File.WriteAllText(path, string.Empty);
                        return(new byte [0]);
                    }
                }
            }
            return(File.ReadAllBytes(path));
        }
コード例 #14
0
        protected override void ExecuteInternal()
        {
            if (MonoNativeInfo == null)
            {
                return;
            }

            MonoNativeInfo.AddProjectDefines(inputProject);
            inputProject.AddAdditionalDefines("MONO_NATIVE_IOS");

            inputProject.FixInfoPListInclude(Suffix);
            inputProject.SetExtraLinkerDefs("extra-linker-defs" + ExtraLinkerDefsSuffix + ".xml");

            Harness.Save(inputProject, ProjectPath);

            XmlDocument info_plist        = new XmlDocument();
            var         target_info_plist = Path.Combine(TargetDirectory, "Info" + Suffix + ".plist");

            info_plist.LoadWithoutNetworkAccess(Path.Combine(TargetDirectory, "Info.plist"));
            info_plist.SetMinimumOSVersion(GetMinimumOSVersion(info_plist.GetMinimumOSVersion()));
            Harness.Save(info_plist, target_info_plist);
        }
コード例 #15
0
        void CreateWatchOSAppProject()
        {
            var csproj = new XmlDocument();

            csproj.LoadWithoutNetworkAccess(Path.Combine(Harness.WatchOSAppTemplate, "App.csproj"));
            csproj.FindAndReplace("%WATCHAPP_PATH%", Path.GetFullPath(Harness.WatchOSAppTemplate).Replace('/', '\\') + "\\");
            csproj.FindAndReplace("%WATCHEXTENSION_CSPROJ%", Path.GetFileName(WatchOSExtensionProjectPath));
            csproj.SetProjectReferenceValue(Path.GetFileName(WatchOSExtensionProjectPath), "Project", WatchOSExtensionGuid);
            csproj.SetProjectReferenceValue(Path.GetFileName(WatchOSExtensionProjectPath), "Name", Path.GetFileNameWithoutExtension(WatchOSExtensionProjectPath));
            WatchOSAppGuid = "{" + Harness.NewStableGuid().ToString().ToUpper() + "}";
            csproj.SetProjectGuid(WatchOSAppGuid);
            Harness.Save(csproj, WatchOSAppProjectPath);

            XmlDocument info_plist        = new XmlDocument();
            var         target_info_plist = Path.Combine(TargetDirectory, "Info-watchos-app.plist");

            info_plist.LoadWithoutNetworkAccess(Path.Combine(Harness.WatchOSAppTemplate, "Info.plist"));
            info_plist.SetCFBundleIdentifier(BundleIdentifier + ".watchkitapp");
            info_plist.SetPListStringValue("WKCompanionAppBundleIdentifier", BundleIdentifier);
            info_plist.SetPListStringValue("CFBundleName", Name);
            Harness.Save(info_plist, target_info_plist);
        }
コード例 #16
0
        public static IEnumerable <string> GetModifiedFiles(Harness harness, int pull_request)
        {
            var path = Path.Combine(harness.LogDirectory, "pr" + pull_request + "-files.log");

            if (!File.Exists(path))
            {
                var rv = GetModifiedFilesLocally(harness, pull_request);
                if (rv == null || rv.Count() == 0)
                {
                    rv = GetModifiedFilesRemotely(harness, pull_request);
                    if (rv == null)
                    {
                        rv = new string [] { }
                    }
                    ;
                }

                File.WriteAllLines(path, rv.ToArray());
                return(rv);
            }

            return(File.ReadAllLines(path));
        }
コード例 #17
0
        public static void ResolveAllPaths(this XmlDocument csproj, string project_path)
        {
            var dir = System.IO.Path.GetDirectoryName(project_path);
            var nodes_with_paths = new string []
            {
                "AssemblyOriginatorKeyFile",
                "CodesignEntitlements",
                "TestLibrariesDirectory",
                "HintPath",
            };
            var attributes_with_paths = new string [] []
            {
                new string [] { "None", "Include" },
                new string [] { "Compile", "Include" },
                new string [] { "ProjectReference", "Include" },
                new string [] { "InterfaceDefinition", "Include" },
                new string [] { "BundleResource", "Include" },
                new string [] { "EmbeddedResource", "Include" },
                new string [] { "ImageAsset", "Include" },
                new string [] { "GeneratedTestInput", "Include" },
                new string [] { "GeneratedTestOutput", "Include" },
                new string [] { "TestLibrariesInput", "Include" },
                new string [] { "TestLibrariesOutput", "Include" },
                new string [] { "TestLibrariesOutput", "Include" },
                new string [] { "Content", "Include" },
                new string [] { "ObjcBindingApiDefinition", "Include" },
                new string [] { "ObjcBindingCoreSource", "Include" },
                new string [] { "ObjcBindingNativeLibrary", "Include" },
                new string [] { "ObjcBindingNativeFramework", "Include" },
            };
            var nodes_with_variables = new string []
            {
                "MtouchExtraArgs",
            };
            Func <string, string> convert = (input) =>
            {
                if (input [0] == '/')
                {
                    return(input);                    // This is already a full path.
                }
                input = input.Replace('\\', '/');     // make unix-style
                input = System.IO.Path.GetFullPath(System.IO.Path.Combine(dir, input));
                input = input.Replace('/', '\\');     // make windows-style again
                return(input);
            };

            foreach (var key in nodes_with_paths)
            {
                var nodes = csproj.SelectElementNodes(key);
                foreach (var node in nodes)
                {
                    node.InnerText = convert(node.InnerText);
                }
            }
            foreach (var key in nodes_with_variables)
            {
                var nodes = csproj.SelectElementNodes(key);
                foreach (var node in nodes)
                {
                    node.InnerText = node.InnerText.Replace("${ProjectDir}", Harness.Quote(System.IO.Path.GetDirectoryName(project_path)));
                }
            }
            foreach (var kvp in attributes_with_paths)
            {
                var element = kvp [0];
                var attrib  = kvp [1];
                var nodes   = csproj.SelectElementNodes(element);
                foreach (XmlNode node in nodes)
                {
                    var a = node.Attributes [attrib];
                    if (a == null)
                    {
                        continue;
                    }
                    // Fix any default LogicalName values (but don't change existing ones).
                    var ln    = node.SelectElementNodes("LogicalName")?.SingleOrDefault();
                    var links = node.SelectElementNodes("Link");
                    if (ln == null && !links.Any())
                    {
                        ln = csproj.CreateElement("LogicalName", MSBuild_Namespace);
                        node.AppendChild(ln);

                        string logicalName = a.Value;
                        switch (element)
                        {
                        case "BundleResource":
                            if (logicalName.StartsWith("Resources\\", StringComparison.Ordinal))
                            {
                                logicalName = logicalName.Substring("Resources\\".Length);
                            }
                            break;

                        default:
                            break;
                        }
                        ln.InnerText = logicalName;
                    }

                    a.Value = convert(a.Value);
                }
            }
        }
コード例 #18
0
ファイル: Program.cs プロジェクト: zippo227/xamarin-macios
        public static int Main(string[] args)
        {
            var harness = new Harness();

            Action showHelp = null;
            var    os       = new OptionSet()
            {
                { "h|?|help", "Displays the help", (v) => showHelp() },
                { "v|verbose", "Show verbose output", (v) => harness.Verbosity++ },
                { "use-system:", "Use the system version of Xamarin.iOS/Xamarin.Mac or the locally build version. Default: the locally build version.", (v) => harness.UseSystem = v == "1" || v == "true" || string.IsNullOrEmpty(v) },
                // Configure
                { "mac", "Configure for Xamarin.Mac instead of iOS.", (v) => harness.Mac = true },
                { "configure", "Creates project files and makefiles.", (v) => harness.Action = HarnessAction.Configure },
                { "autoconf", "Automatically decide what to configure.", (v) => harness.AutoConf = true },
                { "rootdir=", "The root directory for the tests.", (v) => harness.RootDirectory = v },
                { "project=", "Add a project file to process. This can be specified multiple times.", (v) => harness.IOSTestProjects.Add(new TestProject(v)) },
                { "watchos-container-template=", "The directory to use as a template for a watchos container app.", (v) => harness.WatchOSContainerTemplate = v },
                { "watchos-app-template=", "The directory to use as a template for a watchos app.", (v) => harness.WatchOSAppTemplate = v },
                // Run
                { "run=", "Executes a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Run;
                      harness.IOSTestProjects.Add(new TestProject(v));
                  } },
                { "install=", "Installs a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Install;
                      harness.IOSTestProjects.Add(new TestProject(v));
                  } },
                { "uninstall=", "Uninstalls a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Uninstall;
                      harness.IOSTestProjects.Add(new TestProject(v));
                  } },
                { "sdkroot=", "Where Xcode is", (v) => harness.SdkRoot = v },
                { "target=", "Where to run the project ([ios|watchos|tvos]-[device|simulator|simulator-32|simulator-64]).", (v) => harness.Target = v.ParseAsAppRunnerTarget() },
                { "configuration=", "Which configuration to run (defaults to Debug).", (v) => harness.Configuration = v },
                { "logdirectory=", "Where to store logs.", (v) => harness.LogDirectory = v },
                { "logfile=", "Where to store the log.", (v) => harness.LogFile = v },
                { "timeout=", "Timeout for a test run (in minutes). Default is 10 minutes.", (v) => harness.Timeout = double.Parse(v) },
                { "jenkins:", "Execute test run for jenkins.", (v) =>
                  {
                      harness.JenkinsConfiguration = v;
                      harness.Action = HarnessAction.Jenkins;
                  } },
                { "dry-run", "Only print what would be done.", (v) => harness.DryRun = true },
                { "setenv:", "Set the specified environment variable when running apps.", (v) =>
                  {
                      var split = v.Split('=');
                      harness.EnvironmentVariables [split [0]] = split [1];
                  } },
            };

            showHelp = () => {
                os.WriteOptionDescriptions(Console.Out);
                System.Environment.Exit(0);
            };

            var input = os.Parse(args);

            if (input.Count > 0)
            {
                throw new Exception(string.Format("Unknown arguments: {0}", string.Join(", ", input.ToArray())));
            }
            if (harness.Action == HarnessAction.None)
            {
                showHelp();
            }

            // XS sets this, which breaks pretty much everything if it doesn't match what was passed to --sdkroot.
            Environment.SetEnvironmentVariable("XCODE_DEVELOPER_DIR_PATH", null);

            return(harness.Execute());
        }
コード例 #19
0
ファイル: Harness.cs プロジェクト: ezhangle/xamarin-macios
        public async Task EndCaptureAsync(TimeSpan timeout)
        {
            // Check for crash reports
            var crash_report_search_done    = false;
            var crash_report_search_timeout = timeout.TotalSeconds;
            var watch = new Stopwatch();

            watch.Start();
            do
            {
                var end_crashes = await Harness.CreateCrashReportsSnapshotAsync(Log, !Device, DeviceName);

                end_crashes.ExceptWith(InitialSet);
                Reports = end_crashes;
                if (end_crashes.Count > 0)
                {
                    Log.WriteLine("Found {0} new crash report(s)", end_crashes.Count);
                    List <LogFile> crash_reports;
                    if (!Device)
                    {
                        crash_reports = new List <LogFile> (end_crashes.Count);
                        foreach (var path in end_crashes)
                        {
                            Logs.AddFile(path, $"Crash report: {Path.GetFileName (path)}");
                        }
                    }
                    else
                    {
                        // Download crash reports from the device. We put them in the project directory so that they're automatically deleted on wrench
                        // (if we put them in /tmp, they'd never be deleted).
                        var downloaded_crash_reports = new List <LogFile> ();
                        foreach (var file in end_crashes)
                        {
                            var name = Path.GetFileName(file);
                            var crash_report_target = Logs.Create(name, $"Crash report: {name}");
                            var sb = new StringBuilder();
                            sb.Append(" --download-crash-report=").Append(StringUtils.Quote(file));
                            sb.Append(" --download-crash-report-to=").Append(StringUtils.Quote(crash_report_target.Path));
                            sb.Append(" --sdkroot ").Append(StringUtils.Quote(Harness.XcodeRoot));
                            if (!string.IsNullOrEmpty(DeviceName))
                            {
                                sb.Append(" --devname ").Append(StringUtils.Quote(DeviceName));
                            }
                            var result = await ProcessHelper.ExecuteCommandAsync(Harness.MlaunchPath, sb.ToString(), Log, TimeSpan.FromMinutes(1));

                            if (result.Succeeded)
                            {
                                Log.WriteLine("Downloaded crash report {0} to {1}", file, crash_report_target.Path);
                                crash_report_target = await Harness.SymbolicateCrashReportAsync(Logs, Log, crash_report_target);

                                downloaded_crash_reports.Add(crash_report_target);
                            }
                            else
                            {
                                Log.WriteLine("Could not download crash report {0}", file);
                            }
                        }
                        crash_reports = downloaded_crash_reports;
                    }
                    foreach (var cp in crash_reports)
                    {
                        Harness.LogWrench("@MonkeyWrench: AddFile: {0}", cp.Path);
                        Log.WriteLine("    {0}", cp.Path);
                    }
                    crash_report_search_done = true;
                }
                else
                {
                    if (watch.Elapsed.TotalSeconds > crash_report_search_timeout)
                    {
                        crash_report_search_done = true;
                    }
                    else
                    {
                        Log.WriteLine("No crash reports, waiting a second to see if the crash report service just didn't complete in time ({0})", (int)(crash_report_search_timeout - watch.Elapsed.TotalSeconds));
                        Thread.Sleep(TimeSpan.FromSeconds(1));
                    }
                }
            } while (!crash_report_search_done);
        }
コード例 #20
0
ファイル: Harness.cs プロジェクト: ezhangle/xamarin-macios
 public async Task StartCaptureAsync()
 {
     InitialSet = await Harness.CreateCrashReportsSnapshotAsync(Log, !Device, DeviceName);
 }
コード例 #21
0
        public static void CreateSolution(Harness harness, IEnumerable <Target> targets, Target exeTarget, string infix)
        {
            var folders = new StringBuilder();

            var srcDirectory = Path.Combine(harness.RootDirectory, "..", "src");
            var sln_path     = exeTarget == null?Path.Combine(harness.RootDirectory, "tests-" + infix + ".sln") : Path.Combine(Path.GetDirectoryName(exeTarget.ProjectPath), Path.GetFileNameWithoutExtension(exeTarget.ProjectPath) + ".sln");

            using (var writer = new StringWriter()) {
                writer.WriteLine();
                writer.WriteLine("Microsoft Visual Studio Solution File, Format Version 11.00");
                writer.WriteLine("# Visual Studio 2010");
                foreach (var target in targets)
                {
                    var relatedProjects    = target.GetRelatedProjects();
                    var hasRelatedProjects = relatedProjects != null;
                    var folderGuid         = string.Empty;
                    var useFolders         = hasRelatedProjects && target.IsExe && exeTarget == null;

                    if (hasRelatedProjects && target.IsExe)
                    {
                        if (exeTarget == null)
                        {
                            CreateSolution(harness, targets, target, infix);                              // create a solution for just this test project as well
                        }
                        else if (exeTarget != target)
                        {
                            continue;
                        }
                    }

                    if (useFolders)
                    {
                        folderGuid = Guid.NewGuid().ToString().ToUpperInvariant();
                        writer.WriteLine("Project(\"{{2150E333-8FDC-42A3-9474-1A3956D46DE8}}\") = \"{0}\", \"{0}\", \"{{{1}}}\"", target.Name, folderGuid);
                        writer.WriteLine("EndProject");
                    }

                    writer.WriteLine("Project(\"{3}\") = \"{0}\", \"{1}\", \"{2}\"", Path.GetFileNameWithoutExtension(target.ProjectPath), FixProjectPath(sln_path, Path.GetFullPath(target.ProjectPath)), target.ProjectGuid, target.LanguageGuid);
                    writer.WriteLine("EndProject");

                    if (hasRelatedProjects && target.IsExe)
                    {
                        foreach (var rp in relatedProjects)
                        {
                            writer.WriteLine("Project(\"{3}\") = \"{0}\", \"{1}\", \"{2}\"", Path.GetFileNameWithoutExtension(rp.ProjectPath), FixProjectPath(sln_path, Path.GetFullPath(rp.ProjectPath)), rp.Guid, target.LanguageGuid);
                            writer.WriteLine("EndProject");
                        }
                    }

                    if (useFolders)
                    {
                        folders.AppendFormat("\t\t{0} = {{{1}}}\n", target.ProjectGuid, folderGuid);
                        foreach (var rp in relatedProjects)
                        {
                            folders.AppendFormat("\t\t{0} = {{{1}}}\n", rp.Guid, folderGuid);
                        }
                    }
                }

                // Add reference to MonoTouch.NUnitLite project
                string configuration;
                var    proj_path = Path.GetFullPath(Path.Combine(srcDirectory, "MonoTouch.NUnitLite." + infix + ".csproj"));
                if (!File.Exists(proj_path))
                {
                    proj_path = Path.GetFullPath(Path.Combine(srcDirectory, "MonoTouch.NUnitLite.csproj"));
                }
                AddProjectToSolution(harness, sln_path, writer, proj_path, out configuration);

                writer.WriteLine("Global");

                writer.WriteLine("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
                writer.WriteLine("\t\tDebug|iPhoneSimulator = Debug|iPhoneSimulator");
                writer.WriteLine("\t\tRelease|iPhoneSimulator = Release|iPhoneSimulator");
                writer.WriteLine("\t\tDebug|iPhone = Debug|iPhone");
                writer.WriteLine("\t\tRelease|iPhone = Release|iPhone");
                writer.WriteLine("\t\tRelease-bitcode|iPhone = Release-bitcode|iPhone");
                writer.WriteLine("\t\tDebug|Any CPU = Debug|Any CPU");
                writer.WriteLine("\t\tRelease|Any CPU = Release|Any CPU");
                writer.WriteLine("\tEndGlobalSection");

                writer.WriteLine("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
                var exePlatforms   = new string[] { "iPhone", "iPhoneSimulator" };
                var configurations = new string[] { "Debug", "Release", "Release-bitcode" };
                foreach (var target in targets)
                {
                    if (target.IsExe && exeTarget != null && target != exeTarget)
                    {
                        continue;
                    }

                    foreach (var conf in configurations)
                    {
                        if (target.IsExe)
                        {
                            foreach (var platform in exePlatforms)
                            {
                                writer.WriteLine("\t\t{0}.{1}|{2}.ActiveCfg = {1}|{2}", target.ProjectGuid, conf, platform);
                                writer.WriteLine("\t\t{0}.{1}|{2}.Build.0 = {1}|{2}", target.ProjectGuid, conf, platform);
                            }
                        }
                        else
                        {
                            foreach (var platform in new string[] { "Any CPU", "iPhone", "iPhoneSimulator" })
                            {
                                writer.WriteLine("\t\t{0}.{1}|{2}.ActiveCfg = {1}|Any CPU", target.ProjectGuid, conf, platform);
                                writer.WriteLine("\t\t{0}.{1}|{2}.Build.0 = {1}|Any CPU", target.ProjectGuid, conf, platform);
                            }
                        }
                    }

                    if (target.IsExe)
                    {
                        var relatedProjects = target.GetRelatedProjects();
                        if (relatedProjects != null)
                        {
                            foreach (var rp in relatedProjects)
                            {
                                foreach (var conf in configurations)
                                {
                                    foreach (var platform in exePlatforms)
                                    {
                                        writer.WriteLine("\t\t{0}.{1}|{2}.ActiveCfg = {1}|{2}", rp.Guid, conf, platform);
                                        writer.WriteLine("\t\t{0}.{1}|{2}.Build.0 = {1}|{2}", rp.Guid, conf, platform);
                                    }
                                }
                            }
                        }
                    }
                }
                writer.Write(configuration);
                writer.WriteLine("\tEndGlobalSection");

                if (folders.Length > 0)
                {
                    writer.WriteLine("\tGlobalSection(NestedProjects) = preSolution");
                    writer.Write(folders.ToString());
                    writer.WriteLine("\tEndGlobalSection");
                }

                writer.WriteLine("EndGlobal");

                harness.Save(writer, sln_path);
            }
        }
コード例 #22
0
        void CreateWatchOSExtensionProject()
        {
            var csproj = inputProject;
            var suffix = Suffix + "-extension";

            // Remove unused configurations
            csproj.DeleteConfiguration("iPhone", "Release-bitcode");
            csproj.DeleteConfiguration("iPhone", "Release64");
            csproj.DeleteConfiguration("iPhone", "Debug64");

            csproj.FixArchitectures("i386", "ARMv7k", "iPhone", "Release32");
            csproj.FixArchitectures("i386", "ARMv7k", "iPhone", "Debug32");

            // add Release64_32 and set the correct architecture
            csproj.CloneConfiguration("iPhone", "Release", "Release64_32");
            csproj.FixArchitectures("i386", "ARM64_32", "iPhone", "Release64_32");

            // add Debug64_32 and set the correct architecture
            csproj.CloneConfiguration("iPhone", "Debug", "Debug64_32");
            csproj.FixArchitectures("i386", "ARM64_32", "iPhone", "Debug64_32");

            csproj.FixArchitectures(SimulatorArchitectures, DeviceArchitectures, "iPhoneSimulator", "Debug");
            csproj.FixArchitectures(SimulatorArchitectures, DeviceArchitectures, "iPhoneSimulator", "Release");
            csproj.FixArchitectures(SimulatorArchitectures, DeviceArchitectures, "iPhone", "Debug");
            csproj.FixArchitectures(SimulatorArchitectures, DeviceArchitectures, "iPhone", "Release");

            csproj.SetProjectTypeGuids("{1E2E965C-F6D2-49ED-B86E-418A60C69EEF};" + LanguageGuid);
            csproj.SetOutputPath("bin\\$(Platform)\\$(Configuration)" + suffix);
            csproj.SetIntermediateOutputPath("obj\\$(Platform)\\$(Configuration)" + suffix);
            csproj.RemoveTargetFrameworkIdentifier();
            csproj.SetPlatformAssembly("Xamarin.WatchOS");
            csproj.SetImport(IsFSharp ? "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.AppExtension.FSharp.targets" : "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.AppExtension.CSharp.targets");
            csproj.FixProjectReferences("-watchos");

            csproj.FixInfoPListInclude(suffix);
            csproj.SetOutputType("Library");
            csproj.AddAdditionalDefines("BITCODE", "iPhone", "Release");
            csproj.AddAdditionalDefines("XAMCORE_2_0;XAMCORE_3_0;FEATURE_NO_BSD_SOCKETS;MONOTOUCH_WATCH;");
            csproj.RemoveReferences("OpenTK-1.0");
            var ext = IsFSharp ? "fs" : "cs";

            csproj.AddCompileInclude("InterfaceController." + ext, Path.Combine(Harness.WatchOSExtensionTemplate, "InterfaceController." + ext));
            csproj.SetExtraLinkerDefs("extra-linker-defs" + ExtraLinkerDefsSuffix + ".xml");
            csproj.SetMtouchUseBitcode(true, "iPhone", "Release");
            csproj.SetMtouchUseLlvm(true, "iPhone", "Release");

            if (MonoNativeInfo != null)
            {
                csproj.AddAdditionalDefines("MONO_NATIVE_WATCH");
                MonoNativeHelper.AddProjectDefines(csproj, MonoNativeInfo.Flavor);
                MonoNativeHelper.RemoveSymlinkMode(csproj);
            }

            // Not linking a watch extensions requires passing -Os to the native compiler.
            // https://github.com/mono/mono/issues/9867
            var configurations = new string [] { "Debug", "Debug32", "Debug64_32", "Release", "Release32", "Release64_32" };

            foreach (var c in configurations)
            {
                var flags = "-fembed-bitcode-marker";
                if (csproj.GetMtouchLink("iPhone", c) == "None")
                {
                    flags += " -Os";
                }

                csproj.AddExtraMtouchArgs($"--gcc_flags='{flags}'", "iPhone", c);
            }

            Harness.Save(csproj, WatchOSExtensionProjectPath);

            WatchOSExtensionGuid = csproj.GetProjectGuid();

            XmlDocument info_plist        = new XmlDocument();
            var         target_info_plist = Path.Combine(TargetDirectory, $"Info{Suffix}-extension.plist");

            info_plist.LoadWithoutNetworkAccess(Path.Combine(TargetDirectory, "Info.plist"));
            BundleIdentifier = info_plist.GetCFBundleIdentifier() + "_watch";
            if (BundleIdentifier.Length >= 58)
            {
                BundleIdentifier = BundleIdentifier.Substring(0, 57);                  // If the main app's bundle id is 58 characters (or sometimes more), then the watch extension crashes at launch. radar #29847128.
            }
            info_plist.SetCFBundleIdentifier(BundleIdentifier + ".watchkitapp.watchkitextension");
            info_plist.SetMinimumOSVersion(GetMinimumOSVersion("2.0"));
            info_plist.SetUIDeviceFamily(4);
            info_plist.AddPListStringValue("RemoteInterfacePrincipleClass", "InterfaceController");
            info_plist.AddPListKeyValuePair("NSExtension", "dict", string.Format(
                                                @"
    <key>NSExtensionAttributes</key>
    <dict>
    <key>WKAppBundleIdentifier</key>
    <string>{0}.watchkitapp</string>
    </dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.watchkit</string>
", BundleIdentifier));
            if (!info_plist.ContainsKey("NSAppTransportSecurity"))
            {
                info_plist.AddPListKeyValuePair("NSAppTransportSecurity", "dict",
                                                @"
		  <key>NSAllowsArbitraryLoads</key>
		  <true/>
		"        );
            }
            Harness.Save(info_plist, target_info_plist);
        }
コード例 #23
0
        static IEnumerable <string> GetModifiedFilesRemotely(Harness harness, int pull_request)
        {
            var path = Path.Combine(harness.LogDirectory, "pr" + pull_request + "-remote-files.log");

            if (!File.Exists(path))
            {
                Directory.CreateDirectory(harness.LogDirectory);
                using (var client = CreateClient()) {
                    var rv  = new List <string> ();
                    var url = $"https://api.github.com/repos/xamarin/xamarin-macios/pulls/{pull_request}/files?per_page=100";                     // 100 items per page is max
                    do
                    {
                        byte [] data;
                        try {
                            data = client.DownloadData(url);
                        } catch (WebException we) {
                            harness.Log("Could not load pull request files: {0}\n{1}", we, new StreamReader(we.Response.GetResponseStream()).ReadToEnd());
                            File.WriteAllText(path, string.Empty);
                            return(new string [] { });
                        }
                        var reader = JsonReaderWriterFactory.CreateJsonReader(data, new XmlDictionaryReaderQuotas());
                        var doc    = new XmlDocument();
                        doc.Load(reader);
                        foreach (XmlNode node in doc.SelectNodes("/root/item/filename"))
                        {
                            rv.Add(node.InnerText);
                        }

                        url = null;

                        var link = client.ResponseHeaders ["Link"];
                        try {
                            if (link != null)
                            {
                                var ltIdx = link.IndexOf('<');
                                var gtIdx = link.IndexOf('>', ltIdx + 1);
                                while (ltIdx >= 0 && gtIdx > ltIdx)
                                {
                                    var linkUrl = link.Substring(ltIdx + 1, gtIdx - ltIdx - 1);
                                    if (link [gtIdx + 1] != ';')
                                    {
                                        break;
                                    }
                                    var    commaIdx = link.IndexOf(',', gtIdx + 1);
                                    string rel;
                                    if (commaIdx != -1)
                                    {
                                        rel = link.Substring(gtIdx + 3, commaIdx - gtIdx - 3);
                                    }
                                    else
                                    {
                                        rel = link.Substring(gtIdx + 3);
                                    }

                                    if (rel == "rel=\"next\"")
                                    {
                                        url = linkUrl;
                                        break;
                                    }

                                    if (commaIdx == -1)
                                    {
                                        break;
                                    }

                                    ltIdx = link.IndexOf('<', commaIdx);
                                    gtIdx = link.IndexOf('>', ltIdx + 1);
                                }
                            }
                        } catch (Exception e) {
                            harness.Log("Could not paginate github response: {0}: {1}", link, e.Message);
                        }
                    } while (url != null);
                    File.WriteAllLines(path, rv.ToArray());
                    return(rv);
                }
            }

            return(File.ReadAllLines(path));
        }
コード例 #24
0
 public MacBCLTestInfo(Harness harness, string testName) : base(harness, testName)
 {
 }
コード例 #25
0
        void CreateWatchOSExtensionProject()
        {
            var csproj = inputProject;
            var suffix = "-watchos-extension";

            csproj.SetProjectTypeGuids("{1E2E965C-F6D2-49ED-B86E-418A60C69EEF};" + LanguageGuid);
            csproj.SetOutputPath("bin\\$(Platform)\\$(Configuration)" + suffix);
            csproj.SetIntermediateOutputPath("obj\\$(Platform)\\$(Configuration)" + suffix);
            csproj.RemoveTargetFrameworkIdentifier();
            csproj.SetPlatformAssembly("Xamarin.WatchOS");
            csproj.SetImport(IsFSharp ? "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.AppExtension.FSharp.targets" : "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.AppExtension.CSharp.targets");
            csproj.FixProjectReferences("-watchos");
            csproj.FixArchitectures("i386", "ARMv7k");
            csproj.FixInfoPListInclude(suffix);
            csproj.SetOutputType("Library");
            csproj.AddAdditionalDefines("BITCODE", "iPhone", "Release");
            csproj.AddAdditionalDefines("XAMCORE_2_0;XAMCORE_3_0;FEATURE_NO_BSD_SOCKETS");
            csproj.RemoveReferences("OpenTK-1.0");
            var ext = IsFSharp ? "fs" : "cs";

            csproj.AddCompileInclude("InterfaceController." + ext, Path.Combine(Harness.WatchOSExtensionTemplate, "InterfaceController." + ext));
            csproj.SetExtraLinkerDefs("extra-linker-defs" + Suffix + ".xml");
            csproj.SetMtouchUseBitcode(true, "iPhone", "Release");
            csproj.SetMtouchUseLlvm(true, "iPhone", "Release");

            Harness.Save(csproj, WatchOSExtensionProjectPath);

            WatchOSExtensionGuid = csproj.GetProjectGuid();

            XmlDocument info_plist        = new XmlDocument();
            var         target_info_plist = Path.Combine(TargetDirectory, "Info-watchos-extension.plist");

            info_plist.LoadWithoutNetworkAccess(Path.Combine(TargetDirectory, "Info.plist"));
            BundleIdentifier = info_plist.GetCFBundleIdentifier() + "-watch";
            if (BundleIdentifier.Length >= 58)
            {
                BundleIdentifier = BundleIdentifier.Substring(0, 57);                  // If the main app's bundle id is 58 characters (or sometimes more), then the watch extension crashes at launch. radar #29847128.
            }
            info_plist.SetCFBundleIdentifier(BundleIdentifier + ".watchkitapp.watchkitextension");
            info_plist.SetMinimumOSVersion("2.0");
            info_plist.SetUIDeviceFamily(4);
            info_plist.AddPListStringValue("RemoteInterfacePrincipleClass", "InterfaceController");
            info_plist.AddPListKeyValuePair("NSExtension", "dict", string.Format(
                                                @"
    <key>NSExtensionAttributes</key>
    <dict>
    <key>WKAppBundleIdentifier</key>
    <string>{0}.watchkitapp</string>
    </dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.watchkit</string>
", BundleIdentifier));
            if (!info_plist.ContainsKey("NSAppTransportSecurity"))
            {
                info_plist.AddPListKeyValuePair("NSAppTransportSecurity", "dict",
                                                @"
		  <key>NSAllowsArbitraryLoads</key>
		  <true/>
		"        );
            }
            Harness.Save(info_plist, target_info_plist);
        }
コード例 #26
0
 public MonoNativeInfo(Harness harness, MonoNativeFlavor flavor)
 {
     Harness = harness;
     Flavor  = flavor;
 }
コード例 #27
0
ファイル: MonoNativeInfo.cs プロジェクト: wjk/xamarin-macios
 public MacMonoNativeInfo(Harness harness, MonoNativeFlavor flavor)
     : base(harness, flavor)
 {
 }
コード例 #28
0
 public static void CreateSolution(Harness harness, IEnumerable <Target> targets, string infix)
 {
     CreateSolution(harness, targets, null, infix);
 }
コード例 #29
0
ファイル: BCLTestInfo.cs プロジェクト: ye-man/xamarin-macios
 public BCLTestInfo(Harness harness, string testName)
 {
     Harness  = harness;
     TestName = testName;
 }
コード例 #30
0
        public static int Main(string[] args)
        {
            var harness = new Harness();

            Action showHelp = null;
            var    os       = new OptionSet()
            {
                { "h|?|help", "Displays the help", (v) => showHelp() },
                { "v|verbose", "Show verbose output", (v) => harness.Verbosity++ },
                { "use-system:", "Use the system version of Xamarin.iOS/Xamarin.Mac or the locally build version. Default: the locally build version.", (v) => harness.UseSystem = v == "1" || v == "true" || string.IsNullOrEmpty(v) },
                // Configure
                { "mac", "Configure for Xamarin.Mac instead of iOS.", (v) => harness.Mac = true },
                { "configure", "Creates project files and makefiles.", (v) => harness.Action = HarnessAction.Configure },
                { "autoconf", "Automatically decide what to configure.", (v) => harness.AutoConf = true },
                { "rootdir=", "The root directory for the tests.", (v) => harness.RootDirectory = v },
                { "project=", "Add a project file to process. This can be specified multiple times.", (v) => harness.IOSTestProjects.Add(new iOSTestProject(v)) },
                { "watchos-container-template=", "The directory to use as a template for a watchos container app.", (v) => harness.WatchOSContainerTemplate = v },
                { "watchos-app-template=", "The directory to use as a template for a watchos app.", (v) => harness.WatchOSAppTemplate = v },
                // Run
                { "run=", "Executes a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Run;
                      harness.IOSTestProjects.Add(new iOSTestProject(v));
                  } },
                { "install=", "Installs a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Install;
                      harness.IOSTestProjects.Add(new iOSTestProject(v));
                  } },
                { "uninstall=", "Uninstalls a project.", (v) =>
                  {
                      harness.Action = HarnessAction.Uninstall;
                      harness.IOSTestProjects.Add(new iOSTestProject(v));
                  } },
                { "sdkroot=", "Where Xcode is", (v) => harness.SdkRoot = v },
                { "sdkroot94=", "Where Xcode 9.4 is", (v) => harness.SdkRoot94 = v },
                { "target=", "Where to run the project ([ios|watchos|tvos]-[device|simulator|simulator-32|simulator-64]).", (v) => harness.Target = v.ParseAsAppRunnerTarget() },
                { "configuration=", "Which configuration to run (defaults to Debug).", (v) => harness.Configuration = v },
                { "logdirectory=", "Where to store logs.", (v) => harness.LogDirectory = v },
                { "logfile=", "Where to store the log.", (v) => harness.LogFile = v },
                { "timeout=", "Timeout for a test run (in minutes). Default is 10 minutes.", (v) => harness.Timeout = double.Parse(v) },
                { "jenkins:", "Execute test run for jenkins.", (v) =>
                  {
                      harness.JenkinsConfiguration = v;
                      harness.Action = HarnessAction.Jenkins;
                  } },
                { "dry-run", "Only print what would be done.", (v) => harness.DryRun = true },
                { "setenv:", "Set the specified environment variable when running apps.", (v) =>
                  {
                      var split = v.Split('=');
                      harness.EnvironmentVariables [split [0]] = split [1];
                  } },
                { "label=", "Comma-separated list of labels to select which tests to run.", (v) =>
                  {
                      harness.Labels.UnionWith(v.Split(new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries));
                  } },
                { "markdown-summary=", "The path where a summary (in Markdown format) will be written.", (v) => harness.MarkdownSummaryPath = v },
                { "periodic-command=", "A command to execute periodically.", (v) => harness.PeriodicCommand = v },
                { "periodic-command-arguments=", "Arguments to the command to execute periodically.", (v) => harness.PeriodicCommandArguments = v },
                { "periodic-interval=", "An interval (in minutes) between every attempt to execute the periodic command.", (v) => harness.PeriodicCommandInterval = TimeSpan.FromMinutes(double.Parse(v)) },
                { "include-system-permission-tests:", "If tests that require system permissions (which could cause the OS to launch dialogs that hangs the test) should be executed or not. Default is to include such tests.", (v) => harness.IncludeSystemPermissionTests = ParseBool(v, "include-system-permission-tests") },
            };

            showHelp = () => {
                os.WriteOptionDescriptions(Console.Out);
                System.Environment.Exit(0);
            };

            var input = os.Parse(args);

            if (input.Count > 0)
            {
                throw new Exception(string.Format("Unknown arguments: {0}", string.Join(", ", input.ToArray())));
            }
            if (harness.Action == HarnessAction.None)
            {
                showHelp();
            }

            // XS sets this, which breaks pretty much everything if it doesn't match what was passed to --sdkroot.
            Environment.SetEnvironmentVariable("XCODE_DEVELOPER_DIR_PATH", null);

            return(harness.Execute());
        }