public bool IsAlreadyDownloaded(XamarinBuildDownload xbd)
        {
            // Skip extraction if the file is already in place
            var flagFile = xbd.DestinationDir + ".unpacked";

            return(File.Exists(flagFile) || File.Exists(xbd.CacheFile));
        }
Exemple #2
0
        static string GetTarFileName(XamarinBuildDownload xbd)
        {
            var tarPath = Path.Combine(xbd.DestinationDir, Path.ChangeExtension(Path.GetFileName(xbd.CacheFile), "tar"));

            if (File.Exists(tarPath))
            {
                return(tarPath);
            }

            var foundFile = Directory.EnumerateFiles(xbd.DestinationDir, "*.tar", SearchOption.TopDirectoryOnly).FirstOrDefault();

            return(string.IsNullOrEmpty(foundFile) ? tarPath : foundFile);
        }
        async Task <int> ExtractTarOnWindows(XamarinBuildDownload xbd, StringWriter output, CancellationToken token)
        {
            var tarFile    = GetTarFileName(xbd);
            var psi        = CreateExtractionArgs(tarFile, xbd.DestinationDir, xbd.Kind, true);
            var returnCode = await ProcessUtils.StartProcess(psi, output, output, token);

            if (returnCode == 7)
            {
                LogMessage("7Zip command line parse did not work.  Trying without -snl-");
                psi        = CreateExtractionArgs(tarFile, xbd.DestinationDir, xbd.Kind, false);
                returnCode = await ProcessUtils.StartProcess(psi, output, output, token);
            }
            File.Delete(tarFile);
            return(returnCode);
        }
Exemple #4
0
        async Task <bool> ExtractArchive(XamarinBuildDownload xbd, string flagFile, CancellationToken token)
        {
            ProcessStartInfo psi = CreateExtractionArgs(xbd.CacheFile, xbd.DestinationDir, xbd.Kind);

            try {
                LogMessage("Extracting {0} to {1}", xbd.CacheFile, xbd.DestinationDir);
                var output     = new StringWriter();
                int returnCode = await ProcessUtils.StartProcess(psi, output, output, token);

                if (returnCode == 0)
                {
                    //with 7zip, tgz just gets uncompressed to a tar. now extract the tar.
                    if (xbd.Kind == ArchiveKind.Tgz && Platform.IsWindows)
                    {
                        var tarFile = GetTarFileName(xbd);
                        psi        = CreateExtractionArgs(tarFile, xbd.DestinationDir, xbd.Kind);
                        returnCode = await ProcessUtils.StartProcess(psi, output, output, token);

                        File.Delete(tarFile);
                        if (returnCode == 0)
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        return(true);
                    }
                }
                LogCodedError(
                    ThisOrThat(xbd.CustomErrorCode, ErrorCodes.ExtractionFailed),
                    ThisOrThat(xbd.CustomErrorMessage, () => string.Format("Unpacking failed. Please download '{0}' and extract it to the '{1}' directory " +
                                                                           "and create an empty file called '{2}'.", xbd.Url, xbd.DestinationDir, flagFile)));
                LogMessage("Unpacking failure reason: " + output.ToString(), MessageImportance.High);
            } catch (Exception ex) {
                LogErrorFromException(ex);
            }

            //something went wrong, clean up so we try again next time
            try {
                Directory.Delete(xbd.DestinationDir, true);
            } catch (Exception ex) {
                LogCodedError(ErrorCodes.DirectoryDeleteFailed, "Failed to delete directory '{0}'.", xbd.DestinationDir);
                LogErrorFromException(ex);
            }
            return(false);
        }
