Skip to content
This repository has been archived by the owner on Mar 31, 2024. It is now read-only.

Commit

Permalink
builder: Optionally compress man & info pages. Resolves #16
Browse files Browse the repository at this point in the history
Compress any man or info page files found in the manifest with zstd,
if enabled by the packager.

There are two considerations:-
- It _will_ increase the size of the resulting .stone file(s),
  (compressing .stones with --long could resolve this in the future).
- Updating symlinks is not yet tested.
  • Loading branch information
joebonrichie committed Jan 15, 2023
1 parent ca9e003 commit d84f81a
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
115 changes: 115 additions & 0 deletions source/mason/build/analysers/compressman.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* SPDX-FileCopyrightText: Copyright © 2020-2023 Serpent OS Developers
*
* SPDX-License-Identifier: Zlib
*/

/**
* mason.build.analysers.compressman;
*
* Compress man or info pages with zstd
*
* Authors: Copyright © 2020-2023 Serpent OS Developers
* License: Zlib
*/

module mason.build.analysers.compressman;

import mason.build.builder : Builder;
import mason.build.context;
import moss.core.sizing : formattedSize;
import std.algorithm : canFind, endsWith;
import std.experimental.logger;
import std.file;
import std.stdio: File, toFile;
import std.string : format;

public import moss.deps.analysis;

/**
* Detect man or info pages
*
* Params:
* analyser = Scoped analyser for this run
* fileInfo = Current file to run analysis on
* Returns: AnalysisReturn.NextFunction when a page is found and compressman is enabled,
* otherwise AnalysisReturn.NextHandler.
*/
public AnalysisReturn acceptManInfoPages(scope Analyser analyser, ref FileInfo fileInfo)
{
if (!buildContext.spec.options.compressman || fileInfo.type != FileType.Regular)
{
return AnalysisReturn.NextHandler;
}

auto filename = fileInfo.path;

/* Accept Man pages */
if (filename.canFind("man") && filename.endsWith("1", "2", "3", "4", "5", "6", "7", "8", "9"))
{
return AnalysisReturn.NextFunction;
}
/* Accept Info pages */
if (filename.canFind("info") && filename.endsWith(".info"))
{
return AnalysisReturn.NextFunction;
}

return AnalysisReturn.NextHandler;
}

/**
* Compress man or info pages with zstd
*
* Params:
* analyser = Scoped analyser for this run
* fileInfo = Current file to run analysis on
* Returns: AnalysisReturn.IgnoreFile always
*/
static AnalysisReturn compressPage(scope Analyser analyser, ref FileInfo fileInfo)
{
import zstd.highlevel.context : CompressionContext;
import std.datetime : abs, SysTime;

auto filename = fileInfo.path;
auto instance = analyser.userdata!Builder;

auto compressor = new CompressionContext();

/* We have a symlink file, update it to point to the compressed file */
// FIXME: Not tested
if ((fileInfo.type == FileType.Symlink) && (fileInfo.type != FileType.Directory))
{
auto actualpath = std.file.readLink(filename);
std.file.symlink(format!"%s.zst"(actualpath), format!"%s.zst"(filename));
/* Collect the updated symlink into the manifest */
instance.collectPath(format!"%s.zst"(fileInfo.fullPath), instance.installRoot);
/* Remove the original file */
return AnalysisReturn.IgnoreFile;
}

/* Get atime, mtime of the file */
SysTime accessTime, modificationTime;
getTimes(fileInfo.fullPath, accessTime, modificationTime);

/* Compress it in memory */
auto page = std.file.read(fileInfo.fullPath);
auto compressedpage = compressor.compress(page, 19);
immutable double presize = page.length;
immutable double postsize = compressedpage.length;
info(format!"[Man] Compressed: %s. Original size: %s Compressed size: %s"(format!"%s.zst"(filename),
formattedSize(presize), formattedSize(postsize)));

/* Write the compressed file to disk */
File f = File(format!"%s.zst"(fileInfo.fullPath), "w");
f.rawWrite(compressedpage);

/* Set atime, mtime of compressed file to the original for reproducibility */
setTimes(format!"%s.zst"(fileInfo.fullPath), accessTime, modificationTime);

/* Collect the compressed file into the manifest */
instance.collectPath(format!"%s.zst"(fileInfo.fullPath), instance.installRoot);

/* Remove the original pre-compressed file */
return AnalysisReturn.IgnoreFile;
}
1 change: 1 addition & 0 deletions source/mason/build/analysers/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module mason.build.analysers;

public import mason.build.analysers.binary;
public import mason.build.analysers.cmake;
public import mason.build.analysers.compressman;
public import mason.build.analysers.elves;
public import mason.build.analysers.rejects;
public import mason.build.analysers.pkgconfig;
3 changes: 3 additions & 0 deletions source/mason/build/builder.d
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@ private:
&acceptCmakeFiles, &handleCmakeFiles, &includeFile
], 50),

/* Compress man and info pages if enabled */
AnalysisChain("compressman", [&acceptManInfoPages, &compressPage], 40),

/* Default inclusion policy */
AnalysisChain("default", [&includeFile], 0),
];
Expand Down
1 change: 1 addition & 0 deletions source/mason/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ libmason_sources = [
'package.d',
'build/analysers/binary.d',
'build/analysers/cmake.d',
'build/analysers/compressman.d',
'build/analysers/elves.d',
'build/analysers/package.d',
'build/analysers/pkgconfig.d',
Expand Down

0 comments on commit d84f81a

Please sign in to comment.