public bool CreatePodfile(Podfile podfile, string podfilePath)
        {
            if (CancellationToken.IsCancellationRequested)
            {
                Log.LogError("Task was canceled.");
                return(false);
            }

            var podfileContents =
                $"{(podfile.UseFrameworks ? "use_frameworks!" : "")}\n" +
                $"platform :{podfile.PlatformName}, '{podfile.PlatformVersion}'\n" +
                $"target '{podfile.TargetName}' do\n";

            foreach (var pod in podfile.Pods)
            {
                podfileContents +=
                    $"    pod '{pod.Id}', '{pod.Version}'\n";
            }
            podfileContents +=
                $"end";
            Ssh.CreateDirectory(CrossPath.GetDirectoryNameSsh(podfilePath));
            using (var stream = Utilities.GetStreamFromText(podfileContents))
            {
                Ssh.CreateFile(stream, podfilePath);
            }

            return(true);
        }
        public bool ExecuteLaunchCtlCommand(string[] arguments, int checkInterval = 600, string workingDirectory = null)
        {
            var binary  = arguments.FirstOrDefault();
            var options = new StartOptions
            {
                Id       = Process.GetCurrentProcess().Id.ToString(),
                DateTime = DateTime.Now
            };
            var labelName = $"com.xamarin.nativebuild.tasks.{options.GetFormattedDateTime()}.{options.Id}.{Path.GetFileNameWithoutExtension(binary)}".ToLowerInvariant();
            var root      = $"/tmp/{labelName}";

            var outputLog = CrossPath.CombineSsh(root, "output.log");
            var errorLog  = CrossPath.CombineSsh(root, "error.log");
            var appPList  = CrossPath.CombineSsh(root, "app.plist");

            // upload the plist
            var plist = CreatePList(labelName, outputLog, errorLog, arguments, workingDirectory);

            CreateDirectory(root);
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(plist)))
            {
                CreateFile(stream, appPList);
            }

            // create the logs and start the process
            var launchctl = ExecuteCommand($"touch {outputLog}; touch {errorLog}; launchctl load -S Aqua {appPList}");

            if (!WasSuccess(launchctl))
            {
                Log.LogError($"Unable to starting {binary}: {launchctl.Result}");
                return(false);
            }

            // tail and stream the output
            var tailOutput = ExecuteCommandStream($"tail -f {outputLog} & while launchctl list {labelName} &> /dev/null; do sleep {checkInterval / 1000}; done; kill $!;");

            if (!WasSuccess(tailOutput))
            {
                Log.LogError($"There was an error reading the output: {tailOutput.Result}");
                return(false);
            }

            // get the errors
            var tailError = ExecuteCommand($"cat {errorLog}");

            if (!WasSuccess(tailError))
            {
                Log.LogError($"There was an error reading the error log: {tailError.Result}");
                return(false);
            }
            else if (!string.IsNullOrEmpty(tailError.Result))
            {
                Log.LogError($"There was an error: {tailError.Result}");
                return(false);
            }

            return(true);
        }
        public bool CreatePodfileXCodeProject(string podfileRoot, Podfile podfile, bool?noRepoUpdate = null)
        {
            if (CancellationToken.IsCancellationRequested)
            {
                Log.LogError("Task was canceled.");
                return(false);
            }

            var podfilePath     = CrossPath.CombineSsh(podfileRoot, "Podfile");
            var podfileLockPath = CrossPath.CombineSsh(podfileRoot, "Podfile.lock");

            // see if we can avoid updating the master repo
            noRepoUpdate = noRepoUpdate == true || (noRepoUpdate == null && Ssh.FileExists(podfileLockPath));

            // create and restore a Podfile
            return(CreatePodfile(podfile, podfilePath) && RestorePodfile(podfileRoot, noRepoUpdate));
        }
        public bool RestoreDependencies(string buildGradleRoot, IEnumerable <GradleDependency> dependencies, ICollection <GradleLibrary> libraries)
        {
            var buildGradlePath = Path.Combine(CrossPath.ToCurrent(buildGradleRoot), "build.gradle");

            if (!CreateBuildGradle(buildGradlePath, dependencies))
            {
                return(false);
            }

            var libs = GetLibraries(buildGradlePath);

            if (libs == null)
            {
                Log.LogError("Unable to restore gradle packages.");
                return(false);
            }

            if (!ProcessLibraries(dependencies, libs, libraries))
            {
                return(false);
            }

            return(true);
        }
