Skip to content

Commit

Permalink
Generate environment variables doc
Browse files Browse the repository at this point in the history
  • Loading branch information
j178 committed Oct 23, 2024
1 parent 9a8ff85 commit 870896b
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 153 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ serde_json = { version = "1.0.128" }
sha2 = { version = "0.10.8" }
smallvec = { version = "1.13.2" }
spdx = { version = "0.10.6" }
syn = { version = "2.0.77" }
syn = { version = "2.0.77", features = ["full"] }
sys-info = { version = "0.9.1" }
target-lexicon = { version = "0.12.16" }
tempfile = { version = "3.12.0" }
Expand Down
1 change: 0 additions & 1 deletion crates/uv-dev/src/generate_cli_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const SHOW_HIDDEN_COMMANDS: &[&str] = &["generate-shell-completion"];

#[derive(clap::Args)]
pub(crate) struct Args {
/// Write the generated output to stdout (rather than to `settings.md`).
#[arg(long, default_value_t, value_enum)]
pub(crate) mode: Mode,
}
Expand Down
85 changes: 85 additions & 0 deletions crates/uv-dev/src/generate_env_vars_reference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//! Generate the environment variables reference from `uv_static::EnvVars`.

use anyhow::bail;
use pretty_assertions::StrComparison;
use std::path::PathBuf;

use uv_static::EnvVars;

use crate::generate_all::Mode;
use crate::ROOT_DIR;

#[derive(clap::Args)]
pub(crate) struct Args {
#[arg(long, default_value_t, value_enum)]
mode: Mode,
}

pub(crate) fn main(args: &Args) -> anyhow::Result<()> {
let reference_string = generate();
let filename = "environment.md";
let reference_path = PathBuf::from(ROOT_DIR)
.join("docs")
.join("configuration")
.join(filename);

match args.mode {
Mode::DryRun => {
anstream::println!("{reference_string}");
}
Mode::Check => match fs_err::read_to_string(reference_path) {
Ok(current) => {
if current == reference_string {
anstream::println!("Up-to-date: {filename}");
} else {
let comparison = StrComparison::new(&current, &reference_string);
bail!("{filename} changed, please run `cargo dev generate-env-vars-reference`:\n{comparison}");
}
}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
bail!("{filename} not found, please run `cargo dev generate-env-vars-reference`");
}
Err(err) => {
bail!(
"{filename} changed, please run `cargo dev generate-env-vars-reference`:\n{err}"
);
}
},
Mode::Write => match fs_err::read_to_string(&reference_path) {
Ok(current) => {
if current == reference_string {
anstream::println!("Up-to-date: {filename}");
} else {
anstream::println!("Updating: {filename}");
fs_err::write(reference_path, reference_string.as_bytes())?;
}
}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
anstream::println!("Updating: {filename}");
fs_err::write(reference_path, reference_string.as_bytes())?;
}
Err(err) => {
bail!("{filename} changed, please run `cargo dev generate-env-vars-reference`:\n{err}");
}
},
}

Ok(())
}

fn generate() -> String {
let mut output = String::new();

output.push_str("# Environment variables\n\n");
output
.push_str("uv accepts the following command-line arguments as environment variables:\n\n");

EnvVars::constants().iter().for_each(|(var, doc)| {
output.push_str(&format!("- `{}`: {}\n", var, doc));
});

output
}

#[cfg(test)]
mod tests;
19 changes: 19 additions & 0 deletions crates/uv-dev/src/generate_env_vars_reference/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::env;

use anyhow::Result;

use uv_static::EnvVars;

use crate::generate_all::Mode;

use super::{main, Args};

