Example #1
0
#pragma warning disable CS1998
        static async Task DoDownload(FileStream fs, Stream webStream, DownloadStatus status)
        {
            var buf = new byte [16384];
            int nread;

            Log.DebugLine("Downloading...");
            while ((nread = webStream.Read(buf, 0, buf.Length)) > 0)
            {
                status.Update((ulong)nread);
                fs.Write(buf, 0, nread);
            }

            fs.Flush();
        }
        protected override async Task <bool> Execute(Context context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            Uri    nugetUrl       = Configurables.Urls.NugetUri;
            string localNugetPath = Configurables.Paths.LocalNugetPath;

            if (Utilities.FileExists(localNugetPath))
            {
                Log.StatusLine($"NuGet already downloaded ({localNugetPath})");
                return(true);
            }

            Utilities.CreateDirectory(Path.GetDirectoryName(localNugetPath));
            Log.StatusLine("Downloading NuGet");

            (bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus(nugetUrl);

            if (!success)
            {
                if (status == HttpStatusCode.NotFound)
                {
                    Log.ErrorLine("NuGet URL not found");
                }
                else
                {
                    Log.ErrorLine("Failed to obtain NuGet size. HTTP status code: {status} ({(int)status})");
                }
                return(false);
            }

            DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);

            Log.StatusLine($"  {context.Characters.Link} {nugetUrl}", ConsoleColor.White);
            await Download(context, nugetUrl, localNugetPath, "NuGet", Path.GetFileName(localNugetPath), downloadStatus);

            if (!File.Exists(localNugetPath))
            {
                Log.ErrorLine($"Download of NuGet from {nugetUrl} failed");
                return(false);
            }

            return(true);
        }
Example #3
0
        static async Task DoDownload(Uri url, string targetFile, DownloadStatus status)
        {
            using (var httpClient = new HttpClient()) {
                httpClient.Timeout = WebRequestTimeout;
                Log.DebugLine("Calling GetAsync");
                HttpResponseMessage resp = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);

                Log.DebugLine("GetAsync finished");

                resp.EnsureSuccessStatusCode();
                string dir = Path.GetDirectoryName(targetFile);
                CreateDirectory(dir);
                using (var fs = File.Open(targetFile, FileMode.Create, FileAccess.Write)) {
                    using (var webStream = await resp.Content.ReadAsStreamAsync()) {
                        status.Start();
                        WriteWithProgress(fs, webStream, status);
                    }
                }
            }
        }
Example #4
0
        public static async Task <bool> Download(Uri url, string targetFile, DownloadStatus status)
        {
            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }
            if (String.IsNullOrEmpty(targetFile))
            {
                throw new ArgumentException("must not be null or empty", nameof(targetFile));
            }
            if (status == null)
            {
                throw new ArgumentNullException(nameof(status));
            }

            using (var httpClient = new HttpClient()) {
                httpClient.Timeout = WebRequestTimeout;
                HttpResponseMessage resp;
                try {
                    Log.DebugLine("Calling GetAsync");
                    resp = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);

                    Log.DebugLine("GetAsync finished");
                } catch (Exception ex) {
                    Log.DebugLine($"Exception: {ex}");
                    throw;
                }

                resp.EnsureSuccessStatusCode();
                string dir = Path.GetDirectoryName(targetFile);
                CreateDirectory(dir);
                using (var fs = File.Open(targetFile, FileMode.Create, FileAccess.Write)) {
                    using (var webStream = await resp.Content.ReadAsStreamAsync()) {
                        status.Start();
                        await DoDownload(fs, webStream, status);
                    }
                }
            }

            return(true);
        }
        async Task <bool> DownloadCorretto(Context context, string localPackagePath, Uri url)
        {
            if (File.Exists(localPackagePath))
            {
                if (await Utilities.VerifyArchive(localPackagePath))
                {
                    Log.StatusLine("Corretto archive already downloaded and valid");
                    return(true);
                }
                Utilities.DeleteFileSilent(localPackagePath);
            }

            Log.StatusLine("Downloading Corretto from ", url.ToString(), tailColor: ConsoleColor.White);
            (bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus(url);

            if (!success)
            {
                if (status == HttpStatusCode.NotFound)
                {
                    Log.ErrorLine("Corretto archive URL not found");
                }
                else
                {
                    Log.ErrorLine($"Failed to obtain Corretto size. HTTP status code: {status} ({(int)status})");
                }
                return(false);
            }

            DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);

            Log.StatusLine($"  {context.Characters.Link} {url}", ConsoleColor.White);
            await Download(context, url, localPackagePath, "Corretto", Path.GetFileName(localPackagePath), downloadStatus);

            if (!File.Exists(localPackagePath))
            {
                Log.ErrorLine($"Download of Corretto from {url} failed.");
                return(false);
            }

            return(true);
        }
