private async Task DoDownloadAsync()

in JetBrains.Profiler.SelfApi/src/Impl/PrerequisiteBase.cs [65:203]


    private async Task DoDownloadAsync(
      Uri nugetUrl,
      NuGetApi nugetApi,
      string downloadTo,
      IProgress<double> progress,
      CancellationToken cancellationToken)
    {
      const double downloadWeight = 0.8;
      const double unzipWeight = 1.0 - downloadWeight;

      try
      {
        if (string.IsNullOrEmpty(downloadTo))
          downloadTo = GetDefaultDownloadPath();

        Trace.Info("Prerequisite.Download: targetPath = `{0}`", downloadTo);
        Directory.CreateDirectory(downloadTo);

        // Note(ww898): We force the OS architecture everywhere!!! Process architecture is inherited by default in macOS ARM64. We turn off this behavior for x64 processes with /usr/bin/arch!!!
        var runtimeIdString = HabitatInfo.OSRuntimeIdString;

        var nupkgName = GetPackageName() + "." + runtimeIdString;

        string nupkgFolder, nupkgPath, readyMarker;

        var downloadProgress = new SubProgress(progress, 0, downloadWeight);
        var unzipProgress = new SubProgress(progress, downloadWeight * 100.0, unzipWeight);

        using (var http = new HttpClient())
        {
          Trace.Verbose("Prerequisite.Download: Requesting...");
          var content = await http
            .GetNupkgContentAsync(nugetUrl, nugetApi, nupkgName, SemanticVersion, cancellationToken)
            .ConfigureAwait(false);

          var latestVersion = content.Headers.GetValues("Version").Single();
          nupkgFolder = Path.Combine(downloadTo, Name, latestVersion, runtimeIdString);
          readyMarker = Path.Combine(nupkgFolder, ".ready");

          if (File.Exists(readyMarker) && TryGetDownloadedRunner(downloadTo, runtimeIdString, out _runnerPath))
          {
            Trace.Verbose("Prerequisite.Download: Package version `{0}` already downloaded.", latestVersion);
            return;
          }

          Directory.CreateDirectory(nupkgFolder);
          nupkgPath = Path.Combine(nupkgFolder, $"{nupkgName}.{latestVersion}.nupkg");

          Trace.Verbose("Prerequisite.Download: Saving...");
          using (var input = await content.ReadAsStreamAsync().ConfigureAwait(false))
          using (var output = File.Create(nupkgPath))
          {
            CopyStream(
              input,
              output,
              content.Headers.ContentLength ?? GetEstimatedSize(),
              downloadProgress,
              cancellationToken
              );
          }
        }

        const string toolsPrefix = "tools/";

        Trace.Verbose("Prerequisite.Download: Reading .nupkg ...");
        using (var zipInput = File.OpenRead(nupkgPath))
        using (var nupkg = new ZipArchive(zipInput))
        {
          var toolsEntries = nupkg.Entries
            .Where(x => x.FullName.StartsWith(toolsPrefix, StringComparison.OrdinalIgnoreCase))
            .ToArray();

          if (toolsEntries.Length == 0)
            throw new InvalidOperationException(
              "Something went wrong: unable to find /tools folder inside NuGet package.");

          var totalLength = toolsEntries.Sum(x => x.Length);
          Trace.Verbose(
            "Prerequisite.Download: Found {0} entries of total length {1} bytes.",
            toolsEntries.Length,
            totalLength
            );

          Trace.Verbose("Prerequisite.Download: Unpacking...");
          var totalUnzippedSize = 0L;
          foreach (var entry in toolsEntries)
          {
            var dstPath = Path.Combine(nupkgFolder, entry.FullName.Substring(toolsPrefix.Length));

            Directory.CreateDirectory(Path.GetDirectoryName(dstPath));

            using (var input = entry.Open())
            using (var output = File.Create(dstPath))
            {
              Trace.Verbose("Prerequisite.Download:   `{0}` -> `{1}`", entry.FullName, dstPath);
              CopyStream(
                input,
                output,
                entry.Length,
                new SubProgress(unzipProgress, 100.0 * totalUnzippedSize / totalLength, 1.0 * entry.Length / totalLength),
                cancellationToken
                );
            }

            if (HabitatInfo.Platform != JetPlatform.Windows)
            {
              Trace.Verbose("Setting up executable bit for {0}...", dstPath);
              Helper.ChModExecutable(dstPath);
            }

            totalUnzippedSize += entry.Length;
          }
        }

        Trace.Verbose("Prerequisite.Download: Cleaning up...");
        File.Delete(nupkgPath);

        if(!TryGetDownloadedRunner(downloadTo, runtimeIdString, out _runnerPath))
          throw new InvalidOperationException($"Something went wrong: the {Name} console profiler not found.");

        new FileStream(readyMarker, FileMode.Create).Dispose();
        Trace.Verbose("Prerequisite.Download: Confirmed everything is ready to use.");
      }
      catch (HttpRequestException e)
      {
        throw new Exception(
          $"Failed to download prerequisite package. Please, check the NuGet URL and Internet connection.\n[{nugetUrl}]",
          e
          );
      }
      catch (IOException e)
      {
        ThrowOperationCanceledExceptionIfNeeded(e);
        throw new Exception(
          $"Failed to save/unpack prerequisite package. Please, check the path and available disk space.\n[{downloadTo}]",
          e
          );
      }
    }