Exemple #5
0
        async Task <bool> MakeSureLibraryIsInPlace(XamarinBuildDownload xbd, CancellationToken token)
        {
            // Skip extraction if the file is already in place
            var flagFile = xbd.DestinationDir + ".unpacked";

            if (File.Exists(flagFile))
            {
                return(true);
            }

            try {
                Directory.CreateDirectory(xbd.DestinationDir);
            } catch (Exception ex) {
                LogCodedError(ThisOrThat(xbd.CustomErrorCode, ErrorCodes.DirectoryCreateFailed), ThisOrThat(xbd.CustomErrorMessage, () => string.Format("Failed to create directory '{0}'.", xbd.DestinationDir)));
                LogMessage("Directory creation failure reason: " + ex.ToString(), MessageImportance.High);
                return(false);
            }

            var lockFile = xbd.DestinationDir + ".locked";

            using (var lockStream = DownloadUtils.ObtainExclusiveFileLock(lockFile, Token, TimeSpan.FromSeconds(xbd.ExclusiveLockTimeout), this)) {
                if (lockStream == null)
                {
                    LogCodedError(ErrorCodes.ExclusiveLockTimeout, "Timed out waiting for exclusive file lock on: {0}", lockFile);
                    LogMessage("Timed out waiting for an exclusive file lock on: " + lockFile, MessageImportance.High);
                    return(false);
                }

                if (!File.Exists(xbd.CacheFile) || !IsValidDownload(xbd.DestinationDir + ".sha1", xbd.CacheFile, xbd.Sha1))
                {
                    try {
                        int progress = -1;
                        DownloadProgressChangedEventHandler downloadHandler = (o, e) => {
                            if (e.ProgressPercentage % 10 != 0 || progress == e.ProgressPercentage)
                            {
                                return;
                            }
                            progress = e.ProgressPercentage;
                            LogMessage(
                                "\t({0}/{1}b), total {2:F1}%", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage
                                );
                        };
                        using (var client = new WebClient()) {
                            client.DownloadProgressChanged += downloadHandler;
                            LogMessage("  Downloading {0} to {1}", xbd.Url, xbd.CacheFile);
                            client.DownloadFileTaskAsync(xbd.Url, xbd.CacheFile).Wait(token);
                            LogMessage("  Downloading Complete");
                            client.DownloadProgressChanged -= downloadHandler;
                        }
                    } catch (Exception e) {
                        LogCodedError(ThisOrThat(xbd.CustomErrorCode, ErrorCodes.DownloadFailed), ThisOrThat(xbd.CustomErrorMessage, () => string.Format("Download failed. Please download {0} to a file called {1}.", xbd.Url, xbd.CacheFile)));
                        LogMessage("Download failure reason: " + e.GetBaseException().Message, MessageImportance.High);
                        File.Delete(xbd.CacheFile);
                        return(false);
                    }
                }

                if (!File.Exists(xbd.CacheFile))
                {
                    LogCodedError(ThisOrThat(xbd.CustomErrorCode, ErrorCodes.DownloadedFileMissing), ThisOrThat(xbd.CustomErrorMessage, () => string.Format("Downloaded file '{0}' is missing.", xbd.CacheFile)));
                    return(false);
                }

                if (xbd.Kind == ArchiveKind.Uncompressed)
                {
                    var uncompressedCacheFile = xbd.CacheFile;
                    if (!string.IsNullOrEmpty(xbd.ToFile))
                    {
                        uncompressedCacheFile = xbd.ToFile;
                    }

                    File.Move(xbd.CacheFile, Path.Combine(xbd.DestinationDir, Path.GetFileName(uncompressedCacheFile)));
                    File.WriteAllText(flagFile, "This marks that the extraction completed successfully");
                    return(true);
                }
                else
                {
                    if (await ExtractArchive(xbd, flagFile, token))
                    {
                        File.WriteAllText(flagFile, "This marks that the extraction completed successfully");
                        return(true);
                    }
                }
            }

            // We will attempt to delete the lock file when we're done
            try {
                if (File.Exists(lockFile))
                {
                    File.Delete(lockFile);
                }
            } catch { }

            return(false);
        }
        public IEnumerable <XamarinBuildDownload> ParseDownloadItems(ITaskItem[] items, bool allowUnsecureUrls)
        {
            if (items == null || items.Length <= 0)
            {
                return(new List <XamarinBuildDownload> ());
            }

            var results = new List <XamarinBuildDownload> ();

            foreach (var item in items)
            {
                var xbd = new XamarinBuildDownload();

                xbd.Id = item.ItemSpec;
                if (!ValidateId(xbd.Id))
                {
                    Log.LogCodedError(ErrorCodes.XbdInvalidItemId, "Invalid item ID {0}", xbd.Id);
                    continue;
                }
                xbd.Url = item.GetMetadata("Url");
                if (string.IsNullOrEmpty(xbd.Url))
                {
                    Log.LogCodedError(ErrorCodes.XbdInvalidUrl, "Missing required Url metadata on item {0}", item.ItemSpec);
                    continue;
                }
                xbd.Sha256 = item.GetMetadata("Sha256");
                xbd.Kind   = GetKind(xbd.Url, item.GetMetadata("Kind"));
                if (xbd.Kind == ArchiveKind.Unknown)
                {
                    //TODO we may be able to determine the kind from the server response
                    continue;
                }
                if (!EnsureSecureUrl(item, xbd.Url, allowUnsecureUrls))
                {
                    continue;
                }

                xbd.CustomErrorCode    = item.GetMetadata("CustomErrorCode");
                xbd.CustomErrorMessage = item.GetMetadata("CustomErrorMessage");

                // By default, use the kind (tgz or zip) as the file extension for the cache file
                var cacheFileExt = xbd.Kind.ToString().ToLower();

                // If we have an uncompressed file specified (move file instead of decompressing it)
                if (xbd.Kind == ArchiveKind.Uncompressed)
                {
                    // Get the filename
                    xbd.ToFile = item.GetMetadata("ToFile");
                    // If we have a tofile set, try and grab its extension
                    if (!string.IsNullOrEmpty(xbd.ToFile))
                    {
                        cacheFileExt = Path.GetExtension(xbd.ToFile)?.ToLower() ?? string.Empty;
                    }
                }

                xbd.CacheFile      = Path.Combine(CacheDir, item.ItemSpec.TrimEnd('.') + "." + cacheFileExt.TrimStart('.'));
                xbd.DestinationDir = Path.GetFullPath(Path.Combine(CacheDir, item.ItemSpec));

                int lockTimeout = 60;
                if (int.TryParse(item.GetMetadata("ExclusiveLockTimeout"), out lockTimeout))
                {
                    xbd.ExclusiveLockTimeout = lockTimeout;
                }

                results.Add(xbd);
            }

            // Deduplicate possible results by their Id which should be unique always for the given archive
            return(results.GroupBy(item => item.Id).Select((kvp) => kvp.FirstOrDefault()).ToArray());
        }