Example #1
0
    public void Empty_WritesEmptyLine()
    {
        using var mockConsole = new FakeConsole();

        Write.Empty();

        Assert.Equal($"{NL}", mockConsole.GetOuput());
    }
Example #2
0
    private static async Task <CompletedUpload.CompletedPartData> UploadChunk(UploadInitiateData.UploadPartData part, string filepath)
    {
        try
        {
            await Task.Yield();

            await using var stream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
            stream.Seek(part.Offset, SeekOrigin.Begin);

            byte[]    hash;
            var       chunk     = new MemoryStream();
            const int blocksize = 65536;

            using (var reader = new BinaryReader(stream, Encoding.Default, true))
            {
                using (var md5 = MD5.Create())
                {
                    md5.Initialize();
                    var length = part.Length;

                    while (length > blocksize)
                    {
                        length -= blocksize;
                        var bytes = reader.ReadBytes(blocksize);
                        md5.TransformBlock(bytes, 0, blocksize, null, 0);
                        await chunk.WriteAsync(bytes);
                    }

                    var finalBytes = reader.ReadBytes(length);
                    md5.TransformFinalBlock(finalBytes, 0, length);

                    if (md5.Hash is null)
                    {
                        Write.ErrorExit($"MD5 hashing failed for part #{part.PartNumber})");
                        throw new PublishCommandException();
                    }

                    hash = md5.Hash;
                    await chunk.WriteAsync(finalBytes);

                    chunk.Position = 0;
                }
            }

            var request = new HttpRequestMessage(HttpMethod.Put, part.Url);
            request.Content = new StreamContent(chunk);
            request.Content.Headers.ContentMD5    = hash;
            request.Content.Headers.ContentLength = part.Length;

            using var response = await HttpClient.SendAsync(request);

            try
            {
                response.EnsureSuccessStatusCode();
            }
            catch
            {
                Write.Empty();
                Write.ErrorExit(await response.Content.ReadAsStringAsync());
                throw new PublishCommandException();
            }

            if (response.Headers.ETag is null)
            {
                Write.Empty();
                Write.ErrorExit($"Response contained no ETag for part #{part.PartNumber}");
                throw new PublishCommandException();
            }

            return(new CompletedUpload.CompletedPartData()
            {
                ETag = response.Headers.ETag.Tag,
                PartNumber = part.PartNumber
            });
        }
        catch (Exception e)
        {
            Write.Empty();
            Write.ErrorExit($"Exception occured while uploading file chunk #{part.PartNumber}:", e.ToString());
            throw new PublishCommandException();
        }
    }
Example #3
0
    public static int DoBuild(Config.Config config)
    {
        var packageId = config.GetPackageId();

        Write.WithNL($"Building {Cyan(packageId)}", after: true);

        var readmePath = config.GetPackageReadmePath();

        if (!File.Exists(readmePath))
        {
            Write.ErrorExit($"Readme not found from the declared path: {White(Dim(readmePath))}");
            return(1);
        }

        var iconPath = config.GetPackageIconPath();

        if (!File.Exists(iconPath))
        {
            Write.ErrorExit($"Icon not found from the declared path: {White(Dim(iconPath))}");
            return(1);
        }

        var outDir = config.GetBuildOutputDir();

        if (!Directory.Exists(outDir))
        {
            Directory.CreateDirectory(outDir);
        }
        var filename = config.GetBuildOutputFile();

        Write.Line($"Output path {Cyan(filename)}");

        var encounteredIssues = false;

        var plan = new ArchivePlan(config);

        Write.Header("Planning for files to include in build");

        plan.AddPlan("icon.png", () => File.ReadAllBytes(iconPath));
        plan.AddPlan("README.md", () => File.ReadAllBytes(readmePath));
        plan.AddPlan("manifest.json", () => Encoding.UTF8.GetBytes(SerializeManifest(config)));

        if (config.BuildConfig.CopyPaths is not null)
        {
            foreach (var pathMap in config.BuildConfig.CopyPaths)
            {
                Write.WithNL($"Mapping {Dim(pathMap.From)} to {Dim($"/{pathMap.To}")}", before: true);
                encounteredIssues |= !AddPathToArchivePlan(plan, pathMap.From, pathMap.To);
            }
        }

        if (plan.HasErrors)
        {
            Write.Empty();
            Write.ErrorExit(
                "Build was aborted due to errors identified in planning phase",
                "Adjust your configuration so no issues are present"
                );
            return(1);
        }

        Write.Header("Writing configured files");

        using (var outputFile = File.Open(filename, FileMode.Create))
        {
            using (var archive = new ZipArchive(outputFile, ZipArchiveMode.Create))
            {
                var isWindows = OperatingSystem.IsWindows();
                foreach (var entry in plan)
                {
                    Write.Light($"Writing /{entry.Key}");
                    var archiveEntry = archive.CreateEntry(entry.Key, CompressionLevel.Optimal);
                    if (!isWindows)
                    {
                        // https://github.com/dotnet/runtime/issues/17912#issuecomment-641594638
                        // modifed solution to use a constant instead of a string conversion
                        archiveEntry.ExternalAttributes |= 0b110110100 << 16; // rw-rw-r-- permissions
                    }
                    using (var writer = new BinaryWriter(archiveEntry.Open()))
                    {
                        writer.Write(entry.Value());
                    }
                }
            }
        }

        Write.Empty();

        if (encounteredIssues || plan.HasWarnings)
        {
            Write.Note("Some issues were encountered when building, see output for more details");
            return(1);
        }
        else
        {
            Write.Success($"Successfully built {Cyan(packageId)}");
            return(0);
        }
    }