Skip to content

Commit 13bde6d

Browse files
author
lif
committed
Use re-exports to make depending on propolis-client less cumbersome
1 parent f449793 commit 13bde6d

25 files changed

+167
-95
lines changed

Cargo.lock

+8-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+8-25
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,6 @@ You'll need to add add the following to `Cargo.toml`:
3535
```diff
3636
[dependencies]
3737
+progenitor = { git = "https://github.com/oxidecomputer/progenitor" }
38-
+reqwest = { version = "0.11", features = ["json", "stream"] }
39-
+serde = { version = "1.0", features = ["derive"] }
40-
```
41-
42-
In addition, if the OpenAPI document contains string types with the `format`
43-
field set to `date` or `date-time`, include
44-
45-
```diff
46-
[dependencies]
47-
+chrono = { version = "0.4", features = ["serde"] }
48-
```
49-
50-
Similarly if there is a `format` field set to `uuid`:
51-
52-
```diff
53-
[dependencies]
54-
+uuid = { version = "1.0.0", features = ["serde", "v4"] }
5538
```
5639

5740
The macro has some additional fancy options to control the generated code:
@@ -108,20 +91,15 @@ You'll need to add add the following to `Cargo.toml`:
10891
```diff
10992
[dependencies]
11093
+progenitor-client = { git = "https://github.com/oxidecomputer/progenitor" }
111-
+reqwest = { version = "0.11", features = ["json", "stream"] }
112-
+serde = { version = "1.0", features = ["derive"] }
11394

11495
[build-dependencies]
11596
+progenitor = { git = "https://github.com/oxidecomputer/progenitor" }
11697
+serde_json = "1.0"
11798
```
11899

119-
(`chrono` and `uuid` as above)
120-
121100
Note that `progenitor` is used by `build.rs`, but the generated code required
122101
`progenitor-client`.
123102

124-
125103
### Static Crate
126104

127105
Progenitor can be run to emit a stand-alone crate for the generated client.
@@ -146,14 +124,14 @@ For example:
146124

147125
This will produce a package in the specified directory. The output has no
148126
persistent dependency on Progenitor including the `progenitor-client` crate.
149-
Here's a excerpt from the emitted `Cargo.toml`:
127+
Here's an excerpt from the emitted `Cargo.toml`:
150128

151129
```toml
152130
[dependencies]
153131
chrono = { version = "0.4", features = ["serde"] }
154132
futures = "0.3"
155133
percent-encoding = "2.1"
156-
reqwest = { version = "0.11", features = ["json", "stream"] }
134+
reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "6ceb23958c8b6d7f1d8ee093f0ad73184d133d40", features = ["json", "stream"] }
157135
serde = { version = "1.0", features = ["derive"] }
158136
serde_json = "1.0"
159137
uuid = { version = ">=0.8.0, <2.0.0", features = ["serde", "v4"] }
@@ -162,6 +140,11 @@ uuid = { version = ">=0.8.0, <2.0.0", features = ["serde", "v4"] }
162140
Note that there is a dependency on `percent-encoding` which macro- and
163141
build.rs-generated clients is included from `progenitor-client`.
164142

143+
Additionally, note that `chrono` is only required if the OpenAPI document
144+
contains string types with the `format` field set to `date` or `date-time`,
145+
and `uuid` is only required if there is a `format` field set to `uuid`.
146+
(Similarly, `base64` and `rand` would've been included if the API included
147+
any endpoints using the nonstandard Dropshot extension for Websockets.)
165148

166149
## Generation Styles
167150

@@ -290,4 +273,4 @@ let result = client
290273
```
291274

292275
Consumers do not need to specify parameters and struct properties that are not
293-
required or for which the API specifies defaults. Neat!
276+
required or for which the API specifies defaults. Neat!

example-macro/Cargo.toml

-5
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,5 @@ authors = ["Adam H. Leventhal <ahl@oxidecomputer.com>"]
55
edition = "2021"
66

77
[dependencies]
8-
chrono = { version = "0.4", features = ["serde"] }
98
progenitor = { path = "../progenitor" }
10-
reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "6ceb23958c8b6d7f1d8ee093f0ad73184d133d40", features = ["json", "stream"] }
11-
#reqwest = { version = "0.11", features = ["json", "stream"] }
129
schemars = { version = "0.8.10", features = ["uuid1"] }
13-
serde = { version = "1.0", features = ["derive"] }
14-
uuid = { version = "1.0", features = ["serde", "v4"] }