예제 #5
0
        private XCodeBuildOutputs BuildPodfileXCodeProject(string podfileRoot, string[] targets, XCodeArchitectures architectures, bool framework)
        {
            var parameters = new XCodeBuildParameters
            {
                ArchitectureSettings = XCodeBuildArchitecture,
                ArtifactsDirectory   = CrossPath.CombineSsh(podfileRoot, "build"),
                OutputDirectory      = CrossPath.CombineSsh(podfileRoot, "out"),
                IsFrameworks         = framework,
                ProjectFilePath      = CrossPath.CombineSsh(podfileRoot, "Pods/Pods.xcodeproj"),
                BuildTargets         = new[] { "Pods-MSBuildTask" },
                OutputTargets        = targets,
                ArchitectureOverride = architectures
            };
            var outputs = new XCodeBuildOutputs();

            if (XCodeBuild.BuildXCodeProject(parameters, outputs))
            {
                return(outputs);
            }
            else
            {
                return(null);
            }
        }
예제 #6
0
        public bool BuildXCodeProject(XCodeBuildParameters parameters, XCodeBuildOutputs outputs)
        {
            outputs.ProjectDirectory   = CrossPath.GetDirectoryNameSsh(parameters.ProjectFilePath);
            outputs.OutputDirectory    = parameters.OutputDirectory ?? CrossPath.CombineSsh(outputs.ProjectDirectory, "out");
            outputs.ArtifactsDirectory = parameters.ArtifactsDirectory ?? CrossPath.CombineSsh(outputs.ProjectDirectory, "build");

            foreach (var arch in parameters.SplitArchitectures)
            {
                if (CancellationToken.IsCancellationRequested)
                {
                    Log.LogError("Task was canceled.");
                    return(false);
                }

                var artifactsPath = CrossPath.CombineSsh(outputs.ArtifactsDirectory, parameters.ArchitectureSettings.GetArtifactDirectoryName("Release", arch: arch));

                // build the project
                var result = Ssh.ExecuteLaunchCtlCommand(
                    workingDirectory: outputs.ProjectDirectory,
                    arguments: new[]
                {
                    XCodeBuildToolPath,
                    "-project", parameters.ProjectFilePath,
                    "-target", parameters.BuildTargets[0],     // TODO
                    "-configuration", "Release",
                    "-arch", arch.ToString().ToLowerInvariant(),
                    "-sdk", parameters.ArchitectureSettings.GetSdk(arch).ToString().ToLowerInvariant(),
                    "build"
                });
                if (!result)
                {
                    Log.LogError($"Error building the XCode project.");
                    return(false);
                }

                if (CancellationToken.IsCancellationRequested)
                {
                    Log.LogError("Task was canceled.");
                    return(false);
                }

                // copy the artifacts to the intermediates directory, naming them per architecture
                foreach (var target in parameters.OutputTargets)
                {
                    // this might be set multiple times as this is target-based,
                    // but we are building the same target multiple times for each arch
                    outputs[target].IntermediateDirectory = CrossPath.CombineSsh(outputs.OutputDirectory, target, "obj");
                    Ssh.CreateDirectory(outputs[target].IntermediateDirectory);

                    var currentIntermediate = outputs[target].Intermediates[arch];
                    currentIntermediate.IsFrameworks = parameters.IsFrameworks;

                    if (parameters.IsFrameworks)
                    {
                        var cleanTarget = CleanFrameworkName(target);
                        currentIntermediate.Path = CrossPath.CombineSsh(outputs[target].IntermediateDirectory, $"{cleanTarget}-{arch}.framework");
                        Ssh.CopyPath(CrossPath.CombineSsh(artifactsPath, $"{cleanTarget}.framework"), currentIntermediate.Path);
                    }
                    else
                    {
                        currentIntermediate.Path = CrossPath.CombineSsh(outputs.OutputDirectory, target, "obj", $"lib{target}-{arch}.a");
                        Ssh.CopyPath(CrossPath.CombineSsh(artifactsPath, $"lib{target}.a"), currentIntermediate.Path);
                    }
                }
            }

            // run lipo on the outputs, from the obj to the out
            foreach (var targetOutput in outputs)
            {
                targetOutput.Directory = CrossPath.CombineSsh(parameters.OutputDirectory, targetOutput.Target);

                // lipo the .a
                var staticIntermediates = targetOutput.Intermediates.Where(i => !i.IsFrameworks);
                if (staticIntermediates.Any())
                {
                    targetOutput.ArchiveOutput = new BuildArchitectureOutput(targetOutput)
                    {
                        Architecture = Utilities.CreateEnum(staticIntermediates.Select(i => i.Architecture)),
                        IsFrameworks = false,
                        Path         = CrossPath.CombineSsh(parameters.OutputDirectory, targetOutput.Target, $"lib{targetOutput.Target}.a")
                    };
                    if (!RunLipo(targetOutput.ArchiveOutput.Path, staticIntermediates.Select(i => i.Path)))
                    {
                        return(false);
                    }
                }

                // lipo the .framework
                var frameworkIntermediates = targetOutput.Intermediates.Where(i => i.IsFrameworks);
                if (frameworkIntermediates.Any())
                {
                    var cleanTarget = CleanFrameworkName(targetOutput.Target);

                    targetOutput.FrameworkOutput = new BuildArchitectureOutput(targetOutput)
                    {
                        Architecture = Utilities.CreateEnum(frameworkIntermediates.Select(i => i.Architecture)),
                        IsFrameworks = true,
                        Path         = CrossPath.CombineSsh(parameters.OutputDirectory, targetOutput.Target, $"{cleanTarget}.framework")
                    };

                    // copy the first arch as we need the other files
                    var firstArch = frameworkIntermediates.First();
                    Ssh.CopyPath(firstArch.Path, targetOutput.FrameworkOutput.Path);

                    // now lipo the archive
                    if (!RunLipo(CrossPath.CombineSsh(targetOutput.FrameworkOutput.Path, cleanTarget), frameworkIntermediates.Select(i => CrossPath.CombineSsh(i.Path, cleanTarget))))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
 public void CreateFile(Stream stream, string remotePath)
 {
     Commands.Runner.Upload(stream, CrossPath.ToSsh(remotePath));
 }
        public string LocateToolPath(string toolPath, string tool, string versionOption)
        {
            string foundPath = null;

            if (!string.IsNullOrEmpty(toolPath))
            {
                // if it was explicitly set, bail if it wasn't found
                toolPath = CrossPath.ToSsh(toolPath);
                if (Commands.FileExists(toolPath))
                {
                    foundPath = toolPath;
                }
            }
            else
            {
                // not set, so search
                var findTool = GetCommandResult($"which {tool}");
                if (!string.IsNullOrEmpty(findTool))
                {
                    foundPath = findTool.Trim();
                }
                else
                {
                    // we didn't find {tool} in the default places, so do a bit of research
                    var dirs    = string.Join(" ", ToolSearchPaths);
                    var command =
                        $@"for file in {dirs}; do " +
                        $@"  if [ -e ""$file/{tool}"" ]; then" +
                        $@"    echo ""$file/{tool}""; " +
                        $@"    exit 0; " +
                        $@"  fi; " +
                        $@"done; " +
                        $@"exit 1; ";
                    findTool = GetCommandResult(command);
                    if (!string.IsNullOrEmpty(findTool))
                    {
                        foundPath = findTool.Trim();
                    }
                }
            }

            if (string.IsNullOrEmpty(foundPath))
            {
                Log.LogError($"Unable to find {tool}.");
            }
            else
            {
                foundPath = CrossPath.ToSsh(foundPath);
                if (string.IsNullOrEmpty(versionOption))
                {
                    Log.LogVerbose($"Found {tool} at {foundPath}.");
                }
                else
                {
                    var version = GetCommandResult($"{foundPath} {versionOption}");
                    Log.LogVerbose($"Found {tool} version {version} at {foundPath}.");
                }
            }

            return(foundPath);
        }
 public bool FileExists(string filePath)
 {
     return(Commands.FileExists(CrossPath.ToSsh(filePath)));
 }
 public void CreateDirectory(string directoryPath)
 {
     Commands.CreateDirectory(CrossPath.ToSsh(directoryPath));
 }
 public void CopyPath(string source, string destination)
 {
     ExecuteCommand($@"cp -rf ""{CrossPath.ToSsh(source)}"" ""{CrossPath.ToSsh(destination)}""");
 }