Skip to content

Commit 151eeee

Browse files
authored
Add support for running rust-cache commands from within a Nix shell (#290)
1 parent 779680d commit 151eeee

File tree

10 files changed

+167
-43
lines changed

10 files changed

+167
-43
lines changed

.github/workflows/nix.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: nix
2+
3+
on: [push, pull_request]
4+
5+
permissions: {}
6+
7+
jobs:
8+
nix:
9+
if: github.repository == 'Swatinem/rust-cache'
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
os: [ubuntu-latest, macos-latest]
14+
15+
name: Test Nix on ${{ matrix.os }}
16+
runs-on: ${{ matrix.os }}
17+
18+
steps:
19+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
20+
with:
21+
persist-credentials: false
22+
23+
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31.8.4
24+
25+
- uses: ./
26+
with:
27+
workspaces: tests
28+
cmd-format: nix develop ./tests -c {0}
29+
30+
- run: |
31+
nix develop -c cargo check
32+
nix develop -c cargo test
33+
working-directory: tests

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ sensible defaults.
9999
# Determines whether to cache the ~/.cargo/bin directory.
100100
# default: "true"
101101
cache-bin: ""
102+
103+
# A format string used to format commands to be run, i.e. `rustc` and `cargo`.
104+
# Must contain exactly one occurance of `{0}`, which is the formatting fragment
105+
# that will be replaced with the `rustc` or `cargo` command. This is necessary
106+
# when using Nix or other setup that requires running these commands within a
107+
# specific shell, otherwise the system `rustc` and `cargo` will be run.
108+
# default: "{0}"
109+
cmd-format: ""
110+
# To run within a Nix shell (using the default dev shell of a flake in the repo root):
111+
cmd-format: nix develop -c {0}
102112
```
103113
104114
Further examples are available in the [.github/workflows](./.github/workflows/) directory.

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ inputs:
6060
description: "Check if a cache entry exists without downloading the cache"
6161
required: false
6262
default: "false"
63+
cmd-format:
64+
description: "A format string used to format commands to be run, i.e. `rustc` and `cargo`."
65+
required: false
66+
default: "{0}"
6367
outputs:
6468
cache-hit:
6569
description: "A boolean value that indicates an exact match was found."

dist/restore/index.js

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150675,11 +150675,12 @@ function reportError(e) {
150675150675
lib_core.error(`${e.stack}`);
150676150676
}
150677150677
}
150678-
async function getCmdOutput(cmd, args = [], options = {}) {
150678+
async function getCmdOutput(cmdFormat, cmd, options = {}) {
150679+
cmd = cmdFormat.replace("{0}", cmd);
150679150680
let stdout = "";
150680150681
let stderr = "";
150681150682
try {
150682-
await exec.exec(cmd, args, {
150683+
await exec.exec(cmd, [], {
150683150684
silent: true,
150684150685
listeners: {
150685150686
stdout(data) {
@@ -150694,7 +150695,7 @@ async function getCmdOutput(cmd, args = [], options = {}) {
150694150695
}
150695150696
catch (e) {
150696150697
e.commandFailed = {
150697-
command: `${cmd} ${args.join(" ")}`,
150698+
command: cmd,
150698150699
stderr,
150699150700
};
150700150701
throw e;
@@ -150742,11 +150743,12 @@ class Workspace {
150742150743
this.root = root;
150743150744
this.target = target;
150744150745
}
150745-
async getPackages(filter, ...extraArgs) {
150746+
async getPackages(cmdFormat, filter, extraArgs) {
150747+
const cmd = "cargo metadata --all-features --format-version 1" + (extraArgs ? ` ${extraArgs}` : "");
150746150748
let packages = [];
150747150749
try {
150748150750
lib_core.debug(`collecting metadata for "${this.root}"`);
150749-
const meta = JSON.parse(await getCmdOutput("cargo", ["metadata", "--all-features", "--format-version", "1", ...extraArgs], {
150751+
const meta = JSON.parse(await getCmdOutput(cmdFormat, cmd, {
150750150752
cwd: this.root,
150751150753
env: { ...process.env, "CARGO_ENCODED_RUSTFLAGS": "" },
150752150754
}));
@@ -150761,11 +150763,11 @@ class Workspace {
150761150763
}
150762150764
return packages;
150763150765
}
150764-
async getPackagesOutsideWorkspaceRoot() {
150765-
return await this.getPackages((pkg) => !pkg.manifest_path.startsWith(this.root));
150766+
async getPackagesOutsideWorkspaceRoot(cmdFormat) {
150767+
return await this.getPackages(cmdFormat, (pkg) => !pkg.manifest_path.startsWith(this.root));
150766150768
}
150767-
async getWorkspaceMembers() {
150768-
return await this.getPackages((_) => true, "--no-deps");
150769+
async getWorkspaceMembers(cmdFormat) {
150770+
return await this.getPackages(cmdFormat, (_) => true, "--no-deps");
150769150771
}
150770150772
}
150771150773

@@ -150787,6 +150789,8 @@ const STATE_CONFIG = "RUST_CACHE_CONFIG";
150787150789
const HASH_LENGTH = 8;
150788150790
class CacheConfig {
150789150791
constructor() {
150792+
/** A format string for running commands */
150793+
this.cmdFormat = "";
150790150794
/** All the paths we want to cache */
150791150795
this.cachePaths = [];
150792150796
/** The primary cache key */
@@ -150815,6 +150819,17 @@ class CacheConfig {
150815150819
*/
150816150820
static async new() {
150817150821
const self = new CacheConfig();
150822+
let cmdFormat = lib_core.getInput("cmd-format");
150823+
if (cmdFormat) {
150824+
const placeholderMatches = cmdFormat.match(/\{0\}/g);
150825+
if (!placeholderMatches || placeholderMatches.length !== 1) {
150826+
cmdFormat = "{0}";
150827+
}
150828+
}
150829+
else {
150830+
cmdFormat = "{0}";
150831+
}
150832+
self.cmdFormat = cmdFormat;
150818150833
// Construct key prefix:
150819150834
// This uses either the `shared-key` input,
150820150835
// or the `key` input combined with the `job` key.
@@ -150845,7 +150860,7 @@ class CacheConfig {
150845150860
// The env vars are sorted, matched by prefix and hashed into the
150846150861
// resulting environment hash.
150847150862
let hasher = external_crypto_default().createHash("sha1");
150848-
const rustVersion = await getRustVersion();
150863+
const rustVersion = await getRustVersion(cmdFormat);
150849150864
let keyRust = `${rustVersion.release} ${rustVersion.host}`;
150850150865
hasher.update(keyRust);
150851150866
hasher.update(rustVersion["commit-hash"]);
@@ -150895,7 +150910,7 @@ class CacheConfig {
150895150910
for (const workspace of workspaces) {
150896150911
const root = workspace.root;
150897150912
keyFiles.push(...(await globFiles(`${root}/**/.cargo/config.toml\n${root}/**/rust-toolchain\n${root}/**/rust-toolchain.toml`)));
150898-
const workspaceMembers = await workspace.getWorkspaceMembers();
150913+
const workspaceMembers = await workspace.getWorkspaceMembers(cmdFormat);
150899150914
const cargo_manifests = sort_and_uniq(workspaceMembers.map((member) => external_path_default().join(member.path, "Cargo.toml")));
150900150915
for (const cargo_manifest of cargo_manifests) {
150901150916
try {
@@ -151071,8 +151086,8 @@ function isCacheUpToDate() {
151071151086
function digest(hasher) {
151072151087
return hasher.digest("hex").substring(0, HASH_LENGTH);
151073151088
}
151074-
async function getRustVersion() {
151075-
const stdout = await getCmdOutput("rustc", ["-vV"]);
151089+
async function getRustVersion(cmdFormat) {
151090+
const stdout = await getCmdOutput(cmdFormat, "rustc -vV");
151076151091
let splits = stdout
151077151092
.split(/[\n\r]+/)
151078151093
.filter(Boolean)

dist/save/index.js

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -150675,11 +150675,12 @@ function reportError(e) {
150675150675
core.error(`${e.stack}`);
150676150676
}
150677150677
}
150678-
async function getCmdOutput(cmd, args = [], options = {}) {
150678+
async function getCmdOutput(cmdFormat, cmd, options = {}) {
150679+
cmd = cmdFormat.replace("{0}", cmd);
150679150680
let stdout = "";
150680150681
let stderr = "";
150681150682
try {
150682-
await exec.exec(cmd, args, {
150683+
await exec.exec(cmd, [], {
150683150684
silent: true,
150684150685
listeners: {
150685150686
stdout(data) {
@@ -150694,7 +150695,7 @@ async function getCmdOutput(cmd, args = [], options = {}) {
150694150695
}
150695150696
catch (e) {
150696150697
e.commandFailed = {
150697-
command: `${cmd} ${args.join(" ")}`,
150698+
command: cmd,
150698150699
stderr,
150699150700
};
150700150701
throw e;
@@ -150742,11 +150743,12 @@ class Workspace {
150742150743
this.root = root;
150743150744
this.target = target;
150744150745
}
150745-
async getPackages(filter, ...extraArgs) {
150746+
async getPackages(cmdFormat, filter, extraArgs) {
150747+
const cmd = "cargo metadata --all-features --format-version 1" + (extraArgs ? ` ${extraArgs}` : "");
150746150748
let packages = [];
150747150749
try {
150748150750
core.debug(`collecting metadata for "${this.root}"`);
150749-
const meta = JSON.parse(await getCmdOutput("cargo", ["metadata", "--all-features", "--format-version", "1", ...extraArgs], {
150751+
const meta = JSON.parse(await getCmdOutput(cmdFormat, cmd, {
150750150752
cwd: this.root,
150751150753
env: { ...process.env, "CARGO_ENCODED_RUSTFLAGS": "" },
150752150754
}));
@@ -150761,11 +150763,11 @@ class Workspace {
150761150763
}
150762150764
return packages;
150763150765
}
150764-
async getPackagesOutsideWorkspaceRoot() {
150765-
return await this.getPackages((pkg) => !pkg.manifest_path.startsWith(this.root));
150766+
async getPackagesOutsideWorkspaceRoot(cmdFormat) {
150767+
return await this.getPackages(cmdFormat, (pkg) => !pkg.manifest_path.startsWith(this.root));
150766150768
}
150767-
async getWorkspaceMembers() {
150768-
return await this.getPackages((_) => true, "--no-deps");
150769+
async getWorkspaceMembers(cmdFormat) {
150770+
return await this.getPackages(cmdFormat, (_) => true, "--no-deps");
150769150771
}
150770150772
}
150771150773

@@ -150787,6 +150789,8 @@ const STATE_CONFIG = "RUST_CACHE_CONFIG";
150787150789
const HASH_LENGTH = 8;
150788150790
class CacheConfig {
150789150791
constructor() {
150792+
/** A format string for running commands */
150793+
this.cmdFormat = "";
150790150794
/** All the paths we want to cache */
150791150795
this.cachePaths = [];
150792150796
/** The primary cache key */
@@ -150815,6 +150819,17 @@ class CacheConfig {
150815150819
*/
150816150820
static async new() {
150817150821
const self = new CacheConfig();
150822+
let cmdFormat = core.getInput("cmd-format");
150823+
if (cmdFormat) {
150824+
const placeholderMatches = cmdFormat.match(/\{0\}/g);
150825+
if (!placeholderMatches || placeholderMatches.length !== 1) {
150826+
cmdFormat = "{0}";
150827+
}
150828+
}
150829+
else {
150830+
cmdFormat = "{0}";
150831+
}
150832+
self.cmdFormat = cmdFormat;
150818150833
// Construct key prefix:
150819150834
// This uses either the `shared-key` input,
150820150835
// or the `key` input combined with the `job` key.
@@ -150845,7 +150860,7 @@ class CacheConfig {
150845150860
// The env vars are sorted, matched by prefix and hashed into the
150846150861
// resulting environment hash.
150847150862
let hasher = external_crypto_default().createHash("sha1");
150848-
const rustVersion = await getRustVersion();
150863+
const rustVersion = await getRustVersion(cmdFormat);
150849150864
let keyRust = `${rustVersion.release} ${rustVersion.host}`;
150850150865
hasher.update(keyRust);
150851150866
hasher.update(rustVersion["commit-hash"]);
@@ -150895,7 +150910,7 @@ class CacheConfig {
150895150910
for (const workspace of workspaces) {
150896150911
const root = workspace.root;
150897150912
keyFiles.push(...(await globFiles(`${root}/**/.cargo/config.toml\n${root}/**/rust-toolchain\n${root}/**/rust-toolchain.toml`)));
150898-
const workspaceMembers = await workspace.getWorkspaceMembers();
150913+
const workspaceMembers = await workspace.getWorkspaceMembers(cmdFormat);
150899150914
const cargo_manifests = sort_and_uniq(workspaceMembers.map((member) => external_path_default().join(member.path, "Cargo.toml")));
150900150915
for (const cargo_manifest of cargo_manifests) {
150901150916
try {
@@ -151071,8 +151086,8 @@ function isCacheUpToDate() {
151071151086
function digest(hasher) {
151072151087
return hasher.digest("hex").substring(0, HASH_LENGTH);
151073151088
}
151074-
async function getRustVersion() {
151075-
const stdout = await getCmdOutput("rustc", ["-vV"]);
151089+
async function getRustVersion(cmdFormat) {
151090+
const stdout = await getCmdOutput(cmdFormat, "rustc -vV");
151076151091
let splits = stdout
151077151092
.split(/[\n\r]+/)
151078151093
.filter(Boolean)
@@ -151428,9 +151443,9 @@ async function run() {
151428151443
const workspaceCrates = core.getInput("cache-workspace-crates").toLowerCase() || "false";
151429151444
const allPackages = [];
151430151445
for (const workspace of config.workspaces) {
151431-
const packages = await workspace.getPackagesOutsideWorkspaceRoot();
151446+
const packages = await workspace.getPackagesOutsideWorkspaceRoot(config.cmdFormat);
151432151447
if (workspaceCrates === "true") {
151433-
const wsMembers = await workspace.getWorkspaceMembers();
151448+
const wsMembers = await workspace.getWorkspaceMembers(config.cmdFormat);
151434151449
packages.push(...wsMembers);
151435151450
}
151436151451
allPackages.push(...packages);

src/config.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ const STATE_CONFIG = "RUST_CACHE_CONFIG";
1818
const HASH_LENGTH = 8;
1919

2020
export class CacheConfig {
21+
/** A format string for running commands */
22+
public cmdFormat: string = "";
23+
2124
/** All the paths we want to cache */
2225
public cachePaths: Array<string> = [];
2326
/** The primary cache key */
@@ -53,6 +56,17 @@ export class CacheConfig {
5356
static async new(): Promise<CacheConfig> {
5457
const self = new CacheConfig();
5558

59+
let cmdFormat = core.getInput("cmd-format");
60+
if (cmdFormat) {
61+
const placeholderMatches = cmdFormat.match(/\{0\}/g);
62+
if (!placeholderMatches || placeholderMatches.length !== 1) {
63+
cmdFormat = "{0}";
64+
}
65+
} else {
66+
cmdFormat = "{0}";
67+
}
68+
self.cmdFormat = cmdFormat;
69+
5670
// Construct key prefix:
5771
// This uses either the `shared-key` input,
5872
// or the `key` input combined with the `job` key.
@@ -89,7 +103,7 @@ export class CacheConfig {
89103
// resulting environment hash.
90104

91105
let hasher = crypto.createHash("sha1");
92-
const rustVersion = await getRustVersion();
106+
const rustVersion = await getRustVersion(cmdFormat);
93107

94108
let keyRust = `${rustVersion.release} ${rustVersion.host}`;
95109
hasher.update(keyRust);
@@ -158,7 +172,7 @@ export class CacheConfig {
158172
)),
159173
);
160174

161-
const workspaceMembers = await workspace.getWorkspaceMembers();
175+
const workspaceMembers = await workspace.getWorkspaceMembers(cmdFormat);
162176

163177
const cargo_manifests = sort_and_uniq(workspaceMembers.map((member) => path.join(member.path, "Cargo.toml")));
164178

@@ -366,8 +380,8 @@ interface RustVersion {
366380
"commit-hash": string;
367381
}
368382

369-
async function getRustVersion(): Promise<RustVersion> {
370-
const stdout = await getCmdOutput("rustc", ["-vV"]);
383+
async function getRustVersion(cmdFormat: string): Promise<RustVersion> {
384+
const stdout = await getCmdOutput(cmdFormat, "rustc -vV");
371385
let splits = stdout
372386
.split(/[\n\r]+/)
373387
.filter(Boolean)

src/save.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ async function run() {
3939
const workspaceCrates = core.getInput("cache-workspace-crates").toLowerCase() || "false";
4040
const allPackages = [];
4141
for (const workspace of config.workspaces) {
42-
const packages = await workspace.getPackagesOutsideWorkspaceRoot();
42+
const packages = await workspace.getPackagesOutsideWorkspaceRoot(config.cmdFormat);
4343
if (workspaceCrates === "true") {
44-
const wsMembers = await workspace.getWorkspaceMembers();
44+
const wsMembers = await workspace.getWorkspaceMembers(config.cmdFormat);
4545
packages.push(...wsMembers);
4646
}
4747
allPackages.push(...packages);

src/utils.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ export function reportError(e: any) {
1616
}
1717

1818
export async function getCmdOutput(
19+
cmdFormat: string,
1920
cmd: string,
20-
args: Array<string> = [],
2121
options: exec.ExecOptions = {},
2222
): Promise<string> {
23+
cmd = cmdFormat.replace("{0}", cmd);
2324
let stdout = "";
2425
let stderr = "";
2526
try {
26-
await exec.exec(cmd, args, {
27+
await exec.exec(cmd, [], {
2728
silent: true,
2829
listeners: {
2930
stdout(data) {
@@ -37,7 +38,7 @@ export async function getCmdOutput(
3738
});
3839
} catch (e) {
3940
(e as any).commandFailed = {
40-
command: `${cmd} ${args.join(" ")}`,
41+
command: cmd,
4142
stderr,
4243
};
4344
throw e;

0 commit comments

Comments
 (0)