Stop compiling the GPL crate GPUI drags in behind the framework
Lumbridge is Apache-2.0, and decision 0023 quietly made it link
GPL-3.0-or-later. `crates/gpui/Cargo.toml` at the pinned revision carries
`ztracing.workspace = true` -- unconditional, not optional, not behind a
feature -- and `ztracing` is GPL-3.0-or-later, as are the `zlog` and
`ztracing_macro` it pulls. `sum_tree` asks for it too. The path is the ordinary
Linux build, not an `--all-features` artefact and not a dev-dependency:
lumbridge -> gpui_platform -> gpui_linux -> gpui -> ztracing -> zlog
-> ztracing_macro
`cargo deny check licenses` failed on it, exit 4.
This is the second thing decision 0023 got wrong by reading the manifests of the
crates it added instead of resolving the graph; the first was believing there
were two Zed Git sources when there are five. Both were found by a gate that had
never been run.
There was no feature to turn off, so the choice was to relax the licence policy,
drop the framework, or stop compiling the crate. `ztracing` is now redirected by
a `[patch]` table at `crates/lumbridge-ztracing-shim`, a first-party
zero-dependency no-op under Apache-2.0. `zlog` and `ztracing_macro` were
reachable only through it and leave the lockfile with it.
The shim is small because the usage is: nine `#[instrument(skip_all)]` sites
across `gpui/src/svg_renderer.rs`, `sum_tree/src/sum_tree.rs` and
`sum_tree/src/cursor.rs`, and nothing else. Upstream's own crate compiles to
almost exactly this whenever the `ztracing` cfg is off, which is every build
that is not a Tracy profiling build, so no shipping behaviour is lost. It is a
proc-macro crate deliberately: such a crate can export nothing but proc macros,
so an upstream revision that starts using `ztracing::Span` or
`ztracing::info_span!` fails to compile and names the shim, rather than
resolving to something plausible.
`scripts/workspace-guard.sh` gained a third gate asserting, against Cargo.lock
rather than the manifest, that no `ztracing`, `zlog` or `ztracing_macro`
resolves to a Zed source and that the patch table is still present. `cargo deny`
already checks this, and the duplication is the point: `scripts/ci.sh`
downgrades a missing cargo-deny to a warning unless `LUMBRIDGE_CI_STRICT=1`, and
that is how the licence closure went ungated once already. A `[patch]` is an
unusually quiet thing to lose -- delete the table and everything still compiles,
still passes, and is GPL again.
Removing the three GPL rejections exposed a fourth that had been sitting beside
them and was never reported separately: `libbz2-rs-sys` under `bzip2-1.0.6`,
reached through async-compression <- http_client <- gpui. It is BSD-style and
permissive with no copyleft, and is allowed in `deny.toml` with that reasoning
written down. `cargo deny check licenses sources` is exit 0 for the first time.
The Git-source allowances in `deny.toml` are all still needed; the patched
crate's own source was `zed.git`, which `gpui` still requires.
Decision 0025 records the whole of it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SPYebLiN2w4TqnHUYGdECq
This commit is contained in:
co-authored by
Claude Opus 5
parent
3cb5e1002c
commit
2aab0c4aab
Generated
-82
@@ -3786,15 +3786,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
@@ -5484,15 +5475,6 @@ dependencies = [
|
||||
"digest 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared_library"
|
||||
version = "0.1.9"
|
||||
@@ -5993,15 +5975,6 @@ dependencies = [
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.11.3"
|
||||
@@ -6253,32 +6226,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6521,12 +6468,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.13.2"
|
||||
@@ -7910,17 +7851,6 @@ version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12"
|
||||
|
||||
[[package]]
|
||||
name = "zlog"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed.git?rev=ce48461eaadd16c65c31f835511ab96bd3b6e746#ce48461eaadd16c65c31f835511ab96bd3b6e746"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"collections",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.23"
|
||||
@@ -7930,18 +7860,6 @@ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
[[package]]
|
||||
name = "ztracing"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed.git?rev=ce48461eaadd16c65c31f835511ab96bd3b6e746#ce48461eaadd16c65c31f835511ab96bd3b6e746"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"zlog",
|
||||
"ztracing_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ztracing_macro"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed.git?rev=ce48461eaadd16c65c31f835511ab96bd3b6e746#ce48461eaadd16c65c31f835511ab96bd3b6e746"
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
|
||||
+26
@@ -12,6 +12,7 @@ members = [
|
||||
"crates/lumbridge-terminal",
|
||||
"crates/lumbridge-theme",
|
||||
"crates/lumbridge-ui-fixture",
|
||||
"crates/lumbridge-ztracing-shim",
|
||||
"tools/theme-gen",
|
||||
]
|
||||
exclude = ["spikes"]
|
||||
@@ -30,3 +31,28 @@ unsafe_code = "forbid"
|
||||
[workspace.lints.clippy]
|
||||
all = "warn"
|
||||
pedantic = "warn"
|
||||
|
||||
# GPUI's transitive GPL dependency, replaced by a first-party no-op.
|
||||
#
|
||||
# `gpui` at the pinned revision carries `ztracing.workspace = true` --
|
||||
# unconditional and not behind a feature -- and `ztracing` is GPL-3.0-or-later,
|
||||
# as are the `zlog` and `ztracing_macro` it drags with it. All three land in the
|
||||
# ordinary Linux build, not merely under `--all-features`, which makes them a
|
||||
# licence problem for an Apache-2.0 product rather than a lint to silence.
|
||||
# `cargo deny check licenses` failed on exactly this.
|
||||
#
|
||||
# The graph uses one symbol from the crate: an `#[instrument(skip_all)]`
|
||||
# attribute, at nine sites across `gpui` and `sum_tree`. So `ztracing` is
|
||||
# redirected at a workspace crate that provides that attribute and nothing else.
|
||||
# `zlog` and `ztracing_macro` were reachable only through `ztracing` and leave
|
||||
# the resolved graph with it.
|
||||
#
|
||||
# The URL is the one Cargo.lock records for the source being replaced --
|
||||
# `git+https://github.com/zed-industries/zed.git?rev=...` -- and it must stay
|
||||
# spelled that way, `.git` included, or the patch silently applies to nothing.
|
||||
# `scripts/workspace-guard.sh` asserts the result rather than the intent: that
|
||||
# no `ztracing`, `zlog` or `ztracing_macro` resolves to a Zed source.
|
||||
#
|
||||
# Read crates/lumbridge-ztracing-shim/src/lib.rs before bumping the revision.
|
||||
[patch."https://github.com/zed-industries/zed.git"]
|
||||
ztracing = { path = "crates/lumbridge-ztracing-shim" }
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# This package is deliberately named `ztracing` and not `lumbridge-ztracing-shim`.
|
||||
#
|
||||
# A `[patch]` entry can only replace a package with one of the SAME NAME, so the
|
||||
# name is load-bearing: the root manifest's
|
||||
# `[patch."https://github.com/zed-industries/zed.git"]` table redirects the
|
||||
# `ztracing` that `gpui` and `sum_tree` ask for at this directory, and Cargo
|
||||
# matches the two by package name. The directory keeps the `lumbridge-` prefix
|
||||
# every other crate here has so that a reader browsing `crates/` can see whose
|
||||
# code it is; `src/lib.rs` explains why the package underneath answers to a
|
||||
# different name.
|
||||
[package]
|
||||
name = "ztracing"
|
||||
description = "A no-op stand-in for Zed's GPL-licensed ztracing, so Lumbridge's build graph stays Apache-2.0"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
publish = false
|
||||
|
||||
# A proc-macro crate, because the only symbol the graph reaches for is an
|
||||
# attribute macro. Nothing else can live in a crate declared this way, which is
|
||||
# the point: an upstream revision that starts using `ztracing::Span` or
|
||||
# `ztracing::info_span!` fails to compile here rather than quietly resolving.
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
# No dependencies. `syn` and `quote` would only be needed to parse an item this
|
||||
# macro then reassembles unchanged; returning the input `TokenStream` untouched
|
||||
# is both correct and three crates cheaper.
|
||||
[dependencies]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,103 @@
|
||||
//! A first-party `ztracing` that does nothing, so that Lumbridge stays Apache-2.0.
|
||||
//!
|
||||
//! Lumbridge is Apache-2.0, and `DISTRIBUTION.md` treats the licence closure of
|
||||
//! everything it links as a hard gate rather than a preference. Decision 0023
|
||||
//! moved the UI framework from published crates.io releases to a pinned
|
||||
//! revision of Zed, and that move brought more than `gpui` with it: it brought
|
||||
//! `gpui`'s own workspace-internal dependencies, which are not published
|
||||
//! anywhere and were never chosen one by one.
|
||||
//!
|
||||
//! One of them is **GPL-3.0-or-later**. `crates/gpui/Cargo.toml` at the pinned
|
||||
//! revision carries `ztracing.workspace = true` -- unconditional, not optional,
|
||||
//! not behind a feature -- and `ztracing` in turn pulls `zlog` and
|
||||
//! `ztracing_macro`, both also GPL-3.0-or-later. `sum_tree` asks for `ztracing`
|
||||
//! too. The path is short and entirely inside the build we ship:
|
||||
//!
|
||||
//! ```text
|
||||
//! lumbridge -> gpui_platform -> gpui_linux -> gpui -> ztracing -> zlog
|
||||
//! -> ztracing_macro
|
||||
//! ```
|
||||
//!
|
||||
//! This is not an `--all-features` artefact and not a dev-dependency. It is the
|
||||
//! ordinary Linux build, and `cargo deny check licenses` failed on it with
|
||||
//! `rejected: license is not explicitly allowed` for GPL-3.0-or-later. There is
|
||||
//! no feature flag to turn off, so there were three ways out: relax the licence
|
||||
//! policy, drop the framework, or stop compiling those crates. The first
|
||||
//! trades the product's licence for a lint's convenience and the second throws
|
||||
//! away decision 0023. This crate is the third.
|
||||
//!
|
||||
//! # What it replaces
|
||||
//!
|
||||
//! The root manifest's `[patch."https://github.com/zed-industries/zed.git"]`
|
||||
//! table redirects the `ztracing` package -- and only that package -- at this
|
||||
//! directory. Nothing else about the pinned revision changes: `gpui` and
|
||||
//! `gpui_platform` still resolve to
|
||||
//! `ce48461eaadd16c65c31f835511ab96bd3b6e746`, and `scripts/workspace-guard.sh`
|
||||
//! still asserts it. Because `zlog` and `ztracing_macro` were reachable ONLY
|
||||
//! through `ztracing`, patching the one crate removes all three from the
|
||||
//! resolved graph; they no longer appear in `Cargo.lock` at all.
|
||||
//!
|
||||
//! # The entire API surface the graph uses
|
||||
//!
|
||||
//! Every reference to `ztracing` or `zlog` across the eighteen Zed packages in
|
||||
//! Lumbridge's resolved graph, found by grepping the vendored checkout rather
|
||||
//! than by reading manifests:
|
||||
//!
|
||||
//! - `gpui/src/svg_renderer.rs`, two sites: `#[ztracing::instrument(skip_all)]`
|
||||
//! - `sum_tree/src/sum_tree.rs` and `sum_tree/src/cursor.rs`:
|
||||
//! `use ztracing::instrument;`, then seven `#[instrument(skip_all)]` sites
|
||||
//! - `sum_tree/src/sum_tree.rs:1401`: `zlog::init_test()` -- inside `#[cfg(test)]`,
|
||||
//! reached through a dev-dependency that Cargo never resolves for a
|
||||
//! non-workspace package, which is why no `zlog` shim is needed
|
||||
//!
|
||||
//! That is the whole of it: one attribute macro, always with `skip_all`. So
|
||||
//! [`instrument`] is an attribute proc-macro that returns the item it was given,
|
||||
//! byte for byte, and discards its arguments. Upstream's own crate does almost
|
||||
//! exactly this when the `ztracing` cfg is off -- which is to say, in every
|
||||
//! build that is not a Tracy profiling build -- so the shim is not a
|
||||
//! behavioural downgrade of a shipping feature. It is the same nothing,
|
||||
//! reimplemented under a licence we can distribute.
|
||||
//!
|
||||
//! # What a maintainer must check when the gpui revision is bumped
|
||||
//!
|
||||
//! **Whether upstream started using a `ztracing` symbol this crate does not
|
||||
//! provide.** That is the one way this arrangement can go wrong, and the design
|
||||
//! makes it go wrong loudly: a proc-macro crate can export nothing except proc
|
||||
//! macros, so `ztracing::Span`, `ztracing::info_span!`, `ztracing::init()`,
|
||||
//! `ztracing::Level` or `ztracing::field` all fail to resolve at compile time
|
||||
//! with `E0432`/`E0433` naming this crate. There is no silent fallback and no
|
||||
//! runtime surprise; the build stops.
|
||||
//!
|
||||
//! When it does, the fix is not to widen this crate by reflex. Read the new
|
||||
//! upstream use first: if it is another zero-cost annotation, add the
|
||||
//! corresponding no-op here (which will mean splitting this into a normal
|
||||
//! library crate plus a proc-macro crate, since the two cannot share one
|
||||
//! package). If instead upstream has started routing real telemetry through
|
||||
//! `ztracing`, that is a decision record, because Lumbridge ships no telemetry
|
||||
//! by default and `AGENTS.md` says so.
|
||||
//!
|
||||
//! Also re-run `cargo deny check licenses sources` and confirm the bump has not
|
||||
//! introduced a *second* GPL crate on a different path. The lesson of decision
|
||||
//! 0023 -- recorded there, in the correction about there being five Zed Git
|
||||
//! sources rather than two -- is that reading the manifests of the crates you
|
||||
//! added never finds a transitive dependency. Only resolving the graph does.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
/// Zed's `#[instrument]`, with the tracing removed.
|
||||
///
|
||||
/// Expands to the annotated item unchanged and drops the attribute arguments.
|
||||
/// Every call site in Lumbridge's graph passes `skip_all`, which asks for no
|
||||
/// fields to be recorded, so there is nothing here to preserve even in
|
||||
/// principle.
|
||||
///
|
||||
/// Deliberately accepts any argument tokens without parsing them: a future
|
||||
/// upstream `#[instrument(name = "...")]` should keep compiling, because the
|
||||
/// failure mode worth having is a missing *symbol*, which is loud, and not a
|
||||
/// spuriously rejected argument list, which would only be noise.
|
||||
#[proc_macro_attribute]
|
||||
pub fn instrument(_arguments: TokenStream, item: TokenStream) -> TokenStream {
|
||||
item
|
||||
}
|
||||
@@ -34,6 +34,15 @@ allow = [
|
||||
# attribution requirement on downstream distribution. It arrives through
|
||||
# ureq, which the Claude usage endpoint needs (decision 0016).
|
||||
"CDLA-Permissive-2.0",
|
||||
# bzip2-1.0.6 is the bzip2/libbzip2 licence carried by libbz2-rs-sys. It is a
|
||||
# BSD-style permissive licence -- retain the notice, do not misrepresent the
|
||||
# origin, no warranty -- with no copyleft and no source-disclosure term. It
|
||||
# reaches the graph as libbz2-rs-sys -> bzip2 -> compression-codecs ->
|
||||
# async-compression -> http_client -> gpui, so it is in the ordinary Linux
|
||||
# build and not an `--all-features` artefact. It was already failing this
|
||||
# gate alongside the GPL crates; removing those made it the only rejection
|
||||
# left, which is the first time anyone could see it.
|
||||
"bzip2-1.0.6",
|
||||
# NCSA is libfuzzer-sys, a permissive BSD/MIT-style licence. It reaches the
|
||||
# graph only as rav1e -> ravif -> image -> gpui and only under
|
||||
# `all-features`; no shipped build links it. Allowed rather than excluded so
|
||||
@@ -73,7 +82,22 @@ allow-git = [
|
||||
# backends now live in crates Zed does not publish at all.
|
||||
"https://github.com/zed-industries/zed",
|
||||
# Not optional and not obvious: gpui_wgpu reaches font-kit through a Git
|
||||
# source of Zed's own, so adopting the framework brings two Git sources
|
||||
# rather than one. Naming it here is what stops that arriving unnoticed.
|
||||
# source of Zed's own. Decision 0023 predicted that this made two Git
|
||||
# sources rather than one. It was wrong, and the three below are why -- the
|
||||
# resolved graph carries five Zed sources, not two. Each is reached through
|
||||
# gpui_platform, which is to say through the Linux backend the move was made
|
||||
# to obtain, and each is listed rather than waved through with a wildcard.
|
||||
"https://github.com/zed-industries/font-kit",
|
||||
# X11 input methods, supplying zed-xim/xim-ctext/xim-parser to gpui_linux.
|
||||
# This is the IME path, so it is load-bearing for a hard gate rather than
|
||||
# incidental.
|
||||
"https://github.com/zed-industries/xim-rs",
|
||||
# Reached twice: through gpui_web, and through scheduler <- gpui.
|
||||
"https://github.com/zed-industries/wasm_thread",
|
||||
# Resolved in Cargo.lock but NOT reachable in this target's graph, so
|
||||
# cargo deny does not currently object to it. Named anyway: it is screen
|
||||
# capture, it arrives on another platform's build, and discovering it for
|
||||
# the first time in a macOS CI failure would teach us nothing we cannot
|
||||
# write down now.
|
||||
"https://github.com/zed-industries/scap",
|
||||
]
|
||||
|
||||
@@ -89,9 +89,22 @@ failure is unattributable:
|
||||
versions of new `clippy::pedantic` lints arrive as hard errors under
|
||||
`-D warnings`. Isolating this stage is what stops a lint avalanche being
|
||||
mistaken for a GPUI API break.
|
||||
3. **`deny.toml`.** Add `zed-industries/zed` and `zed-industries/font-kit` to
|
||||
`allow-git`. The second is not optional: `gpui_wgpu` reaches `font-kit`
|
||||
through a Git source, so the move brings two Git sources, not one.
|
||||
3. **`deny.toml`.** Add the Zed Git sources to `allow-git`. This record
|
||||
originally said there were two, `zed-industries/zed` and
|
||||
`zed-industries/font-kit`. **That was wrong: there are five.** The graph also
|
||||
carries `xim-rs` (X11 input methods, feeding `gpui_linux` -- the IME path,
|
||||
so load-bearing for a hard gate rather than incidental), `wasm_thread`
|
||||
(reached twice, through `gpui_web` and through `scheduler` <- `gpui`), and
|
||||
`scap`, which resolves in the lockfile without being reachable in this
|
||||
target's graph and so is named before some later platform's build finds it
|
||||
first.
|
||||
|
||||
The error is worth keeping visible rather than quietly corrected. It was made
|
||||
by reading the manifests of the two crates being added, which is exactly the
|
||||
reasoning that misses a transitive Git source; only resolving the graph
|
||||
answers the question. `cargo deny check sources` is what caught it, on the
|
||||
commit after the allowance was written -- which is the argument for running
|
||||
that check at all.
|
||||
4. **The dependency swap.** `gpui` and `gpui_platform` at the pinned rev;
|
||||
`wayland`/`x11` requested on `gpui_platform`, where they still mean
|
||||
something; and `Application::new()` — which does not exist at that revision —
|
||||
@@ -101,10 +114,21 @@ failure is unattributable:
|
||||
6. **The probe changes job**: it stops proving AccessKit exists and starts
|
||||
proving the next revision still compiles.
|
||||
|
||||
The renderer swap from blade to wgpu in stage 4 is the least characterised risk.
|
||||
`scripts/native-libs.sh` addresses one missing `libxkbcommon-x11` symlink and
|
||||
says nothing about a Vulkan or GL loader, and the Gitea job installs no wgpu
|
||||
dependency. Expect to learn something here.
|
||||
The renderer swap from blade to wgpu in stage 4 was called the least
|
||||
characterised risk here, and at build time it cost nothing: the whole closure
|
||||
compiled on the existing `libxkbcommon-x11` shim, with no Vulkan or GL loader
|
||||
problem and no new native dependency. That is not the same as the risk being
|
||||
disproven. Nothing in `cargo check`, `clippy`, or the test suite opens a window,
|
||||
so the renderer has still never run. The risk moved from build time to first
|
||||
launch; it did not go away.
|
||||
|
||||
The rest of stage 4 was smaller than expected. The entire API delta across the
|
||||
ten-month jump was three signatures over nineteen sites: `Window::focus` taking
|
||||
the `App` it used to reach through the window, `flex_shrink` taking the factor
|
||||
it used to assume, and `Application::new` becoming
|
||||
`gpui_platform::application()`. No crate outside `apps/lumbridge` needed any
|
||||
change, because none of them imports a gpui type -- the narrow boundary
|
||||
`ARCHITECTURE.md` insisted on is the reason this was an afternoon.
|
||||
|
||||
## What is knowingly still unmet
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# 0025: GPUI's GPL dependency is patched out, not tolerated
|
||||
|
||||
Status: accepted. Amends decision 0023, which chose the pinned Zed revision
|
||||
without noticing what came with it. Does not change that revision.
|
||||
|
||||
## The decision
|
||||
|
||||
`ztracing` is redirected, by a `[patch]` table in the root manifest, at
|
||||
`crates/lumbridge-ztracing-shim` — a first-party, zero-dependency, no-op crate
|
||||
under Apache-2.0. Nothing else about decision 0023's pin changes.
|
||||
|
||||
## The problem
|
||||
|
||||
Lumbridge is Apache-2.0, and `DISTRIBUTION.md` treats the licence closure of
|
||||
everything the product links as a hard gate. Decision 0023 replaced published
|
||||
`gpui` releases with a pinned revision of Zed's monorepo, and a monorepo
|
||||
revision does not bring only the crates you named. `crates/gpui/Cargo.toml` at
|
||||
`ce48461` carries:
|
||||
|
||||
```toml
|
||||
ztracing.workspace = true
|
||||
```
|
||||
|
||||
Unconditional. Not optional. Not behind a feature. `ztracing` is
|
||||
**GPL-3.0-or-later**, and it pulls `zlog` and `ztracing_macro`, both also
|
||||
GPL-3.0-or-later. `sum_tree` asks for `ztracing` as well. The path is entirely
|
||||
inside the build that ships:
|
||||
|
||||
```text
|
||||
lumbridge -> gpui_platform -> gpui_linux -> gpui -> ztracing -> zlog
|
||||
-> ztracing_macro
|
||||
```
|
||||
|
||||
This is not an `--all-features` artefact and not a dev-dependency. It is the
|
||||
ordinary Linux build. `cargo deny check licenses` failed on it, exit 4, three
|
||||
rejections, each `license is not explicitly allowed`.
|
||||
|
||||
That is the second thing decision 0023 got wrong by reading manifests instead of
|
||||
resolving a graph. The first was believing there were two Zed Git sources when
|
||||
there are five. Both were caught by a gate that had never been run, and both
|
||||
argue the same point: the transitive closure is the only thing that answers a
|
||||
licensing question.
|
||||
|
||||
## What was rejected
|
||||
|
||||
**Relax `deny.toml`.** Adding GPL-3.0-or-later to the allow list would trade the
|
||||
product's licence for a green build. The gate exists precisely to stop that
|
||||
being done quietly.
|
||||
|
||||
**Turn the feature off.** There is no feature. `ztracing.workspace = true` has
|
||||
no `optional = true` beside it, and no `cfg` guards its use sites.
|
||||
|
||||
**Drop GPUI.** That throws away decision 0023 and, until `lumbridge-toolkit`
|
||||
exists, the product's ability to draw a window.
|
||||
|
||||
**Vendor and relicense.** Not available: GPL is GPL.
|
||||
|
||||
## What was chosen, and why it is small
|
||||
|
||||
Every use of `ztracing` and `zlog` across the eighteen Zed packages in the
|
||||
resolved graph, found by grepping the vendored checkout rather than the
|
||||
manifests:
|
||||
|
||||
- `gpui/src/svg_renderer.rs`, two sites: `#[ztracing::instrument(skip_all)]`
|
||||
- `sum_tree/src/sum_tree.rs` and `sum_tree/src/cursor.rs`:
|
||||
`use ztracing::instrument;`, then seven `#[instrument(skip_all)]` sites
|
||||
- `sum_tree/src/sum_tree.rs:1401`: `zlog::init_test()`, inside `#[cfg(test)]`,
|
||||
behind a dev-dependency Cargo never resolves for a non-workspace package —
|
||||
which is why no `zlog` shim is needed and why `zlog` leaves the lockfile
|
||||
entirely
|
||||
|
||||
Nine attribute sites, all `skip_all`, and nothing else. So the shim is one
|
||||
attribute proc-macro that returns its input unchanged. Upstream's own crate
|
||||
compiles to almost exactly that whenever the `ztracing` cfg is off — which is
|
||||
every build that is not a Tracy profiling build — so no shipping behaviour is
|
||||
lost. Lumbridge ships no telemetry by default in any case.
|
||||
|
||||
Because `zlog` and `ztracing_macro` were reachable only through `ztracing`,
|
||||
patching the one package removes all three: they no longer appear in
|
||||
`Cargo.lock`.
|
||||
|
||||
## How it is held
|
||||
|
||||
`scripts/workspace-guard.sh` gained a third gate. It asserts, against
|
||||
`Cargo.lock` rather than the manifest, that no `ztracing`, `zlog` or
|
||||
`ztracing_macro` resolves to a Zed source, and that the `[patch]` table is still
|
||||
in `Cargo.toml`.
|
||||
|
||||
`cargo deny` already checks this, so the duplication is deliberate.
|
||||
`scripts/ci.sh` downgrades a missing `cargo-deny` to a warning unless
|
||||
`LUMBRIDGE_CI_STRICT=1`, and that arrangement is how the licence closure went
|
||||
ungated once already — green on a runner that had never installed the tool. The
|
||||
guard needs no tool and runs in milliseconds. It is what makes deleting the
|
||||
patch a build failure rather than a silent relicensing of the product.
|
||||
|
||||
A `[patch]` is an unusually quiet thing to lose: delete the table and everything
|
||||
still compiles, still passes every test, and is GPL again.
|
||||
|
||||
## The unrelated failure this exposed
|
||||
|
||||
Removing the three GPL rejections left one behind that had been sitting beside
|
||||
them: `libbz2-rs-sys` under the `bzip2-1.0.6` licence, reached through
|
||||
`bzip2 -> compression-codecs -> async-compression -> http_client -> gpui`. It is
|
||||
BSD-style and permissive — retain the notice, do not misrepresent the origin, no
|
||||
warranty — with no copyleft and no source-disclosure term, and it is allowed in
|
||||
`deny.toml` with that reasoning written down. It is recorded here because it was
|
||||
never reported as a separate finding; it was simply the fourth line of a failure
|
||||
everyone read as being about GPL.
|
||||
|
||||
## What the next revision bump must check
|
||||
|
||||
Whether upstream started using a `ztracing` symbol the shim does not provide.
|
||||
The shim is a proc-macro crate, which can export nothing except proc macros, so
|
||||
`ztracing::Span`, `ztracing::info_span!`, `ztracing::init()`, `ztracing::Level`
|
||||
and `ztracing::field` all fail to resolve at compile time and name this crate in
|
||||
the error. There is no silent fallback.
|
||||
|
||||
The fix then is not to widen the shim by reflex. If the new use is another
|
||||
zero-cost annotation, add the matching no-op — which means splitting the shim
|
||||
into a library crate and a proc-macro crate, since one package cannot be both.
|
||||
If upstream has started routing real telemetry through `ztracing`, that is a
|
||||
decision record, because no telemetry is enabled by default here.
|
||||
|
||||
And run `cargo deny check licenses sources` at the new revision before anything
|
||||
else. A monorepo pin can acquire a *different* GPL crate on a different path,
|
||||
and reading the manifests of the crates you added will not find it.
|
||||
@@ -86,7 +86,55 @@ for pkg in gpui gpui_platform; do
|
||||
fi
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. No GPL crate has come back into the graph.
|
||||
#
|
||||
# `gpui` depends on `ztracing` unconditionally, and `ztracing` -- with the
|
||||
# `zlog` and `ztracing_macro` it pulls -- is GPL-3.0-or-later. That is a
|
||||
# licence problem for an Apache-2.0 product, and it is in the ordinary Linux
|
||||
# build, not behind a feature. The root manifest's
|
||||
# `[patch."https://github.com/zed-industries/zed.git"]` table redirects
|
||||
# `ztracing` at crates/lumbridge-ztracing-shim, a first-party no-op, and the
|
||||
# other two leave the graph with it.
|
||||
#
|
||||
# `cargo deny check licenses` already catches this, so why assert it here as
|
||||
# well? Because deny is a gate a runner can skip. scripts/ci.sh downgrades a
|
||||
# missing cargo-deny to a warning unless LUMBRIDGE_CI_STRICT=1, and that exact
|
||||
# arrangement is how the licence closure went ungated once already -- reported
|
||||
# green on a runner that had never installed the tool. This check needs no
|
||||
# tool, runs in milliseconds, and is what makes deleting the patch table a
|
||||
# failure rather than a quiet relicensing of the product.
|
||||
#
|
||||
# Asserted against Cargo.lock for the same reason as the gate above: the
|
||||
# manifest states an intent, and a `[patch]` whose URL does not match the
|
||||
# source character for character applies to nothing while still looking
|
||||
# correct in a diff. The lockfile states what would actually be compiled.
|
||||
for pkg in ztracing zlog ztracing_macro; do
|
||||
block="$(awk -v pkg="$pkg" '$0 == "name = \"" pkg "\""{found=1} found{print} found&&/^$/{exit}' Cargo.lock)"
|
||||
[ -n "$block" ] || continue
|
||||
actual_source="$(printf '%s' "$block" | sed -n 's/^source = "\(.*\)"$/\1/p')"
|
||||
case "$actual_source" in
|
||||
"")
|
||||
# No source line: a path package, which is the patched shim. Correct.
|
||||
;;
|
||||
*)
|
||||
echo "workspace-guard: $pkg resolves to $actual_source, not the local shim." >&2
|
||||
echo " That crate is GPL-3.0-or-later and Lumbridge is Apache-2.0." >&2
|
||||
echo " The [patch] table in Cargo.toml is missing, misspelled, or" >&2
|
||||
echo " no longer matches the source it is meant to replace." >&2
|
||||
echo " See crates/lumbridge-ztracing-shim/src/lib.rs." >&2
|
||||
status=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ! grep -qF '[patch."https://github.com/zed-industries/zed.git"]' Cargo.toml; then
|
||||
echo "workspace-guard: the Zed [patch] table is gone from Cargo.toml." >&2
|
||||
echo " Without it gpui compiles GPL-3.0-or-later ztracing." >&2
|
||||
status=1
|
||||
fi
|
||||
|
||||
if [ "$status" = 0 ]; then
|
||||
echo "workspace-guard: crate membership and the pinned UI dependency are as recorded."
|
||||
echo "workspace-guard: crate membership, the pinned UI dependency, and the GPL patch are as recorded."
|
||||
fi
|
||||
exit "$status"
|
||||
|
||||
Reference in New Issue
Block a user