Skip to content

Commit 89ee690

Browse files
authored
Don't require cargo to build offline queries (#1415)
In particular building with bazel and cargo-raze doesn't imply having cargo at all, and deferring the lookup allows same-crate builds to succeed with no change to semantics. Fixes #1414 Signed-off-by: Robert Collins <[email protected]>
1 parent d94c081 commit 89ee690

File tree

1 file changed

+44
-34
lines changed

1 file changed

+44
-34
lines changed

sqlx-macros/src/query/mod.rs

+44-34
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::path::PathBuf;
2+
#[cfg(feature = "offline")]
3+
use std::sync::{Arc, Mutex};
24

35
use once_cell::sync::Lazy;
46
use proc_macro2::TokenStream;
@@ -30,7 +32,38 @@ struct Metadata {
3032
#[cfg(feature = "offline")]
3133
target_dir: PathBuf,
3234
#[cfg(feature = "offline")]
33-
workspace_root: PathBuf,
35+
workspace_root: Arc<Mutex<Option<PathBuf>>>,
36+
}
37+
38+
#[cfg(feature = "offline")]
39+
impl Metadata {
40+
pub fn workspace_root(&self) -> PathBuf {
41+
let mut root = self.workspace_root.lock().unwrap();
42+
if root.is_none() {
43+
use serde::Deserialize;
44+
use std::process::Command;
45+
46+
let cargo = env("CARGO").expect("`CARGO` must be set");
47+
48+
let output = Command::new(&cargo)
49+
.args(&["metadata", "--format-version=1"])
50+
.current_dir(&self.manifest_dir)
51+
.env_remove("__CARGO_FIX_PLZ")
52+
.output()
53+
.expect("Could not fetch metadata");
54+
55+
#[derive(Deserialize)]
56+
struct CargoMetadata {
57+
workspace_root: PathBuf,
58+
}
59+
60+
let metadata: CargoMetadata =
61+
serde_json::from_slice(&output.stdout).expect("Invalid `cargo metadata` output");
62+
63+
*root = Some(metadata.workspace_root);
64+
}
65+
root.clone().unwrap()
66+
}
3467
}
3568

3669
// If we are in a workspace, lookup `workspace_root` since `CARGO_MANIFEST_DIR` won't
@@ -71,39 +104,14 @@ static METADATA: Lazy<Metadata> = Lazy::new(|| {
71104

72105
let database_url = env("DATABASE_URL").ok();
73106

74-
#[cfg(feature = "offline")]
75-
let workspace_root = {
76-
use serde::Deserialize;
77-
use std::process::Command;
78-
79-
let cargo = env("CARGO").expect("`CARGO` must be set");
80-
81-
let output = Command::new(&cargo)
82-
.args(&["metadata", "--format-version=1"])
83-
.current_dir(&manifest_dir)
84-
.env_remove("__CARGO_FIX_PLZ")
85-
.output()
86-
.expect("Could not fetch metadata");
87-
88-
#[derive(Deserialize)]
89-
struct CargoMetadata {
90-
workspace_root: PathBuf,
91-
}
92-
93-
let metadata: CargoMetadata =
94-
serde_json::from_slice(&output.stdout).expect("Invalid `cargo metadata` output");
95-
96-
metadata.workspace_root
97-
};
98-
99107
Metadata {
100108
manifest_dir,
101109
offline,
102110
database_url,
103111
#[cfg(feature = "offline")]
104112
target_dir,
105113
#[cfg(feature = "offline")]
106-
workspace_root,
114+
workspace_root: Arc::new(Mutex::new(None)),
107115
}
108116
});
109117

@@ -118,18 +126,20 @@ pub fn expand_input(input: QueryMacroInput) -> crate::Result<TokenStream> {
118126
#[cfg(feature = "offline")]
119127
_ => {
120128
let data_file_path = METADATA.manifest_dir.join("sqlx-data.json");
121-
let workspace_data_file_path = METADATA.workspace_root.join("sqlx-data.json");
122129

123130
if data_file_path.exists() {
124131
expand_from_file(input, data_file_path)
125-
} else if workspace_data_file_path.exists() {
126-
expand_from_file(input, workspace_data_file_path)
127132
} else {
128-
Err(
129-
"`DATABASE_URL` must be set, or `cargo sqlx prepare` must have been run \
133+
let workspace_data_file_path = METADATA.workspace_root().join("sqlx-data.json");
134+
if workspace_data_file_path.exists() {
135+
expand_from_file(input, workspace_data_file_path)
136+
} else {
137+
Err(
138+
"`DATABASE_URL` must be set, or `cargo sqlx prepare` must have been run \
130139
and sqlx-data.json must exist, to use query macros"
131-
.into(),
132-
)
140+
.into(),
141+
)
142+
}
133143
}
134144
}
135145

0 commit comments

Comments
 (0)