Example #6
0
        public static async Task <bool> Download(Uri url, string targetFile, DownloadStatus status)
        {
            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }
            if (String.IsNullOrEmpty(targetFile))
            {
                throw new ArgumentException("must not be null or empty", nameof(targetFile));
            }
            if (status == null)
            {
                throw new ArgumentNullException(nameof(status));
            }

            bool      succeeded = false;
            const int retries   = 5;

            for (int i = 0; i < retries; i++)
            {
                try {
                    await DoDownload(url, targetFile, status);

                    succeeded = true;
                    break;
                } catch (Exception ex) {
                    Log.DebugLine($"Exception: {ex}");
                    if (i < retries - 1)
                    {
                        Log.StatusLine($"'{ex.Message}'. Retrying...", ConsoleColor.Yellow);
                        await Task.Delay(1000);
                    }
                }
            }

            return(succeeded);
        }
Example #7
0
        protected override async Task <bool> Execute(Context context)
        {
            if (context.ForceRuntimesBuild)
            {
                if (osSupportsMonoBuild)
                {
                    Log.InfoLine("Rebuilding Mono runtimes as requested");
                    return(false);
                }

                Log.InfoLine($"Forced Mono runtimes rebuild requested but rebuilding on {context.OS.Type} is currently not supported.");
            }

            string localPackagePath = Configurables.Paths.BundleArchivePath;

            Log.DebugLine($"Local bundle path: {localPackagePath}");

            if (await Utilities.VerifyArchive(localPackagePath))
            {
                Log.StatusLine("Xamarin.Android Bundle archive already downloaded and valid");
            }
            else
            {
                if (!String.IsNullOrEmpty(context.XABundlePath))
                {
                    // User indicated they wanted to use a specific bundle that's supposed to be on disk. It's not (or
                    // it's invalid) and that means we have no way of getting it - we can't download the default one
                    // since that was not the intention behind overriding the location. Thus, we error out.
                    Log.DebugLine($"Bundle directory from command line: {context.XABundlePath}");
                    throw new InvalidOperationException($"Xamarin.Android bundle indicated on the command line does not exist ({context.XABundlePath})");
                }

                var bundleUrl = new Uri(BundleUriPrefix, BundleFileName);

                Log.StatusLine("Bundle URL: ", $"{bundleUrl}", tailColor: ConsoleColor.Cyan);

                HttpStatusCode status;
                bool           success;
                ulong          size;

                (success, size, status) = await Utilities.GetDownloadSizeWithStatus(bundleUrl);

                if (!success)
                {
                    if (status == HttpStatusCode.NotFound)
                    {
                        if (osSupportsMonoBuild)
                        {
                            Log.StatusLine("   not found, will need to rebuild");
                        }
                        else
                        {
                            Log.ErrorLine($"   not found, rebuilding on {context.OS.Type} is not currently supported");
                        }
                        return(false);
                    }

                    if (String.IsNullOrEmpty(bundle404Message))
                    {
                        throw new InvalidOperationException($"Failed to access bundle at {bundleUrl} (HTTP status: {status})");
                    }
                    else
                    {
                        throw new InvalidOperationException(bundle404Message);
                    }
                }

                DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);
                Log.StatusLine($"  {context.Characters.Link} {bundleUrl}", ConsoleColor.White);
                await Download(context, bundleUrl, localPackagePath, "Xamarin.Android Bundle", Path.GetFileName(localPackagePath), downloadStatus);

                if (!File.Exists(localPackagePath))
                {
                    Log.ErrorLine($"Download of Xamarin.Android Bundle from {bundleUrl} failed.");
                    return(false);
                }
            }

            Log.StatusLine($"Unpacking bundle to {Utilities.GetRelativePath (BuildPaths.XamarinAndroidSourceRoot, Configurables.Paths.BundleInstallDir)}");
            string tempDir = $"{Configurables.Paths.BundleInstallDir}-bundle.temp";

            try {
                if (!await Utilities.Unpack(localPackagePath, tempDir, cleanDestinatioBeforeUnpacking: true))
                {
                    Log.WarningLine("Failed to unpack bundle, will need to rebuild");
                    return(false);
                }

                Log.DebugLine($"Moving unpacked bundle from {tempDir} to {Configurables.Paths.BundleInstallDir}");
                Utilities.MoveDirectoryContentsRecursively(tempDir, Configurables.Paths.BundleInstallDir, resetFileTimestamp: true, ignoreDeletionErrors: true);
            } finally {
                Utilities.DeleteDirectorySilent(tempDir);
            }

            string managedRuntime     = context.Properties.GetRequiredValue(KnownProperties.ManagedRuntime);
            bool   haveManagedRuntime = !String.IsNullOrEmpty(managedRuntime);

            if (!await Utilities.BuildRemapRef(context, haveManagedRuntime, managedRuntime))
            {
                return(false);
            }

            Utilities.PropagateXamarinAndroidCecil(context);

            if (String.IsNullOrEmpty(context.XABundleCopyDir))
            {
                return(HaveEverything());
            }

            string destPackagePath = Path.Combine(context.XABundleCopyDir, Path.GetFileName(localPackagePath));

            Log.DebugLine($"Copy of the XA bundle was requested to be created at {destPackagePath}");
            if (Utilities.FileExists(destPackagePath))
            {
                Log.DebugLine("Bundle copy already exists");
                return(HaveEverything());
            }

            // Utilities.FileExists above will return `false` for a dangling symlink at `destPackagePath`, doesn't hurt
            // to remove it here just in case
            Utilities.DeleteFileSilent(destPackagePath);
            Utilities.CopyFile(localPackagePath, destPackagePath);

            return(HaveEverything());

            bool HaveEverything()
            {
                bool ret = MonoRuntimesHelpers.AllBundleItemsPresent(new Runtimes());

                if (!ret)
                {
                    Log.Instance.StatusLine($"Some bundle files are missing, download/rebuild/reinstall forced");
                }
                return(ret);
            }
        }
        protected override async Task <bool> Execute(Context context)
        {
            string localPackagePath = Configurables.Paths.AntArchivePath;

            if (await Utilities.VerifyArchive(localPackagePath))
            {
                Log.StatusLine("Ant archive already downloaded and valid");
            }
            else
            {
                Uri antUrl = new Uri(Configurables.Urls.AntBaseUri, Configurables.Paths.AntArchiveName);

                Log.StatusLine("Ant URL: ", $"{antUrl}", tailColor: ConsoleColor.Cyan);

                HttpStatusCode status;
                bool           success;
                ulong          size;

                (success, size, status) = await Utilities.GetDownloadSizeWithStatus(antUrl);

                if (!success)
                {
                    Log.ErrorLine($"Failed to access Ant at {antUrl} (HTTP status: {status})");
                    return(false);
                }

                DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);
                Log.StatusLine($"  {context.Characters.Link} {antUrl}", ConsoleColor.White);
                await Download(context, antUrl, localPackagePath, "Apache Ant", Path.GetFileName(localPackagePath), downloadStatus);

                if (!File.Exists(localPackagePath))
                {
                    Log.ErrorLine($"Download of Xamarin.Android Bundle from {antUrl} failed.");
                    return(false);
                }
            }

            Log.StatusLine($"Unpacking Ant to {Configurables.Paths.AntInstallDir}");
            string tempDir = $"{Configurables.Paths.AntInstallDir}-ant.temp";

            try {
                if (!await Utilities.Unpack(localPackagePath, tempDir, cleanDestinatioBeforeUnpacking: true))
                {
                    Log.ErrorLine("Failed to unpack Ant");
                    return(false);
                }

                Log.DebugLine($"Moving unpacked Ant from {tempDir} to {Configurables.Paths.AntInstallDir}");

                // There should be just a single subdirectory
                List <string> subdirs = Directory.EnumerateDirectories(tempDir).ToList();
                if (subdirs.Count > 1)
                {
                    throw new InvalidOperationException($"Unexpected contents layout of the Ant archive - expected a single subdirectory, instead found {subdirs.Count}");
                }

                Utilities.MoveDirectoryContentsRecursively(subdirs [0], Configurables.Paths.AntInstallDir);
            } finally {
                Utilities.DeleteDirectorySilent(tempDir);
            }

            return(true);
        }
        protected override async Task <bool> Execute(Context context)
        {
            string sdkRoot         = context.Properties.GetRequiredValue(KnownProperties.AndroidSdkDirectory);
            string ndkRoot         = context.Properties.GetRequiredValue(KnownProperties.AndroidNdkDirectory);
            string packageCacheDir = context.Properties.GetRequiredValue(KnownProperties.AndroidToolchainCacheDirectory);

            RefreshSdk = context.ComponentsToRefresh.HasFlag(RefreshableComponent.AndroidSDK);
            RefreshNdk = context.ComponentsToRefresh.HasFlag(RefreshableComponent.AndroidNDK);

            Log.StatusLine("Android SDK location: ", sdkRoot, tailColor: Log.DestinationColor);
            Log.StatusLine("Android NDK location: ", ndkRoot, tailColor: Log.DestinationColor);
            Log.DebugLine($"Toolchain cache directory: {packageCacheDir}");

            var toolchain = new AndroidToolchain();
            var toInstall = new List <AndroidPackage> ();

            toolchain.Components.ForEach(c => Check(context, packageCacheDir, sdkRoot, c, toInstall, 4));
            if (toInstall.Count == 0)
            {
                return(GatherNDKInfo(context, ndkRoot));
            }

            Log.MessageLine();
            toInstall.ForEach(p => Log.DebugLine($"Missing Android component: {p.Component.Name}"));

            string tempDir = Path.Combine(context.Properties.GetRequiredValue(KnownProperties.AndroidToolchainDirectory), "temp");

            Log.DebugLine($"Toolchain temporary directory: {tempDir}");

            if (Directory.Exists(tempDir))
            {
                Log.DebugLine("Temporary directory exists, cleaning it up");
                Utilities.DeleteDirectorySilent(tempDir);
            }
            Directory.CreateDirectory(tempDir);

            Log.MessageLine("Installing missing components");
            var toDownload = new List <AndroidPackage> ();

            toInstall.ForEach(c => CheckPackageStatus(context, packageCacheDir, c, toDownload));

            if (toDownload.Count > 0)
            {
                ulong totalDownloadSize = 0;
                foreach (AndroidPackage pkg in toDownload)
                {
                    Log.DebugLine($"Android component '{pkg.Component.Name}' will be downloaded from {pkg.Url}");
                    (bool success, ulong size) = await Utilities.GetDownloadSize(pkg.Url);

                    if (!success)
                    {
                        continue;
                    }
                    totalDownloadSize += size;
                }

                toDownload.ForEach(p => Log.StatusLine($"  {context.Characters.Link} {p.Url}", ConsoleColor.White));

                DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, totalDownloadSize, context.InteractiveSession);
                await Task.WhenAll(toDownload.Select(p => Download(context, p.Url, p.LocalPackagePath, p.Component.Name, p.PackageName, downloadStatus)));
            }

            foreach (AndroidPackage p in toInstall)
            {
                await Unpack(context, tempDir, p);
            }

            if (!AcceptLicenses(context, sdkRoot))
            {
                Log.ErrorLine("Failed to accept Android SDK licenses");
                return(false);
            }

            return(GatherNDKInfo(context, ndkRoot));
        }