progenitor-client/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ bytes = "1.2.1"
1111
futures-core = "0.3.24"
1212
percent-encoding = "2.2"
1313
reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "6ceb23958c8b6d7f1d8ee093f0ad73184d133d40", features = ["json", "stream"] }
14-
#reqwest = { version = "0.11", default-features = false, features = ["json", "stream"] }
15-
serde = "1.0"
14+
chrono = { version = "0.4", features = ["serde"] }
15+
uuid = { version = "1.0.0", features = ["serde", "v4"] }
16+
serde = { version = "1.0", features = ["derive"] }
1617
serde_json = "1.0"
1718
serde_urlencoded = "0.7.1"
1819
base64 = "0.13"

progenitor-client/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ mod progenitor_client;
44

55
pub use crate::progenitor_client::*;
66

7+
pub mod deps {
8+
pub use ::base64;
9+
pub use ::chrono;
10+
pub use ::rand;
11+
pub use ::reqwest;
12+
pub use ::serde;
13+
pub use ::uuid;
14+
}
15+
716
// For stand-alone crates, rather than adding a dependency on
817
// progenitor-client, we simply dump the code right in. This means we don't
918
// need to determine the provenance of progenitor (crates.io, github, etc.)

progenitor-client/src/progenitor_client.rs

-5
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,3 @@ impl<E> RequestBuilderExt<E> for RequestBuilder {
401401
})?))
402402
}
403403
}
404-
405-
#[doc(hidden)]
406-
pub fn generate_websocket_key() -> String {
407-
base64::encode(rand::random::<[u8; 16]>())
408-
}

progenitor-impl/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ serde_json = "1.0"
2121
syn = { version = "1.0", features = ["parsing"] }
2222
thiserror = "1.0"
2323
# To publish, use a numbered version
24-
typify = "0.0.10"
25-
#typify = { git = "https://github.com/oxidecomputer/typify" }
24+
#typify = "0.0.10"
25+
typify = { git = "https://github.com/oxidecomputer/typify" }
2626
unicode-ident = "1.0.3"
2727

2828
[dev-dependencies]

progenitor-impl/src/lib.rs

+64-5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub struct Generator {
3838
type_space: TypeSpace,
3939
settings: GenerationSettings,
4040
uses_futures: bool,
41+
uses_websockets: bool,
4142
}
4243

4344
#[derive(Default, Clone)]
@@ -48,6 +49,7 @@ pub struct GenerationSettings {
4849
pre_hook: Option<TokenStream>,
4950
post_hook: Option<TokenStream>,
5051
extra_derives: Vec<String>,
52+
serde_crate_location: Option<String>,
5153
}
5254

5355
#[derive(Clone, Deserialize, PartialEq, Eq)]
@@ -108,6 +110,19 @@ impl GenerationSettings {
108110
self.extra_derives.push(derive.to_string());
109111
self
110112
}
113+
114+
pub fn with_serde_crate_location(
115+
&mut self,
116+
crate_location: impl ToString,
117+
) -> &mut Self {
118+
self.serde_crate_location = Some(crate_location.to_string());
119+
self
120+
}
121+
122+
pub fn without_serde_crate_location(&mut self) -> &mut Self {
123+
self.serde_crate_location = None;
124+
self
125+
}
111126
}
112127

113128
impl Default for Generator {
@@ -118,6 +133,7 @@ impl Default for Generator {
118133
),
119134
settings: Default::default(),
120135
uses_futures: Default::default(),
136+
uses_websockets: Default::default(),
121137
}
122138
}
123139
}
@@ -128,13 +144,17 @@ impl Generator {
128144
type_settings
129145
.with_type_mod("types")
130146
.with_struct_builder(settings.interface == InterfaceStyle::Builder);
147+
if let Some(crate_location) = &settings.serde_crate_location {
148+
type_settings.with_serde_crate_location(crate_location.to_owned());
149+
}
131150
settings.extra_derives.iter().for_each(|derive| {
132151
let _ = type_settings.with_derive(derive.clone());
133152
});
134153
Self {
135154
type_space: TypeSpace::new(&type_settings),
136155
settings: settings.clone(),
137156
uses_futures: false,
157+
uses_websockets: false,
138158
}
139159
}
140160

