Add libghostty-vt source tarball (2.8 MB vs. 38 MB for Ghostty GUI) (#11863)

This makes it so that `zig build dist -Demit-lib-vt` produces a
`libghostty-vt-<version>.tar.gz` source tarball that only contains what
is needed to build and test libghostty-vt (it cannot build Ghostty GUI
on macOS or Linux). `distcheck` has been updated to also verify cmake
works.

The source tarball goes from 38 MB to 2.8 MB for libghostty.

I also updated CI to build and test this, and also contains an assertion
that our tarball is always less than 5 MB so we can be aware if/when we
blow it up.

The `release-tip` job was also updated to add the libghostty-vt tarball
to our tip release on GH.
This commit is contained in:
Mitchell Hashimoto
2026-03-26 07:15:01 -07:00
committed by GitHub
3 changed files with 185 additions and 21 deletions

View File

@@ -163,7 +163,7 @@ jobs:
github.ref_name == 'main'
)
)
runs-on: namespace-profile-ghostty-md
runs-on: namespace-profile-ghostty-sm
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
@@ -206,6 +206,60 @@ jobs:
ghostty-source.tar.gz.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }}
source-tarball-lib-vt:
needs: [setup]
if: |
needs.setup.outputs.should_skip != 'true' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.repository_owner == 'ghostty-org' &&
github.ref_name == 'main'
)
)
runs-on: namespace-profile-ghostty-sm
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@51f3067b56fe8ae331890c77d4e454f6d60615ff # v31.10.2
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Create Tarball
run: |
rm -rf zig-out/dist
nix develop -c zig build dist -Demit-lib-vt=true
cp zig-out/dist/*.tar.gz libghostty-vt-source.tar.gz
- name: Sign Tarball
run: |
echo -n "${{ secrets.MINISIGN_KEY }}" > minisign.key
echo -n "${{ secrets.MINISIGN_PASSWORD }}" > minisign.password
nix develop -c minisign -S -m libghostty-vt-source.tar.gz -s minisign.key < minisign.password
- name: Update Release
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
tag_name: tip
target_commitish: ${{ github.sha }}
files: |
libghostty-vt-source.tar.gz
libghostty-vt-source.tar.gz.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }}
build-macos:
needs: [setup]
if: |

View File

@@ -85,6 +85,7 @@ jobs:
- skip
- build-bench
- build-dist
- build-dist-lib-vt
- build-examples-zig
- build-examples-cmake
- build-examples-cmake-windows
@@ -652,7 +653,7 @@ jobs:
run: nm result/bin/.ghostty-wrapped 2>&1 | grep -q 'main_ghostty.main'
build-dist:
runs-on: namespace-profile-ghostty-md
runs-on: namespace-profile-ghostty-sm
needs: test
outputs:
artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }}
@@ -693,6 +694,48 @@ jobs:
path: |-
ghostty-source.tar.gz
build-dist-lib-vt:
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@51f3067b56fe8ae331890c77d4e454f6d60615ff # v31.10.2
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build and Check Source Tarball
run: |
rm -rf zig-out/dist
nix develop -c zig build distcheck -Demit-lib-vt=true
- name: Verify tarball size
run: |
tarball=$(ls zig-out/dist/*.tar.gz)
size=$(stat --format=%s "$tarball")
max=$((5 * 1024 * 1024))
echo "Tarball size: $size bytes (max: $max)"
if [ "$size" -gt "$max" ]; then
echo "ERROR: tarball exceeds 5 MB"
exit 1
fi
trigger-snap:
if: github.event_name != 'pull_request'
runs-on: namespace-profile-ghostty-xsm

View File

@@ -18,17 +18,23 @@ archive_step: *std.Build.Step,
check_step: *std.Build.Step,
pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// The name prefix used for all paths in the archive.
const name = if (cfg.emit_lib_vt) "libghostty-vt" else "ghostty";
// Get the resources we're going to inject into the source tarball.
// lib-vt doesn't need GTK resources or frame data.
const alloc = b.allocator;
var resources: std.ArrayListUnmanaged(Resource) = .empty;
{
const gtk = SharedDeps.gtkNgDistResources(b);
try resources.append(alloc, gtk.resources_c);
try resources.append(alloc, gtk.resources_h);
}
{
const framedata = GhosttyFrameData.distResources(b);
try resources.append(alloc, framedata.framedata);
if (!cfg.emit_lib_vt) {
{
const gtk = SharedDeps.gtkNgDistResources(b);
try resources.append(alloc, gtk.resources_c);
try resources.append(alloc, gtk.resources_h);
}
{
const framedata = GhosttyFrameData.distResources(b);
try resources.append(alloc, framedata.framedata);
}
}
// git archive to create the final tarball. "git archive" is the
@@ -46,8 +52,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
const version = b.addWriteFiles().add("VERSION", b.fmt("{f}", .{cfg.version}));
// --add-file uses the most recent --prefix to determine the path
// in the archive to copy the file (the directory only).
git_archive.addArg(b.fmt("--prefix=ghostty-{f}/", .{
cfg.version,
git_archive.addArg(b.fmt("--prefix={s}-{f}/", .{
name, cfg.version,
}));
git_archive.addPrefixedFileArg("--add-file=", version);
}
@@ -65,8 +71,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// --add-file uses the most recent --prefix to determine the path
// in the archive to copy the file (the directory only).
git_archive.addArg(b.fmt("--prefix=ghostty-{f}/{s}/", .{
cfg.version,
git_archive.addArg(b.fmt("--prefix={s}-{f}/{s}/", .{
name, cfg.version,
std.fs.path.dirname(resource.dist).?,
}));
git_archive.addPrefixedFileArg("--add-file=", copied);
@@ -77,19 +83,28 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// This is important. Standard source tarballs extract into
// a directory named `project-version`. This is expected by
// standard tooling such as debhelper and rpmbuild.
b.fmt("--prefix=ghostty-{f}/", .{cfg.version}),
b.fmt("--prefix={s}-{f}/", .{ name, cfg.version }),
"-o",
});
const output = git_archive.addOutputFileArg(b.fmt(
"ghostty-{f}.tar.gz",
.{cfg.version},
"{s}-{f}.tar.gz",
.{ name, cfg.version },
));
git_archive.addArg("HEAD");
// When building for lib-vt only, exclude large directories that
// are not needed to build libghostty-vt. This significantly reduces
// the size of the resulting archive.
if (cfg.emit_lib_vt) {
for (lib_vt_excludes) |exclude| {
git_archive.addArg(b.fmt(":(exclude){s}", .{exclude}));
}
}
// The install step to put the dist into the build directory.
const install = b.addInstallFile(
output,
b.fmt("dist/ghostty-{f}.tar.gz", .{cfg.version}),
b.fmt("dist/{s}-{f}.tar.gz", .{ name, cfg.version }),
);
// The check step to ensure the archive works.
@@ -100,8 +115,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// This is the root Ghostty source dir of the extracted source tarball.
// i.e. this is way `build.zig` is.
const extract_dir = check
.addOutputDirectoryArg("ghostty")
.path(b, b.fmt("ghostty-{f}", .{cfg.version}));
.addOutputDirectoryArg(name)
.path(b, b.fmt("{s}-{f}", .{ name, cfg.version }));
// Check that tests pass within the extracted directory. This isn't
// a fully hermetic test because we're sharing the Zig cache. In
@@ -109,7 +124,12 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// in the interest of speed we don't do that for now and hope other
// CI catches any issues.
const check_test = step: {
const step = b.addSystemCommand(&.{ "zig", "build", "test" });
// For lib-vt, we run the lib-vt tests instead of the full test suite.
const check_cmd = if (cfg.emit_lib_vt)
&[_][]const u8{ "zig", "build", "test-lib-vt", "-Demit-lib-vt=true" }
else
&[_][]const u8{ "zig", "build", "test" };
const step = b.addSystemCommand(check_cmd);
step.setCwd(extract_dir);
// Must be set so that Zig knows that this command doesn't
@@ -133,6 +153,23 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
check_test.step.dependOn(&check_path.step);
}
// For lib-vt, also verify the CMake build works from the tarball.
if (cfg.emit_lib_vt) {
const cmake_build_dir = extract_dir.path(b, "cmake-build");
const cmake_configure = b.addSystemCommand(&.{ "cmake", "-B" });
cmake_configure.addDirectoryArg(cmake_build_dir);
cmake_configure.setCwd(extract_dir);
cmake_configure.expectExitCode(0);
cmake_configure.step.dependOn(&check.step);
const cmake_build = b.addSystemCommand(&.{ "cmake", "--build" });
cmake_build.addDirectoryArg(cmake_build_dir);
cmake_build.expectExitCode(0);
cmake_build.step.dependOn(&cmake_configure.step);
check_test.step.dependOn(&cmake_build.step);
}
return .{
.archive = output,
.install_step = &install.step,
@@ -141,6 +178,36 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
};
}
/// Paths to exclude from the dist archive when building for lib-vt only.
/// These are large files and directories that are not needed to build or
/// test libghostty-vt, specified as git pathspec exclude patterns.
const lib_vt_excludes = &[_][]const u8{
// App and platform resources
"images",
"macos",
"dist/doxygen",
"dist/linux",
"dist/macos",
"dist/windows",
"flatpak",
"snap",
"po",
"example",
// Test corpus (lib-vt tests use embedded testdata within src/terminal/)
"test",
// Large binary assets
"src/font/res",
"src/crash/testdata",
"pkg/wuffs/src/too_big.jpg",
"pkg/wuffs/src/too_big.png",
"pkg/breakpad/vendor",
// Vendored libraries not used by lib-vt
"vendor",
};
/// A dist resource is a resource that is built and distributed as part
/// of the source tarball with Ghostty. These aren't committed to the Git
/// repository but are built as part of the `zig build dist` command.