Example #10
0
        protected override async Task <bool> Execute(Context context)
        {
            if (context.ForceRuntimesBuild)
            {
                if (osSupportsMonoBuild)
                {
                    Log.InfoLine("Rebuilding Mono runtimes as requested");
                    return(false);
                }

                Log.InfoLine($"Forced Mono runtimes rebuild requested but rebuilding on {context.OS.Type} is currently not supported.");
            }

            string localPackagePath = Path.Combine(Configurables.Paths.BundleArchivePath);

            if (await Utilities.VerifyArchive(localPackagePath))
            {
                Log.StatusLine("Xamarin.Android Bundle archive already downloaded and valid");
            }
            else
            {
                if (!String.IsNullOrEmpty(context.XABundlePath))
                {
                    // User indicated they wanted to use a specific bundle that's supposed to be on disk. It's not (or
                    // it's invalid) and that means we have no way of getting it - we can't download the default one
                    // since that was not the intention behind overriding the location. Thus, we error out.
                    throw new InvalidOperationException($"Xamarin.Android bundle indicated on the command line does not exist ({context.XABundlePath})");
                }

                var bundleUrl = new Uri(BundleUriPrefix, BundleFileName);

                Log.StatusLine("Bundle URL: ", $"{bundleUrl}", tailColor: ConsoleColor.Cyan);

                HttpStatusCode status;
                bool           success;
                ulong          size;

                (success, size, status) = await Utilities.GetDownloadSizeWithStatus(bundleUrl);

                if (!success)
                {
                    if (status == HttpStatusCode.NotFound)
                    {
                        if (osSupportsMonoBuild)
                        {
                            Log.StatusLine("   not found, will need to rebuild");
                        }
                        else
                        {
                            Log.ErrorLine($"   not found, rebuilding on {context.OS.Type} is not currently supported");
                        }
                        return(false);
                    }

                    if (String.IsNullOrEmpty(bundle404Message))
                    {
                        throw new InvalidOperationException($"Failed to access bundle at {bundleUrl} (HTTP status: {status})");
                    }
                    else
                    {
                        throw new InvalidOperationException(bundle404Message);
                    }
                }

                DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);
                Log.StatusLine($"  {context.Characters.Link} {bundleUrl}", ConsoleColor.White);
                await Download(context, bundleUrl, localPackagePath, "Xamarin.Android Bundle", Path.GetFileName(localPackagePath), downloadStatus);

                if (!File.Exists(localPackagePath))
                {
                    Log.ErrorLine($"Download of Xamarin.Android Bundle from {bundleUrl} failed.");
                    return(false);
                }
            }

            Log.StatusLine($"Unpacking bundle to {Utilities.GetRelativePath (BuildPaths.XamarinAndroidSourceRoot, Configurables.Paths.BundleInstallDir)}");
            string tempDir = $"{Configurables.Paths.BundleInstallDir}-bundle.temp";

            try {
                if (!await Utilities.Unpack(localPackagePath, tempDir, cleanDestinatioBeforeUnpacking: true))
                {
                    Log.WarningLine("Failed to unpack bundle, will need to rebuild");
                    return(false);
                }

                Log.DebugLine("Moving unpacked bundle from {tempDir} to {Configurables.Paths.Bundle_InstallDir}");
                Utilities.MoveDirectoryContentsRecursively(tempDir, Configurables.Paths.BundleInstallDir, resetFileTimestamp: true);
            } finally {
                Utilities.DeleteDirectorySilent(tempDir);
            }

            return(true);
        }