#[test]
fn test_generate_env_vars_reference() -> Result<()> {
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
Mode::Write
} else {
Mode::Check
};
main(&Args { mode })
}
1 change: 0 additions & 1 deletion crates/uv-dev/src/generate_json_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ struct CombinedOptions {

#[derive(clap::Args)]
pub(crate) struct Args {
/// Write the generated output to stdout (rather than to `uv.schema.json`).
#[arg(long, default_value_t, value_enum)]
pub(crate) mode: Mode,
}
Expand Down
1 change: 0 additions & 1 deletion crates/uv-dev/src/generate_options_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ struct CombinedOptions {

#[derive(clap::Args)]
pub(crate) struct Args {
/// Write the generated output to stdout (rather than to `settings.md`).
#[arg(long, default_value_t, value_enum)]
pub(crate) mode: Mode,
}
Expand Down
5 changes: 5 additions & 0 deletions crates/uv-dev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::clear_compile::ClearCompileArgs;
use crate::compile::CompileArgs;
use crate::generate_all::Args as GenerateAllArgs;
use crate::generate_cli_reference::Args as GenerateCliReferenceArgs;
use crate::generate_env_vars_reference::Args as GenerateEnvVarsReferenceArgs;
use crate::generate_json_schema::Args as GenerateJsonSchemaArgs;
use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs;
#[cfg(feature = "render")]
Expand All @@ -31,6 +32,7 @@ mod clear_compile;
mod compile;
mod generate_all;
mod generate_cli_reference;
mod generate_env_vars_reference;
mod generate_json_schema;
mod generate_options_reference;
mod render_benchmarks;
Expand All @@ -54,6 +56,8 @@ enum Cli {
GenerateOptionsReference(GenerateOptionsReferenceArgs),
/// Generate the CLI reference for the documentation.
GenerateCliReference(GenerateCliReferenceArgs),
/// Generate the environment variables reference for the documentation.
GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs),
#[cfg(feature = "render")]
/// Render the benchmarks.
RenderBenchmarks(RenderBenchmarksArgs),
Expand All @@ -70,6 +74,7 @@ async fn run() -> Result<()> {
Cli::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?,
Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?,
Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?,
#[cfg(feature = "render")]
Cli::RenderBenchmarks(args) => render_benchmarks::render_benchmarks(&args)?,
}
Expand Down
55 changes: 54 additions & 1 deletion crates/uv-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod options_metadata;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
use syn::{parse_macro_input, Attribute, DeriveInput, ImplItem, ItemImpl};

#[proc_macro_derive(OptionsMetadata, attributes(option, doc, option_group))]
pub fn derive_options_metadata(input: TokenStream) -> TokenStream {
Expand Down Expand Up @@ -49,3 +49,56 @@ fn impl_combine(ast: &DeriveInput) -> TokenStream {
};
gen.into()
}

fn get_doc_comment(attr: &Attribute) -> Option<String> {
if attr.path().is_ident("doc") {
if let syn::Meta::NameValue(meta) = &attr.meta {
if let syn::Expr::Lit(expr) = &meta.value {
if let syn::Lit::Str(str) = &expr.lit {
return Some(str.value().trim().to_string());
}
}
}
}
None
}

#[proc_macro_attribute]
pub fn collect_constants(_attr: TokenStream, input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as ItemImpl);

let constants: Vec<_> = ast
.items
.iter()
.filter_map(|item| {
match item {
ImplItem::Const(item) => {
let name = item.ident.to_string();
let doc = item.attrs.iter().find_map(get_doc_comment).expect("Missing doc comment");
Some((name, doc))
}
_ => None,
}
})
.collect();

let struct_name = &ast.self_ty;
let pairs = constants.iter().map(|(name, doc)| {
quote! {
(#name, #doc)
}
});

let expanded = quote! {
#ast

impl #struct_name {
/// Returns a list of pairs of constants and their documentation defined in this impl block.
pub fn constants<'a>() -> &'a [(&'static str, &'static str)] {
&[#(#pairs),*]
}
}
};

expanded.into()
}
1 change: 1 addition & 0 deletions crates/uv-static/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ doctest = false
workspace = true

[dependencies]
uv-macros = { workspace = true }
3 changes: 3 additions & 0 deletions crates/uv-static/src/env_vars.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use uv_macros::collect_constants;

/// Declares all environment variable used throughout `uv` and its crates.
pub struct EnvVars;

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

0 comments on commit 870896b

Please sign in to comment.