Skip to content

Commit a39ea99

Browse files
committed
Generate environment variables doc
1 parent 9a8ff85 commit a39ea99

File tree

12 files changed

+291
-153
lines changed

12 files changed

+291
-153
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ serde_json = { version = "1.0.128" }
147147
sha2 = { version = "0.10.8" }
148148
smallvec = { version = "1.13.2" }
149149
spdx = { version = "0.10.6" }
150-
syn = { version = "2.0.77" }
150+
syn = { version = "2.0.77", features = ["full"] }
151151
sys-info = { version = "0.9.1" }
152152
target-lexicon = { version = "0.12.16" }
153153
tempfile = { version = "3.12.0" }

crates/uv-dev/src/generate_cli_reference.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ const SHOW_HIDDEN_COMMANDS: &[&str] = &["generate-shell-completion"];
3131

3232
#[derive(clap::Args)]
3333
pub(crate) struct Args {
34-
/// Write the generated output to stdout (rather than to `settings.md`).
3534
#[arg(long, default_value_t, value_enum)]
3635
pub(crate) mode: Mode,
3736
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//! Generate the environment variables reference from `uv_static::EnvVars`.
2+
3+
use anyhow::bail;
4+
use pretty_assertions::StrComparison;
5+
use std::path::PathBuf;
6+
7+
use uv_static::EnvVars;
8+
9+
use crate::generate_all::Mode;
10+
use crate::ROOT_DIR;
11+
12+
#[derive(clap::Args)]
13+
pub(crate) struct Args {
14+
#[arg(long, default_value_t, value_enum)]
15+
mode: Mode,
16+
}
17+
18+
pub(crate) fn main(args: &Args) -> anyhow::Result<()> {
19+
let reference_string = generate();
20+
let filename = "environment.md";
21+
let reference_path = PathBuf::from(ROOT_DIR)
22+
.join("docs")
23+
.join("configuration")
24+
.join(filename);
25+
26+
match args.mode {
27+
Mode::DryRun => {
28+
anstream::println!("{reference_string}");
29+
}
30+
Mode::Check => match fs_err::read_to_string(reference_path) {
31+
Ok(current) => {
32+
if current == reference_string {
33+
anstream::println!("Up-to-date: {filename}");
34+
} else {
35+
let comparison = StrComparison::new(&current, &reference_string);
36+
bail!("{filename} changed, please run `cargo dev generate-env-vars-reference`:\n{comparison}");
37+
}
38+
}
39+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
40+
bail!("{filename} not found, please run `cargo dev generate-env-vars-reference`");
41+
}
42+
Err(err) => {
43+
bail!(
44+
"{filename} changed, please run `cargo dev generate-env-vars-reference`:\n{err}"
45+
);
46+
}
47+
},
48+
Mode::Write => match fs_err::read_to_string(&reference_path) {
49+
Ok(current) => {
50+
if current == reference_string {
51+
anstream::println!("Up-to-date: {filename}");
52+
} else {
53+
anstream::println!("Updating: {filename}");
54+
fs_err::write(reference_path, reference_string.as_bytes())?;
55+
}
56+
}
57+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
58+
anstream::println!("Updating: {filename}");
59+
fs_err::write(reference_path, reference_string.as_bytes())?;
60+
}
61+
Err(err) => {
62+
bail!("{filename} changed, please run `cargo dev generate-env-vars-reference`:\n{err}");
63+
}
64+
},
65+
}
66+
67+
Ok(())
68+
}
69+
70+
fn generate() -> String {
71+
let mut output = String::new();
72+
73+
output.push_str("# Environment variables\n\n");
74+
output
75+
.push_str("uv accepts the following command-line arguments as environment variables:\n\n");
76+
77+
for (var, doc) in EnvVars::constants() {
78+
output.push_str(&format!("- `{var}`: {doc}\n"));
79+
}
80+
81+
output
82+
}
83+
84+
#[cfg(test)]
85+
mod tests;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use std::env;
2+
3+
use anyhow::Result;
4+
5+
use uv_static::EnvVars;
6+
7+
use crate::generate_all::Mode;
8+
9+
use super::{main, Args};
10+
11+
#[test]
12+
fn test_generate_env_vars_reference() -> Result<()> {
13+
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
14+
Mode::Write
15+
} else {
16+
Mode::Check
17+
};
18+
main(&Args { mode })
19+
}