Example #11
0
        async Task <bool> InstallDotNetAsync(Context context, string dotnetPath, string version, bool runtimeOnly = false)
        {
            if (Directory.Exists(Path.Combine(dotnetPath, "sdk", version)) && !runtimeOnly)
            {
                Log.Status($"dotnet SDK version ");
                Log.Status(version, ConsoleColor.Yellow);
                Log.StatusLine(" already installed in: ", Path.Combine(dotnetPath, "sdk", version), tailColor: ConsoleColor.Cyan);
                return(true);
            }

            if (Directory.Exists(Path.Combine(dotnetPath, "shared", "Microsoft.NETCore.App", version)) && runtimeOnly)
            {
                Log.Status($"dotnet runtime version ");
                Log.Status(version, ConsoleColor.Yellow);
                Log.StatusLine(" already installed in: ", Path.Combine(dotnetPath, "shared", "Microsoft.NETCore.App", version), tailColor: ConsoleColor.Cyan);
                return(true);
            }

            Uri    dotnetScriptUrl  = Configurables.Urls.DotNetInstallScript;
            string dotnetScriptPath = Path.Combine(dotnetPath, Path.GetFileName(dotnetScriptUrl.LocalPath));

            if (File.Exists(dotnetScriptPath))
            {
                Utilities.DeleteFile(dotnetScriptPath);
            }

            Log.StatusLine("Downloading dotnet-install...");

            (bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus(dotnetScriptUrl);

            if (!success)
            {
                if (status == HttpStatusCode.NotFound)
                {
                    Log.ErrorLine("dotnet-install URL not found");
                }
                else
                {
                    Log.ErrorLine("Failed to obtain dotnet-install size. HTTP status code: {status} ({(int)status})");
                }
                return(false);
            }

            DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);

            Log.StatusLine($"  {context.Characters.Link} {dotnetScriptUrl}", ConsoleColor.White);
            await Download(context, dotnetScriptUrl, dotnetScriptPath, "dotnet-install", Path.GetFileName(dotnetScriptUrl.LocalPath), downloadStatus);

            if (!File.Exists(dotnetScriptPath))
            {
                Log.ErrorLine($"Download of dotnet-install from {dotnetScriptUrl} failed");
                return(false);
            }

            Log.StatusLine($"Installing dotnet SDK/runtime '{version}'...");

            if (Context.IsWindows)
            {
                var args = new List <string> {
                    "-NoProfile", "-ExecutionPolicy", "unrestricted", "-file", dotnetScriptPath,
                    "-Version", version, "-InstallDir", dotnetPath, "-Verbose"
                };
                if (runtimeOnly)
                {
                    args.AddRange(new string [] { "-Runtime", "dotnet" });
                }

                return(Utilities.RunCommand("powershell.exe", args.ToArray()));
            }
            else
            {
                var args = new List <string> {
                    dotnetScriptPath, "--version", version, "--install-dir", dotnetPath, "--verbose"
                };
                if (runtimeOnly)
                {
                    args.AddRange(new string [] { "-Runtime", "dotnet" });
                }

                return(Utilities.RunCommand("bash", args.ToArray()));
            }
        }