@@ -219,12 +239,13 @@ impl Generator {
219239
ByteStream,
220240
Error,
221241
ResponseValue,
222-
generate_websocket_key
223242
};
224243
#[allow(unused_imports)]
225244
use progenitor_client::{encode_path, RequestBuilderExt};
226245

227246
pub mod types {
247+
#[allow(unused_imports)]
248+
use super::deps::*;
228249
use serde::{Deserialize, Serialize};
229250

230251
// This may be used by some impl Deserialize, but not all.
@@ -325,8 +346,8 @@ impl Generator {
325346
use super::types;
326347
#[allow(unused_imports)]
327348
use super::{
349+
deps::*,
328350
encode_path,
329-
generate_websocket_key,
330351
ByteStream,
331352
Error,
332353
RequestBuilderExt,
@@ -363,8 +384,8 @@ impl Generator {
363384
use super::types;
364385
#[allow(unused_imports)]
365386
use super::{
387+
deps::*,
366388
encode_path,
367-
generate_websocket_key,
368389
ByteStream,
369390
Error,
370391
RequestBuilderExt,
@@ -388,9 +409,25 @@ impl Generator {
388409

389410
/// Render text output.
390411
pub fn generate_text(&mut self, spec: &OpenAPI) -> Result<String> {
412+
self.settings
413+
.with_serde_crate_location("progenitor_client::deps::serde");
391414
self.generate_text_impl(
392415
spec,
393416
rustfmt_wrapper::config::Config::default(),
417+
true,
418+
)
419+
}
420+
421+
/// Render text output without re-exports (for stand-alone crate output)
422+
pub fn generate_text_standalone(
423+
&mut self,
424+
spec: &OpenAPI,
425+
) -> Result<String> {
426+
self.settings.without_serde_crate_location();
427+
self.generate_text_impl(
428+
spec,
429+
rustfmt_wrapper::config::Config::default(),
430+
false,
394431
)
395432
}
396433

@@ -409,15 +446,33 @@ impl Generator {
409446
wrap_comments: Some(true),
410447
..Default::default()
411448
},
449+
true,
412450
)
413451
}
414452

415453
fn generate_text_impl(
416454
&mut self,
417455
spec: &OpenAPI,
418456
config: rustfmt_wrapper::config::Config,
457+
reexport: bool,
419458
) -> Result<String> {
420-
let output = self.generate_tokens(spec)?;
459+
let mut output = self.generate_tokens(spec)?;
460+
if reexport {
461+
// Add re-exports from progenitor-client such that build.rs users
462+
// don't have to maintain a matching dependency on the same reqwest
463+
// version we use.
464+
output = quote! {
465+
use progenitor_client::deps;
466+
#output
467+
};
468+
} else {
469+
// the generated output has a couple instances of (in this case
470+
// unnecessary) `use super::deps::*;` which we account for with:
471+
output = quote! {
472+
mod deps { /* this space intentionally left blank */ }
473+
#output
474+
};
475+
}
421476

422477
// Format the file with rustfmt.
423478
let content = rustfmt_wrapper::rustfmt_config(config, output).unwrap();
@@ -437,7 +492,7 @@ impl Generator {
437492
"bytes = \"1.1\"",
438493
"futures-core = \"0.3\"",
439494
"percent-encoding = \"2.1\"",
440-
"reqwest = { version = \"0.11\", features = [\"json\", \"stream\"] }",
495+
"reqwest = { git = \"https://github.com/seanmonstar/reqwest\", rev = \"6ceb23958c8b6d7f1d8ee093f0ad73184d133d40\", features = [\"json\", \"stream\"] }",
441496
"serde = { version = \"1.0\", features = [\"derive\"] }",
442497
"serde_urlencoded = \"0.7\"",
443498
];
@@ -455,6 +510,10 @@ impl Generator {
455510
if self.uses_futures {
456511
deps.push("futures = \"0.3\"")
457512
}
513+
if self.uses_websockets {
514+
deps.push("base64 = \"0.13\"");
515+
deps.push("rand = \"0.8\"");
516+
}
458517
if self.type_space.uses_serde_json() {
459518
deps.push("serde_json = \"1.0\"")
460519
}

0 commit comments

Comments
 (0)