1
1
use std:: path:: PathBuf ;
2
+ #[ cfg( feature = "offline" ) ]
3
+ use std:: sync:: { Arc , Mutex } ;
2
4
3
5
use once_cell:: sync:: Lazy ;
4
6
use proc_macro2:: TokenStream ;
@@ -30,7 +32,38 @@ struct Metadata {
30
32
#[ cfg( feature = "offline" ) ]
31
33
target_dir : PathBuf ,
32
34
#[ 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
+ }
34
67
}
35
68
36
69
// 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(|| {
71
104
72
105
let database_url = env ( "DATABASE_URL" ) . ok ( ) ;
73
106
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
-
99
107
Metadata {
100
108
manifest_dir,
101
109
offline,
102
110
database_url,
103
111
#[ cfg( feature = "offline" ) ]
104
112
target_dir,
105
113
#[ cfg( feature = "offline" ) ]
106
- workspace_root,
114
+ workspace_root : Arc :: new ( Mutex :: new ( None ) ) ,
107
115
}
108
116
} ) ;
109
117
@@ -118,18 +126,20 @@ pub fn expand_input(input: QueryMacroInput) -> crate::Result<TokenStream> {
118
126
#[ cfg( feature = "offline" ) ]
119
127
_ => {
120
128
let data_file_path = METADATA . manifest_dir . join ( "sqlx-data.json" ) ;
121
- let workspace_data_file_path = METADATA . workspace_root . join ( "sqlx-data.json" ) ;
122
129
123
130
if data_file_path. exists ( ) {
124
131
expand_from_file ( input, data_file_path)
125
- } else if workspace_data_file_path. exists ( ) {
126
- expand_from_file ( input, workspace_data_file_path)
127
132
} 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 \
130
139
and sqlx-data.json must exist, to use query macros"
131
- . into ( ) ,
132
- )
140
+ . into ( ) ,
141
+ )
142
+ }
133
143
}
134
144
}
135
145
0 commit comments