Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ eyre = "0.6.8"
# needs real I/O (git fetch, filesystem), so it's off by default for
# `comline-core`'s wasm32 consumers (the playground editor, the language
# server); the CLI is the one consumer that actually runs `comline build`.
comline-core = { git = "https://github.com/ComlineProject/core", rev = "2be483f5adc303bd39c76e11f930ec2340eee57a", features = ["deps"] }
comline-core = { git = "https://github.com/ComlineProject/core", rev = "525939352b79538ce5e9b41ae6713ee6bd26a25e", features = ["deps"] }
# All three pinned to revs that agree on one `comline-codegen`, and bumped
# together: comline-rust and comline-typescript's codegen crates consume
# `comline-codegen`'s types, so the rev below must be byte-identical to the
# one *they* pin - Cargo only unifies a git dependency across identical rev
# strings, and two copies of `GenRequest` are two incompatible types.
comline-codegen = { git = "https://github.com/ComlineProject/generation", rev = "9b8336e4acd0a1f10b75aa851c36571f4e1d0d47" }
comline-codegen = { git = "https://github.com/ComlineProject/generation", rev = "ac4425c32f88f98a2a3bfb971a209c173c6559a8" }
# The official Markdown and HTML documentation renderers (`comline doc`),
# linked in like the official generators. Same generation rev as
# `comline-codegen`.
comline-doc-markdown = { git = "https://github.com/ComlineProject/generation", rev = "9b8336e4acd0a1f10b75aa851c36571f4e1d0d47" }
comline-doc-html = { git = "https://github.com/ComlineProject/generation", rev = "9b8336e4acd0a1f10b75aa851c36571f4e1d0d47" }
comline-codegen-rust = { git = "https://github.com/ComlineProject/comline-rust", rev = "89530a72f37180517e1c70f88437b1bedf1e703a", optional = true }
comline-codegen-typescript = { git = "https://github.com/ComlineProject/comline-typescript", rev = "82447d54a8616a1ed37e4a7886df25deb2af7baf", optional = true }
comline-doc-markdown = { git = "https://github.com/ComlineProject/generation", rev = "ac4425c32f88f98a2a3bfb971a209c173c6559a8" }
comline-doc-html = { git = "https://github.com/ComlineProject/generation", rev = "ac4425c32f88f98a2a3bfb971a209c173c6559a8" }
comline-codegen-rust = { git = "https://github.com/ComlineProject/comline-rust", rev = "8d0d659d100d41d64d203a7890a6b15471cde802", optional = true }
comline-codegen-typescript = { git = "https://github.com/ComlineProject/comline-typescript", rev = "37cd70f96260325f37a39be6a15cb858d2e069dc", optional = true }
# `comline conformance`: the conformance runner (corpus loading, judging,
# profile proofs) and its case format, a public spec. Pinned by git rev.
comline-runtime-conformance = { git = "https://github.com/ComlineProject/runtime", rev = "4378c91b74ee1ef1debc800a3daf75c874198e70" }
Expand Down
5 changes: 5 additions & 0 deletions src/changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ fn config_line(change: &ConfigChange) -> String {
"~",
format!("Changed `wire.framing`: {old} {arrow} {new}"),
),
ConfigChange::PackageIdChanged { old, new } => mark(
"🔄",
"~",
format!("Changed the package `id` (a different package): {old} {arrow} {new}"),
),
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ pub fn run(work_dir: &Path, watching: bool) -> Result<()> {

fn build_once(work_dir: &Path) -> Result<()> {
ui::step(format!("Building project{}", ui::at_path(work_dir)));
// Every package has an id (its identity for `comline@2`); one without
// gets it here, as one line in config.idp.
match comline_core::package::id::ensure_in_config(work_dir) {
Ok(Some(id)) => ui::note(format!(
"config.idp had no `id`: added `id = \"{id}\"`. Keep it when renaming the \
package, and change it in a copy"
)),
Ok(None) => {}
Err(e) => return Err(core_err("couldn't add an id to config.idp", e)),
}
let spinner = ui::spinner("compiling schemas");
let registry = generator_registry();
let mut target_warnings = Vec::new();
Expand Down
56 changes: 54 additions & 2 deletions src/commands/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::io::Write as _;
use std::path::Path;

use anstyle::{AnsiColor, Color, Style};
use comline_core::compat::{self, PackageFacts};
use comline_core::inspect::{self, Acceptance, Choice, ProtocolSummary, Source};
use miette::{IntoDiagnostic, Result};

Expand All @@ -30,9 +31,12 @@ pub fn run(work_dir: &Path, json: bool) -> Result<()> {
let context = outcome.map_err(|e| core_err("validation failed", e))?;

let protocols = inspect::protocols(&context);
// What the latest build records for `comline@2`: each protocol's line,
// shape hash and functions' "since". None before the first build.
let facts = latest_facts(work_dir);
let mut out = anstream::stdout().lock();
if json {
let report = serde_json::json!({ "protocols": protocols });
let report = serde_json::json!({ "protocols": protocols, "facts": facts });
writeln!(
out,
"{}",
Expand All @@ -48,13 +52,61 @@ pub fn run(work_dir: &Path, json: bool) -> Result<()> {
}
let text = protocols
.iter()
.map(|p| render(p, ui::plain()))
.map(|p| {
let mut text = render(p, ui::plain());
if !p.dependency {
if let Some(facts) = &facts {
text += &render_facts(
facts,
&compat::protocol_path(&p.schema, &p.name),
ui::plain(),
);
}
}
text
})
.collect::<Vec<_>>()
.join("\n");
write!(out, "{text}").into_diagnostic()?;
Ok(())
}

/// The latest build's facts, if the package was built. Read-only: the
/// store is never created here.
fn latest_facts(work_dir: &Path) -> Option<PackageFacts> {
use comline_core::package::build::cas::{main_ref, ref_exists};
if !ref_exists(work_dir, main_ref()) {
return None;
}
compat::facts(work_dir, None).ok()
}

/// A protocol's line, shape hash and functions' "since", as the latest
/// build records them. `path` is its `namespace::Protocol`: facts are kept
/// per qualified path, so two protocols of one name stay apart.
pub fn render_facts(facts: &PackageFacts, path: &str, plain: bool) -> String {
let Some(p) = facts.protocols.iter().find(|p| p.path == path) else {
return String::new();
};
let dim = |text: &str| {
if plain {
text.to_string()
} else {
format!("{DIM}{text}{DIM:#}")
}
};
let mut out = format!(
"\n {}\n",
dim(&format!("{} as of build {}", p.path, facts.version))
);
out += &format!(" {:<10} {}\n", "line", p.line);
out += &format!(" {:<10} {}\n", "shape", p.shape_hash);
for f in &p.functions {
out += &format!(" {:<10} {:<24} {}\n", "since", f.name, f.since);
}
out
}

/// One protocol: a header of choices, then a row per guarantee. Fits 80
/// columns: anything long goes on its own indented line.
pub fn render(p: &ProtocolSummary, plain: bool) -> String {
Expand Down
3 changes: 3 additions & 0 deletions src/commands/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,12 @@ fn scaffold_language() -> String {

fn config_idp(name: &str) -> String {
let language = scaffold_language();
// The package's identity: kept by a rename, changed by a copy.
let id = comline_core::package::id::config_line(&comline_core::package::id::generate());
format!(
"\
congregation {name}
{id}
specification_version = 1

code_generation = {{
Expand Down
32 changes: 32 additions & 0 deletions tests/cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,38 @@ fn freezes_an_initial_version() {
assert!(project.join(".comline").is_dir());
}

#[test]
fn adds_a_missing_id_with_a_note_and_keeps_one_there_is() {
let temp = tempfile::tempdir().unwrap();
let project = fixture_project(temp.path());
let before = std::fs::read_to_string(project.join("config.idp")).unwrap();
assert!(!before.contains("\nid = "), "{before}");

build(&project)
.success()
.stderr(predicate::str::contains("config.idp had no `id`: added"));
let after = std::fs::read_to_string(project.join("config.idp")).unwrap();
// One line added after `congregation`, nothing else touched.
let added: Vec<&str> = after
.lines()
.filter(|l| !before.lines().any(|b| b == *l))
.collect();
assert_eq!(added.len(), 1, "{after}");
assert!(
added[0].starts_with("id = \"") && added[0].len() == "id = \"\"".len() + 32,
"{after}"
);
assert_eq!(after.replace(&format!("{}\n", added[0]), ""), before);

build(&project)
.success()
.stderr(predicate::str::contains("had no `id`").not());
assert_eq!(
std::fs::read_to_string(project.join("config.idp")).unwrap(),
after
);
}

/// `fixture_project`, declaring `languages` (and anything after) instead.
fn declaring(temp: &std::path::Path, languages: &str, rest: &str) -> std::path::PathBuf {
let project = fixture_project(temp);
Expand Down
6 changes: 6 additions & 0 deletions tests/cli/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ fn scaffolds_a_buildable_project() {

let config = fs::read_to_string(root.join("config.idp")).unwrap();
assert!(config.contains("congregation my_api"));
// The package's identity, random, on the line after its name.
let id = config.lines().nth(1).unwrap();
assert!(
id.starts_with("id = \"") && id.len() == "id = \"\"".len() + 32,
"{config}"
);
assert!(config.contains("code_generation"));
// The widest promise: the Rust generator's floor.
assert!(config.contains("rust#1.85.0 = {}"), "{config}");
Expand Down
12 changes: 6 additions & 6 deletions tests/fixtures/generators/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions tests/fixtures/generators/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ publish = false
[dependencies]
# The same revs the CLI pins, so the real generator's output is comparable
# byte for byte with the CLI's built-in one.
comline-codegen = { git = "https://github.com/ComlineProject/generation", rev = "9b8336e4acd0a1f10b75aa851c36571f4e1d0d47" }
comline-doc-markdown = { git = "https://github.com/ComlineProject/generation", rev = "9b8336e4acd0a1f10b75aa851c36571f4e1d0d47" }
comline-doc-html = { git = "https://github.com/ComlineProject/generation", rev = "9b8336e4acd0a1f10b75aa851c36571f4e1d0d47" }
comline-codegen-rust = { git = "https://github.com/ComlineProject/comline-rust", rev = "89530a72f37180517e1c70f88437b1bedf1e703a" }
comline-codegen = { git = "https://github.com/ComlineProject/generation", rev = "ac4425c32f88f98a2a3bfb971a209c173c6559a8" }
comline-doc-markdown = { git = "https://github.com/ComlineProject/generation", rev = "ac4425c32f88f98a2a3bfb971a209c173c6559a8" }
comline-doc-html = { git = "https://github.com/ComlineProject/generation", rev = "ac4425c32f88f98a2a3bfb971a209c173c6559a8" }
comline-codegen-rust = { git = "https://github.com/ComlineProject/comline-rust", rev = "8d0d659d100d41d64d203a7890a6b15471cde802" }
Loading