crates/uv-dev/src/generate_json_schema.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ struct CombinedOptions {
2727

2828
#[derive(clap::Args)]
2929
pub(crate) struct Args {
30-
/// Write the generated output to stdout (rather than to `uv.schema.json`).
3130
#[arg(long, default_value_t, value_enum)]
3231
pub(crate) mode: Mode,
3332
}

crates/uv-dev/src/generate_options_reference.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ struct CombinedOptions {
3434

3535
#[derive(clap::Args)]
3636
pub(crate) struct Args {
37-
/// Write the generated output to stdout (rather than to `settings.md`).
3837
#[arg(long, default_value_t, value_enum)]
3938
pub(crate) mode: Mode,
4039
}

crates/uv-dev/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::clear_compile::ClearCompileArgs;
2020
use crate::compile::CompileArgs;
2121
use crate::generate_all::Args as GenerateAllArgs;
2222
use crate::generate_cli_reference::Args as GenerateCliReferenceArgs;
23+
use crate::generate_env_vars_reference::Args as GenerateEnvVarsReferenceArgs;
2324
use crate::generate_json_schema::Args as GenerateJsonSchemaArgs;
2425
use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs;
2526
#[cfg(feature = "render")]
@@ -31,6 +32,7 @@ mod clear_compile;
3132
mod compile;
3233
mod generate_all;
3334
mod generate_cli_reference;
35+
mod generate_env_vars_reference;
3436
mod generate_json_schema;
3537
mod generate_options_reference;
3638
mod render_benchmarks;
@@ -54,6 +56,8 @@ enum Cli {
5456
GenerateOptionsReference(GenerateOptionsReferenceArgs),
5557
/// Generate the CLI reference for the documentation.
5658
GenerateCliReference(GenerateCliReferenceArgs),
59+
/// Generate the environment variables reference for the documentation.
60+
GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs),
5761
#[cfg(feature = "render")]
5862
/// Render the benchmarks.
5963
RenderBenchmarks(RenderBenchmarksArgs),
@@ -70,6 +74,7 @@ async fn run() -> Result<()> {
7074
Cli::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
7175
Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?,
7276
Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?,
77+
Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?,
7378
#[cfg(feature = "render")]
7479
Cli::RenderBenchmarks(args) => render_benchmarks::render_benchmarks(&args)?,
7580
}

crates/uv-macros/src/lib.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ mod options_metadata;
22

33
use proc_macro::TokenStream;
44
use quote::quote;
5-
use syn::{parse_macro_input, DeriveInput};
5+
use syn::{parse_macro_input, Attribute, DeriveInput, ImplItem, ItemImpl};
66

77
#[proc_macro_derive(OptionsMetadata, attributes(option, doc, option_group))]
88
pub fn derive_options_metadata(input: TokenStream) -> TokenStream {
@@ -49,3 +49,56 @@ fn impl_combine(ast: &DeriveInput) -> TokenStream {
4949
};
5050
gen.into()
5151
}
52+
53+
fn get_doc_comment(attr: &Attribute) -> Option<String> {
54+
if attr.path().is_ident("doc") {
55+
if let syn::Meta::NameValue(meta) = &attr.meta {
56+
if let syn::Expr::Lit(expr) = &meta.value {
57+
if let syn::Lit::Str(str) = &expr.lit {
58+
return Some(str.value().trim().to_string());
59+
}
60+
}
61+
}
62+
}
63+
None
64+
}
65+
66+
#[proc_macro_attribute]
67+
pub fn collect_constants(_attr: TokenStream, input: TokenStream) -> TokenStream {
68+
let ast = parse_macro_input!(input as ItemImpl);
69+
70+
let constants: Vec<_> = ast
71+
.items
72+
.iter()
73+
.filter_map(|item| {
74+
match item {
75+
ImplItem::Const(item) => {
76+
let name = item.ident.to_string();
77+
let doc = item.attrs.iter().find_map(get_doc_comment).expect("Missing doc comment");
78+
Some((name, doc))
79+
}
80+
_ => None,
81+
}
82+
})
83+
.collect();
84+
85+
let struct_name = &ast.self_ty;
86+
let pairs = constants.iter().map(|(name, doc)| {
87+
quote! {
88+
(#name, #doc)
89+
}
90+
});
91+
92+
let expanded = quote! {
93+
#ast
94+
95+
impl #struct_name {
96+
/// Returns a list of pairs of constants and their documentation defined in this impl block.
97+
pub fn constants<'a>() -> &'a [(&'static str, &'static str)] {
98+
&[#(#pairs),*]
99+
}
100+
}
101+
};
102+
103+
expanded.into()
104+
}

crates/uv-static/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ doctest = false
1616
workspace = true
1717

1818
[dependencies]
19+
uv-macros = { workspace = true }

crates/uv-static/src/env_vars.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
use uv_macros::collect_constants;
2+
13
/// Declares all environment variable used throughout `uv` and its crates.
24
pub struct EnvVars;
35

6+
#[collect_constants]
47
impl EnvVars {
58
/// Equivalent to the `--default-index` argument. Base index URL for searching packages.
69
pub const UV_DEFAULT_INDEX: &'static str = "UV_DEFAULT_INDEX";

0 commit comments

Comments
 (0)