diff --git a/README.md b/README.md index 9ece287..21b4ebd 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ This cache is automatically keyed by: available), - the following values, if `add-rust-environment-hash-key` is `"true"`: - the value of some compiler-specific environment variables (eg. RUSTFLAGS, etc), and - - a hash of all `Cargo.lock` / `Cargo.toml` files found anywhere in the repository (if present). + - a hash of the workspace's `Cargo.lock` and of the `Cargo.toml` of the workspace root and every workspace member (if present). - a hash of all `rust-toolchain` / `rust-toolchain.toml` files in the root of the repository (if present). - a hash of all `.cargo/config.toml` files in the root of the repository (if present). diff --git a/dist/cache-BzPKClMA.js b/dist/cache-BaeW9gVW.js similarity index 99% rename from dist/cache-BzPKClMA.js rename to dist/cache-BaeW9gVW.js index 9c7a3dc..98c32e1 100644 --- a/dist/cache-BzPKClMA.js +++ b/dist/cache-BaeW9gVW.js @@ -1,4 +1,4 @@ -import { x as commonjsGlobal, y as requireTunnel, z as getDefaultExportFromCjs, A as getAugmentedNamespace } from './cleanup-e3M0pm4f.js'; +import { x as commonjsGlobal, y as requireTunnel, z as getDefaultExportFromCjs, A as getAugmentedNamespace } from './cleanup-DYJDrBaf.js'; import os__default from 'os'; import crypto__default from 'crypto'; import fs__default from 'fs'; diff --git a/dist/cache-Dl81DHPs.js b/dist/cache-DoD2J4WY.js similarity index 99% rename from dist/cache-Dl81DHPs.js rename to dist/cache-DoD2J4WY.js index f7efb8f..d2f1532 100644 --- a/dist/cache-Dl81DHPs.js +++ b/dist/cache-DoD2J4WY.js @@ -1,4 +1,4 @@ -import { f as debug, m as mkdirP, n as create, l as exec, w as which, o as warning, i as info, H as HttpCodes, p as HttpClientError, q as HttpClient, t as isDebug, u as setSecret, B as BearerCredentialHandler, v as rmRF, e as error } from './cleanup-e3M0pm4f.js'; +import { f as debug, m as mkdirP, n as create, l as exec, w as which, o as warning, i as info, H as HttpCodes, p as HttpClientError, q as HttpClient, t as isDebug, u as setSecret, B as BearerCredentialHandler, v as rmRF, e as error } from './cleanup-DYJDrBaf.js'; import * as path from 'path'; import * as crypto from 'crypto'; import * as fs from 'fs'; diff --git a/dist/cleanup-e3M0pm4f.js b/dist/cleanup-DYJDrBaf.js similarity index 99% rename from dist/cleanup-e3M0pm4f.js rename to dist/cleanup-DYJDrBaf.js index d7406fd..486168f 100644 --- a/dist/cleanup-e3M0pm4f.js +++ b/dist/cleanup-DYJDrBaf.js @@ -34972,10 +34972,10 @@ async function getCacheProvider() { let cache; switch (cacheProvider) { case "github": - cache = await import('./cache-Dl81DHPs.js'); + cache = await import('./cache-DoD2J4WY.js'); break; case "warpbuild": - cache = await import('./cache-BzPKClMA.js').then(function (n) { return n.c; }); + cache = await import('./cache-BaeW9gVW.js').then(function (n) { return n.c; }); break; default: throw new Error(`The \`cache-provider\` \`${cacheProvider}\` is not valid.`); @@ -35006,6 +35006,7 @@ class Workspace { async getPackages(cmdFormat, filter, extraArgs) { const cmd = "cargo metadata --all-features --format-version 1" + (extraArgs ? ` ${extraArgs}` : ""); let packages = []; + let workspaceRoot = this.root; try { debug(`collecting metadata for "${this.root}"`); const meta = JSON.parse(await getCmdOutput(cmdFormat, cmd, { @@ -35013,6 +35014,7 @@ class Workspace { env: { ...process.env, CARGO_ENCODED_RUSTFLAGS: "" }, })); debug(`workspace "${this.root}" has ${meta.packages.length} packages`); + workspaceRoot = meta.workspace_root; for (const pkg of meta.packages.filter(filter)) { const targets = pkg.targets.filter((t) => t.kind.some((kind) => SAVE_TARGETS.has(kind))).map((t) => t.name); packages.push({ name: pkg.name, version: pkg.version, targets, path: path__default.dirname(pkg.manifest_path) }); @@ -35021,13 +35023,16 @@ class Workspace { catch (err) { console.error(err); } - return packages; + return { packages, workspaceRoot }; } async getPackagesOutsideWorkspaceRoot(cmdFormat) { - return await this.getPackages(cmdFormat, (pkg) => !pkg.manifest_path.startsWith(this.root)); + const filter = (pkg) => !pkg.manifest_path.startsWith(this.root); + return (await this.getPackages(cmdFormat, filter)).packages; } + /** The workspace's members, and the root directory of the cargo workspace they belong to. */ async getWorkspaceMembers(cmdFormat) { - return await this.getPackages(cmdFormat, (_) => true, "--no-deps"); + const { packages, workspaceRoot } = await this.getPackages(cmdFormat, (_) => true, "--no-deps"); + return { members: packages, workspaceRoot }; } } @@ -35155,9 +35160,15 @@ class CacheConfig { for (const workspace of workspaces) { const root = workspace.root; keyFiles.push(...(await globFiles(`${root}/**/.cargo/config.toml\n${root}/**/rust-toolchain\n${root}/**/rust-toolchain.toml`))); - const workspaceMembers = await workspace.getWorkspaceMembers(cmdFormat); - const cargo_manifests = sort_and_uniq(workspaceMembers.map((member) => path__default.join(member.path, "Cargo.toml"))); - for (const cargo_manifest of cargo_manifests) { + const { members, workspaceRoot } = await workspace.getWorkspaceMembers(cmdFormat); + const cargo_manifests = members.map((member) => path__default.join(member.path, "Cargo.toml")); + // A virtual workspace's root manifest belongs to no member, yet its `[profile]` and `[patch]` + // sections apply to every member. + const root_manifest = path__default.join(workspaceRoot, "Cargo.toml"); + if (await exists(root_manifest)) { + cargo_manifests.push(root_manifest); + } + for (const cargo_manifest of sort_and_uniq(cargo_manifests)) { try { const content = await fs$1.readFile(cargo_manifest, { encoding: "utf8" }); // Use any since TomlPrimitive is not exposed @@ -35168,12 +35179,16 @@ class CacheConfig { pack["version"] = "0.0.0"; } } - for (const prefix of ["", "build-", "dev-"]) { - const section_name = `${prefix}dependencies`; - if (!(section_name in parsed)) { + const workspace_table = parsed.workspace ?? {}; + if ("package" in workspace_table && "version" in workspace_table.package) { + workspace_table.package["version"] = "0.0.0"; + } + const dependency_tables = ["", "build-", "dev-"].map((prefix) => parsed[`${prefix}dependencies`]); + dependency_tables.push(workspace_table.dependencies); + for (const deps of dependency_tables) { + if (deps === undefined) { continue; } - const deps = parsed[section_name]; for (const key of Object.keys(deps)) { const dep = deps[key]; try { @@ -35198,7 +35213,7 @@ class CacheConfig { keyFiles.push(cargo_manifest); } } - const cargo_lock = path__default.join(workspace.root, "Cargo.lock"); + const cargo_lock = path__default.join(workspaceRoot, "Cargo.lock"); if (await exists(cargo_lock)) { try { const content = await fs$1.readFile(cargo_lock, { encoding: "utf8" }); diff --git a/dist/restore.js b/dist/restore.js index fe64211..5a77ed8 100644 --- a/dist/restore.js +++ b/dist/restore.js @@ -1,4 +1,4 @@ -import { e as error, g as getCacheProvider, a as getInput, b as exportVariable, C as CacheConfig, i as info, c as cleanTargetDir, r as reportError, s as setOutput } from './cleanup-e3M0pm4f.js'; +import { e as error, g as getCacheProvider, a as getInput, b as exportVariable, C as CacheConfig, i as info, c as cleanTargetDir, r as reportError, s as setOutput } from './cleanup-DYJDrBaf.js'; import 'os'; import 'crypto'; import 'fs'; diff --git a/dist/save.js b/dist/save.js index 3a8c8e5..fcebd7d 100644 --- a/dist/save.js +++ b/dist/save.js @@ -1,4 +1,4 @@ -import { e as error, g as getCacheProvider, a as getInput, d as isCacheUpToDate, i as info, C as CacheConfig, c as cleanTargetDir, f as debug, h as cleanRegistry, j as cleanBin, k as cleanGit, r as reportError, l as exec } from './cleanup-e3M0pm4f.js'; +import { e as error, g as getCacheProvider, a as getInput, d as isCacheUpToDate, i as info, C as CacheConfig, c as cleanTargetDir, f as debug, h as cleanRegistry, j as cleanBin, k as cleanGit, r as reportError, l as exec } from './cleanup-DYJDrBaf.js'; import 'os'; import 'crypto'; import 'fs'; @@ -63,8 +63,8 @@ async function run() { for (const workspace of config.workspaces) { const packages = await workspace.getPackagesOutsideWorkspaceRoot(config.cmdFormat); if (workspaceCrates === "true") { - const wsMembers = await workspace.getWorkspaceMembers(config.cmdFormat); - packages.push(...wsMembers); + const { members } = await workspace.getWorkspaceMembers(config.cmdFormat); + packages.push(...members); } allPackages.push(...packages); try { diff --git a/src/config.ts b/src/config.ts index 67633b9..78499d4 100644 --- a/src/config.ts +++ b/src/config.ts @@ -167,11 +167,17 @@ export class CacheConfig { )), ); - const workspaceMembers = await workspace.getWorkspaceMembers(cmdFormat); + const { members, workspaceRoot } = await workspace.getWorkspaceMembers(cmdFormat); - const cargo_manifests = sort_and_uniq(workspaceMembers.map((member) => path.join(member.path, "Cargo.toml"))); + const cargo_manifests = members.map((member) => path.join(member.path, "Cargo.toml")); + // A virtual workspace's root manifest belongs to no member, yet its `[profile]` and `[patch]` + // sections apply to every member. + const root_manifest = path.join(workspaceRoot, "Cargo.toml"); + if (await exists(root_manifest)) { + cargo_manifests.push(root_manifest); + } - for (const cargo_manifest of cargo_manifests) { + for (const cargo_manifest of sort_and_uniq(cargo_manifests)) { try { const content = await fs.readFile(cargo_manifest, { encoding: "utf8" }); // Use any since TomlPrimitive is not exposed @@ -184,12 +190,17 @@ export class CacheConfig { } } - for (const prefix of ["", "build-", "dev-"]) { - const section_name = `${prefix}dependencies`; - if (!(section_name in parsed)) { + const workspace_table = parsed.workspace ?? {}; + if ("package" in workspace_table && "version" in workspace_table.package) { + workspace_table.package["version"] = "0.0.0"; + } + + const dependency_tables = ["", "build-", "dev-"].map((prefix) => parsed[`${prefix}dependencies`]); + dependency_tables.push(workspace_table.dependencies); + for (const deps of dependency_tables) { + if (deps === undefined) { continue; } - const deps = parsed[section_name]; for (const key of Object.keys(deps)) { const dep = deps[key]; @@ -217,7 +228,7 @@ export class CacheConfig { } } - const cargo_lock = path.join(workspace.root, "Cargo.lock"); + const cargo_lock = path.join(workspaceRoot, "Cargo.lock"); if (await exists(cargo_lock)) { try { const content = await fs.readFile(cargo_lock, { encoding: "utf8" }); diff --git a/src/save.ts b/src/save.ts index 4d4cdc3..dae4a27 100644 --- a/src/save.ts +++ b/src/save.ts @@ -41,8 +41,8 @@ async function run() { for (const workspace of config.workspaces) { const packages = await workspace.getPackagesOutsideWorkspaceRoot(config.cmdFormat); if (workspaceCrates === "true") { - const wsMembers = await workspace.getWorkspaceMembers(config.cmdFormat); - packages.push(...wsMembers); + const { members } = await workspace.getWorkspaceMembers(config.cmdFormat); + packages.push(...members); } allPackages.push(...packages); try { diff --git a/src/workspace.ts b/src/workspace.ts index 434957d..8216d36 100644 --- a/src/workspace.ts +++ b/src/workspace.ts @@ -15,9 +15,10 @@ export class Workspace { cmdFormat: string, filter: (p: Meta["packages"][0]) => boolean, extraArgs?: string, - ): Promise { + ): Promise<{ packages: Packages; workspaceRoot: string }> { const cmd = "cargo metadata --all-features --format-version 1" + (extraArgs ? ` ${extraArgs}` : ""); let packages: Packages = []; + let workspaceRoot = this.root; try { core.debug(`collecting metadata for "${this.root}"`); const meta: Meta = JSON.parse( @@ -27,6 +28,7 @@ export class Workspace { }), ); core.debug(`workspace "${this.root}" has ${meta.packages.length} packages`); + workspaceRoot = meta.workspace_root; for (const pkg of meta.packages.filter(filter)) { const targets = pkg.targets.filter((t) => t.kind.some((kind) => SAVE_TARGETS.has(kind))).map((t) => t.name); packages.push({ name: pkg.name, version: pkg.version, targets, path: path.dirname(pkg.manifest_path) }); @@ -34,15 +36,18 @@ export class Workspace { } catch (err) { console.error(err); } - return packages; + return { packages, workspaceRoot }; } public async getPackagesOutsideWorkspaceRoot(cmdFormat: string): Promise { - return await this.getPackages(cmdFormat, (pkg) => !pkg.manifest_path.startsWith(this.root)); + const filter = (pkg: Meta["packages"][0]) => !pkg.manifest_path.startsWith(this.root); + return (await this.getPackages(cmdFormat, filter)).packages; } - public async getWorkspaceMembers(cmdFormat: string): Promise { - return await this.getPackages(cmdFormat, (_) => true, "--no-deps"); + /** The workspace's members, and the root directory of the cargo workspace they belong to. */ + public async getWorkspaceMembers(cmdFormat: string): Promise<{ members: Packages; workspaceRoot: string }> { + const { packages, workspaceRoot } = await this.getPackages(cmdFormat, (_) => true, "--no-deps"); + return { members: packages, workspaceRoot }; } } @@ -56,6 +61,7 @@ export interface PackageDefinition { export type Packages = Array; interface Meta { + workspace_root: string; packages: Array<{ name: string; version: string;