Example #12
0
        async Task <bool> DownloadAndUpackIfNeeded(Context context, string name, string customUrl, string localPath, string archiveFileName, string destinationDirectory)
        {
            if (File.Exists(localPath))
            {
                Log.StatusLine($"{name} archive already downloaded");
            }
            else
            {
                Utilities.DeleteFileSilent(localPath);

                var url = string.IsNullOrEmpty(customUrl) ?
                          new Uri(Configurables.Urls.MonoArchive_BaseUri, archiveFileName) :
                          new Uri(customUrl);
                Log.StatusLine($"Downloading {name} archive from {url}");

                (bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus(url);

                if (!success)
                {
                    if (status == HttpStatusCode.NotFound)
                    {
                        Log.Info($"{name} archive URL not found");
                    }
                    else
                    {
                        Log.Info($"Failed to obtain {name} archive size. HTTP status code: {status} ({(int)status})");
                    }
                    Log.InfoLine(". Mono runtimes will be rebuilt");
                    return(false);
                }

                DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);
                Log.StatusLine($"  {context.Characters.Link} {url}", ConsoleColor.White);
                await Download(context, url, localPath, $"{name} Archive", archiveFileName, downloadStatus);

                if (!File.Exists(localPath))
                {
                    Log.InfoLine($"Download of {name} archive from {url} failed");
                    return(false);
                }
            }

            string tempDir = $"{destinationDirectory}.tmp";

            if (!await Utilities.Unpack(localPath, tempDir, cleanDestinatioBeforeUnpacking: true))
            {
                Utilities.DeleteFileSilent(localPath);
                Utilities.DeleteDirectorySilent(destinationDirectory);
                Log.WarningLine($"Failed to unpack {name} archive {localPath}");
                Utilities.DeleteFileSilent(localPath);
                return(false);
            }

            Log.DebugLine($"Moving unpacked Mono archive from {tempDir} to {destinationDirectory}");
            try {
                Utilities.MoveDirectoryContentsRecursively(tempDir, destinationDirectory, resetFileTimestamp: true);
            } finally {
                Utilities.DeleteDirectorySilent(tempDir);
                // Clean up zip after extraction if running on a hosted azure pipelines agent.
                if (context.IsRunningOnHostedAzureAgent)
                {
                    Utilities.DeleteFileSilent(localPath);
                }
            }

            return(true);
        }
		protected async Task Download (Context context, Uri url, string destinationFilePath, string descriptiveName, string fileName, DownloadStatus downloadStatus)
		{
			bool fancyLogging = context.InteractiveSession;
			Log.DebugLine ($"{descriptiveName} URL: {url}");
			if (!context.InteractiveSession)
				LogStatus ($"downloading {fileName} ", 4, ConsoleColor.Gray);

			bool success;
			Exception downloadEx = null;
			try {
				Log.DebugLine ("About to start downloading");
				success = await Utilities.Download (url, destinationFilePath, downloadStatus);
			} catch (Exception ex) {
				Log.DebugLine ($"Caught exception: {ex}");
				downloadEx = ex;
				success = false;
			}

			Log.Debug ($"success == {success}");
			if (success)
				return;

			string message = $"Failed to download {url}";

			if (downloadEx != null)
				throw new InvalidOperationException ($"{message}: {downloadEx.Message}", downloadEx);
			throw new InvalidOperationException (message);
		}