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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Changelog

- **Added** `vp run --json` prints every package and task in the workspace, with each task's `dependsOn` resolved to task IDs, as one JSON document for scripts, editors and coding agents. It runs nothing and, like `vp run` without a task, loads every package's config. It prints the same document from any directory in the workspace: indented in a terminal, on one line when captured. Its `$schema` field points to a JSON Schema that describes each field, which `vp run` writes to the system temp directory ([#948](https://github.com/voidzero-dev/vite-task/pull/948)).
- **Fixed** On Linux, where every user shares the temp folder `/tmp`, the helper files `vp run` writes there, such as the library that tracks file accesses, now go in a folder only the current user can write to, like `/tmp/fspy-1000`. Before, they went in a folder such as `/tmp/fspy` that belonged to whoever ran `vp run` first: running a different version as another user failed, and the same version used files that user could replace ([#947](https://github.com/voidzero-dev/vite-task/pull/947)).
- **Fixed** On macOS, task commands that use `sh` or `bash` now behave as they do on Linux in four cases. A `while read` loop with a redirect under `set -e` no longer exits the script. An `EXIT` trap now sees the exit status in `$?`, and a bare `exit` in the trap keeps that status, so a failed task is no longer reported as successful. `$BASH` is now set when the command runs as `bash`. The bundled shell is updated to an Oils build from master that has these fixes ([#939](https://github.com/voidzero-dev/vite-task/pull/939)).
- **Changed** `vp run` now loads a package's `vite.config.*` only when the run reaches one of that package's tasks; the workspace root's config still always loads. A run in one package no longer waits for every package's config to load, and a broken config in another package no longer fails it. Runs that reach that package, such as `vp run -r build` or a task whose `dependsOn` names one of its tasks, still fail with the config's error, and `vp run` without a task, which lists every task, still loads every config ([#944](https://github.com/voidzero-dev/vite-task/pull/944)).
Expand Down
46 changes: 46 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ reqwest = { version = "0.13.5", default-features = false }
rusqlite = "0.39.0"
rustc-hash = "2.1.1"
rustls = { version = "0.23.44", default-features = false }
schemars = "1.2.3"
# SeccompAction::UserNotif (SECCOMP_RET_USER_NOTIF) was added after the latest published release (v0.5.0)
seccompiler = { git = "https://github.com/rust-vmm/seccompiler", rev = "08587106340b8e3cb361c7561411510039436857" }
serde = "1.0.219"
Expand Down
4 changes: 3 additions & 1 deletion crates/fspy_seccomp_unotify/src/supervisor/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ macro_rules! impl_handler {
}
fn handle_notify(&mut self, notify: &::libc::seccomp_notif) -> ::std::io::Result<()> {
$crate::supervisor::handler::arg::Caller::with_pid(notify.pid as _, |caller| {
// The cast names its type: with `as _`, any `PartialEq<T> for c_int` impl in
// the dependency graph, such as serde_json's, makes the comparison ambiguous.
$(
$(#[$attr])?
if notify.data.nr == $crate::supervisor::handler::Sysno::$syscall as _ {
if notify.data.nr == $crate::supervisor::handler::Sysno::$syscall as ::libc::c_int {
return self.$syscall(caller, $crate::supervisor::handler::arg::FromNotify::from_notify(notify)?)
}
)*
Expand Down
5 changes: 5 additions & 0 deletions crates/vt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ anstream = { workspace = true }
anyhow = { workspace = true }
async-trait = { workspace = true }
bytes = { workspace = true }
cow-utils = { workspace = true }
wincode = { workspace = true, features = ["derive"] }
clap = { workspace = true, features = ["derive"] }
ctrlc = { workspace = true }
Expand Down Expand Up @@ -67,7 +68,11 @@ wax = { workspace = true }
zstd = { workspace = true }

[dev-dependencies]
# `preserve_order` keeps the schema's properties in declaration order, as the document prints them.
schemars = { workspace = true, features = ["preserve_order"] }
tempfile = { workspace = true }
vt_snapshot_test = { workspace = true }
vt_str = { workspace = true, features = ["schemars"] }

[target.'cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))'.dependencies]
fspy = { workspace = true }
Expand Down
4 changes: 4 additions & 0 deletions crates/vt/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ fn main() {
println!("cargo::rustc-check-cfg=cfg(fspy)");
println!("cargo::rerun-if-changed=build.rs");

// The JSON Schema that `vp run --json` output points to, embedded with `artifact!`.
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
println!("cargo::rustc-env=VT_TASK_GRAPH_SCHEMA={manifest_dir}/schemas/task-graph.json");

let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
if matches!(target_os.as_str(), "windows" | "macos" | "linux") {
println!("cargo::rustc-cfg=fspy");
Expand Down
119 changes: 119 additions & 0 deletions crates/vt/schemas/task-graph.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "TaskGraph",
"description": "Every package and task in the workspace, and how the tasks depend on each other, as printed by `vp run --json`.",
"type": "object",
"properties": {
"$schema": {
"description": "`file://` URL of the JSON Schema that describes this document.",
"type": "string"
},
"version": {
"description": "Format version. It changes only for a breaking change: a rename, a removal, or a changed meaning. New fields and values don't change it; ignore fields you don't know.",
"type": "integer",
"const": 1
},
"workspaceRoot": {
"description": "Absolute path of the workspace root. Other paths are relative to it, with `/` on every platform.",
"type": "string"
},
"packages": {
"description": "Every package in the workspace, keyed by path (`\".\"` for the root), even ones without tasks.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/Package"
}
},
"tasks": {
"description": "Every task, keyed by task ID: `<package path>#<task name>`, e.g. `packages/ui#build`, or just the task name for a task of the root package. In each part, `%` is written `%25` and `#` is written `%23`. Compare IDs; don't decode them.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/Task"
}
}
},
"required": [
"$schema",
"version",
"workspaceRoot",
"packages",
"tasks"
],
"definitions": {
"Package": {
"description": "A package in the workspace.",
"type": "object",
"properties": {
"name": {
"description": "The name in `package.json`. Absent when the package has none.",
"type": "string"
},
"dependencies": {
"description": "The other workspace packages in `dependencies` in `package.json`, by path. Packages from outside the workspace aren't listed. Absent when there are none.",
"type": "array",
"items": {
"type": "string"
}
},
"devDependencies": {
"description": "The other workspace packages in `devDependencies` in `package.json`, by path. Packages from outside the workspace aren't listed. Absent when there are none.",
"type": "array",
"items": {
"type": "string"
}
},
"peerDependencies": {
"description": "The other workspace packages in `peerDependencies` in `package.json`, by path. Packages from outside the workspace aren't listed. Absent when there are none.",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"Task": {
"description": "A task.",
"type": "object",
"properties": {
"package": {
"description": "The path of the task's package, which is also its key in `packages`.",
"type": "string"
},
"name": {
"description": "The task name, from `vite.config.*` or a `package.json` script.",
"type": "string"
},
"cwd": {
"description": "The directory the command runs in, when the task's `cwd` setting changes it. It is absolute when it's outside the workspace.",
"type": "string"
},
"command": {
"description": "The command as the task defines it.",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"dependsOn": {
"description": "The tasks in the task's own `dependsOn`, by ID. An entry such as `{ task: 'build', from: 'dependencies' }` is replaced by the tasks it selects. Absent when there are none.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"package",
"name",
"command"
]
}
}
}
13 changes: 13 additions & 0 deletions crates/vt/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ pub struct RunCommand {
#[clap(long, exclusive = true)]
pub(crate) last_details: bool,

/// Print every package and task in the workspace as JSON, and run nothing.
#[clap(long, exclusive = true)]
pub(crate) json: bool,

#[clap(
allow_hyphen_values = true,
value_names = ["TASK_SPECIFIER", "ADDITIONAL_ARGS"],
Expand Down Expand Up @@ -165,6 +169,7 @@ impl Command {
pub(crate) fn into_resolved(self) -> ResolvedCommand {
match self {
Self::Run(run) if run.last_details => ResolvedCommand::RunLastDetails,
Self::Run(run) if run.json => ResolvedCommand::TaskGraphJson,
Self::Run(run) => ResolvedCommand::Run(run.into_resolved()),
Self::Cache { subcmd } => ResolvedCommand::Cache { subcmd },
}
Expand All @@ -186,6 +191,8 @@ pub enum ResolvedCommand {
Run(ResolvedRunCommand),
/// Display the saved detailed summary of the last run (`--last-details`).
RunLastDetails,
/// Print the task graph as JSON (`--json` without a task).
TaskGraphJson,
/// Manage the task cache.
Cache { subcmd: CacheSubcommand },
}
Expand All @@ -206,6 +213,12 @@ pub struct ResolvedRunCommand {
}

impl RunCommand {
/// Whether `--json` is set, asking for the task graph as JSON instead of a run.
#[must_use]
pub const fn is_task_graph_json(&self) -> bool {
self.json
}

/// Convert to the resolved run command, stripping the `last_details` flag.
///
/// Splits `task_and_args` into `task_specifier` (the first element) and
Expand Down
Loading
Loading