skip to content

How do you make distTar produce a compressed, reproducible archive, and what knobs control compression?

level: seniorimportance: nice to knowfreq 18%

answer

  1. distTar is a Tar -> compression = Compression.GZIP
  2. isReproducibleFileOrder = true
  3. isPreserveFileTimestamps = false
  4. withType<AbstractArchiveTask>().configureEach
  5. pin file/dir permissions for stable modes

basics

~10 s

Configure the distTar task: set compression = Compression.GZIP to produce a .tgz-style gzip tar, and set isReproducibleFileOrder = true and isPreserveFileTimestamps = false for byte-stable, reproducible archives.

solid answer

~40 s

`distTar` is a `Tar` task, so it exposes `compression`. Set `tasks.distTar { compression = Compression.GZIP }` (or BZIP2) to gzip the tar — also fix the extension via `archiveExtension.set("tgz")` if you want. For **reproducible** archives (identical bytes across machines/time so builds are cacheable and verifiable), set on both `distTar` and `distZip`: `isReproducibleFileOrder = true` (sort entries deterministically) and `isPreserveFileTimestamps = false` (zero out per-file timestamps). `distZip`, being a `Zip`, additionally has those same two flags. These are the standard `AbstractArchiveTask` reproducibility knobs and pair well with the `dirMode`/`fileMode` permission settings for stable Unix modes. Gradle ships a convenience `tasks.withType<AbstractArchiveTask>().configureEach { ... }` so you can apply reproducibility to every archive, including distZip/distTar, in one place.

code

kotlin · 11 lines
kotlin
import org.gradle.api.tasks.bundling.Compression

tasks.distTar {
    compression = Compression.GZIP
    archiveExtension.set("tgz")
}

tasks.withType<AbstractArchiveTask>().configureEach {
    isReproducibleFileOrder = true
    isPreserveFileTimestamps = false
}

go deeper

for a junior

Know distTar can be gzip-compressed via the compression property.

for a middle

Set GZIP compression and adjust the extension; recognize the two reproducibility flags exist.

for a senior

Explain why ordering + timestamps cause nondeterminism and configure both flags (plus permissions) across all archive tasks.

for a principal

Mandate reproducible builds for supply-chain/verification, applying archive reproducibility via a convention plugin and tying it to build-cache/attestation policy.

## Compression on distTar `distTar` is a `Tar` task. A plain tar is uncompressed; you opt into compression with the `compression` property: ```kotlin import org.gradle.api.tasks.bundling.Compression tasks.distTar { compression = Compression.GZIP // or Compression.BZIP2 / Compression.NONE archiveExtension.set("tgz") // cosmetic: name it .tgz } ``` `distZip` is always DEFLATE-compressed (zip's native scheme); there is no `compression` enum for it — its `entryCompression` can be set to `STORED` vs `DEFLATED` if you need uncompressed entries. ## Why reproducibility matters A **reproducible archive** produces byte-identical output given the same inputs, regardless of build machine, filesystem ordering, or wall-clock time. That makes archives verifiable (supply-chain integrity), and lets Gradle's build cache and up-to-date checks treat them as stable. Two sources of nondeterminism in archives are *entry ordering* (filesystem walk order varies) and *per-entry timestamps* (mtime of files at build time). ## The two flags On any `AbstractArchiveTask` (so on both distZip and distTar): ```kotlin tasks.withType<AbstractArchiveTask>().configureEach { isReproducibleFileOrder = true // deterministic, sorted entry order isPreserveFileTimestamps = false // constant timestamp instead of real mtime } ``` - `isReproducibleFileOrder = true` sorts entries so the order doesn't depend on the filesystem. - `isPreserveFileTimestamps = false` writes a fixed timestamp (a constant) for every entry instead of the file's real modification time. ## Permissions File/dir modes can also vary; pin them with `filePermissions { unix("644") }` / `dirPermissions { unix("755") }` (Gradle 8.3+; older: `fileMode`/`dirMode`). This keeps executable bits on start scripts stable across platforms. ## Applying broadly Because distZip/distTar are just archive tasks, the idiomatic move is the `withType<AbstractArchiveTask>().configureEach { }` block — it covers the jar, the dist archives, and any custom archives uniformly, which is the right altitude for a release build.

  • Why set isPreserveFileTimestamps = false for reproducibility?
    Real file mtimes vary per build, so archives differ byte-for-byte; writing a constant timestamp removes that source of nondeterminism.
  • Does distZip have a `compression` enum like distTar?
    No — zip uses DEFLATE natively; distZip exposes `entryCompression` (STORED vs DEFLATED) instead of the Tar `compression` enum.
  • How do you apply reproducibility to all archive tasks at once?
    Use `tasks.withType<AbstractArchiveTask>().configureEach { ... }`, which covers jar, distZip, distTar, and custom archives.

saying these in an interview costs you the question

  • Saying distZip takes a `Compression.GZIP` value — that enum is for Tar; zip uses entryCompression.
  • Claiming reproducible archives just need a fixed name — ordering and timestamps are the real levers.
  • Forgetting to also disable timestamp preservation, leaving archives non-reproducible despite sorted order.

context