-
Notifications
You must be signed in to change notification settings - Fork 259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API View] Generate API Report in JSON #2019
Draft
HarshaNalluru
wants to merge
11
commits into
Azure:main
Choose a base branch
from
HarshaNalluru:harshan/apiview
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
d49e23f
temp-project and rust parser init
HarshaNalluru 53a7c85
generates structs, enums and functions without errors
HarshaNalluru 54d9eb3
block for function too
HarshaNalluru 8a13098
all serializable items
HarshaNalluru fc05796
start from rustdoc output
HarshaNalluru 55b71a0
temp-project to test
HarshaNalluru 605e3e7
Azure Rust API Exporter
HarshaNalluru 8cbad9f
structured generate_api_report tool
HarshaNalluru 177ae9f
--package flag
HarshaNalluru 7461436
derive example
HarshaNalluru 5708d5c
.rust.json
HarshaNalluru File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "generate_api_report" | ||
authors = ["Microsoft"] | ||
edition = "2021" | ||
license = "MIT" | ||
repository = "https://github.com/azure/azure-sdk-for-rust" | ||
rust-version = "1.80" | ||
|
||
[dependencies] | ||
serde = { version = "1.0", features = ["derive"] } | ||
serde_json = "1.0" | ||
|
||
[workspace] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Azure Rust API Exporter | ||
|
||
## Generate API Report | ||
|
||
This tool generates a JSON report of the API documentation for a specified Rust package. | ||
It uses the following command `cargo +nightly rustdoc -Z unstable-options --output-format json --package {package_name} --all-features` to generate the documentation in JSON format, processes the JSON to remove unnecessary attributes, and outputs a cleaned-up version of the JSON. | ||
|
||
## Usage | ||
|
||
To run the tool, navigate to the root of the `azure-sdk-for-rust` repository and use the following command: | ||
|
||
```sh | ||
cargo run --manifest-path eng/tools/generate_api_report/Cargo.toml -- --package package_name | ||
``` | ||
|
||
Generates `package_name.rust.json` in the `target/doc/` directory, adjacent to the rustdoc JSON (`package_name.json`) output. | ||
|
||
For example, to generate the report for a package named `docs`, run: | ||
|
||
```bash | ||
cargo run --manifest-path eng/tools/generate_api_report/Cargo.toml -- --package docs | ||
``` | ||
|
||
## Functionality | ||
|
||
1. **Check for Existing JSON File**: The tool checks if the JSON documentation file for the specified package exists in the `target/doc/` directory. | ||
2. **Generate JSON Documentation**: If the file does not exist, the tool runs `cargo +nightly rustdoc ...` to generate the JSON documentation. | ||
3. **Process JSON**: The tool reads the JSON file, removes the `span` attribute from each item, and retains important attributes like `deprecation`, `inner`, `format_version`, and `paths`. | ||
4. **Output Cleaned JSON**: The tool writes the cleaned-up JSON to a new file in the doc directory with a `.rust.json` suffix. | ||
|
||
## Contributing | ||
|
||
Contributions are welcome! Please open an issue or submit a pull request with your changes. | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use std::env; | ||
use std::fs::File; | ||
use std::io::prelude::*; | ||
use std::path::Path; | ||
use std::error::Error; | ||
use std::process::Command; | ||
use crate::models::Crate; | ||
|
||
mod models; | ||
|
||
fn main() -> Result<(), Box<dyn Error>> { | ||
// Get the package name from command-line arguments | ||
let args: Vec<String> = env::args().collect(); | ||
if args.len() != 3 || args[1] != "--package" { | ||
eprintln!("Usage: {} --package <package_name>", args[0]); | ||
std::process::exit(1); | ||
} | ||
let package_name = &args[2]; | ||
let path_str = format!("./target/doc/{}.json", package_name); | ||
let path = Path::new(&path_str); | ||
|
||
// Call cargo +nightly rustdoc to generate the JSON file | ||
let output = Command::new("cargo") | ||
.arg("+nightly") | ||
.arg("rustdoc") | ||
.arg("-Z") | ||
.arg("unstable-options") | ||
.arg("--output-format") | ||
.arg("json") | ||
.arg("--package") | ||
.arg(package_name) | ||
.arg("--all-features") | ||
.output()?; | ||
|
||
if !output.status.success() { | ||
eprintln!("Failed to generate JSON file: {}", String::from_utf8_lossy(&output.stderr)); | ||
std::process::exit(1); | ||
} | ||
|
||
let mut file = File::open(path)?; | ||
let mut contents = String::new(); | ||
file.read_to_string(&mut contents)?; | ||
|
||
// -------- Prettifying package_name.json - starts ----- | ||
// Parse the JSON to ensure it's valid | ||
let json_value: serde_json::Value = serde_json::from_str(&contents)?; | ||
|
||
// Write the pretty-printed JSON back to the file | ||
let mut file = File::create(path)?; | ||
serde_json::to_writer_pretty(&mut file, &json_value)?; | ||
// -------- Prettifying package_name.json - ends ----- | ||
|
||
let mut root: Crate = serde_json::from_str(&contents)?; | ||
|
||
// Remove the span attribute from each item | ||
for item in root.index.values_mut() { | ||
item.span = None; | ||
} | ||
|
||
let output_path_str = format!("./target/doc/{}.rust.json", package_name); | ||
let output_path = Path::new(&output_path_str); | ||
let mut output_file = File::create(output_path)?; | ||
serde_json::to_writer_pretty(&mut output_file, &root)?; | ||
|
||
println!("File has been generated at: {}", output_path_str); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use serde::{Deserialize, Serialize}; | ||
use serde_json::Value; | ||
use std::collections::HashMap; | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct Item { | ||
pub id: u32, | ||
pub crate_id: u32, | ||
pub name: Option<String>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub span: Option<Value>, | ||
pub visibility: Value, | ||
pub docs: Option<String>, | ||
pub links: HashMap<String, Value>, | ||
pub attrs: Vec<String>, | ||
pub deprecation: Value, | ||
pub inner: Value, | ||
} | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct Crate { | ||
pub root: u32, | ||
pub crate_version: Option<String>, | ||
pub index: HashMap<String, Item>, | ||
pub paths: HashMap<String, Value>, | ||
pub external_crates: Value, | ||
pub format_version: u32 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "docs" | ||
version = "0.1.0" | ||
authors.workspace = true | ||
edition.workspace = true | ||
license.workspace = true | ||
repository.workspace = true | ||
rust-version.workspace = true | ||
|
||
[dependencies] | ||
|
||
[lints] | ||
workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
pub mod module_example; | ||
|
||
/// This is a sample module | ||
pub mod sample_module { | ||
/// This is a sample function | ||
pub fn sample_function() { | ||
// function implementation | ||
} | ||
|
||
/// This is a sample struct | ||
pub struct SampleStruct { | ||
/// This is a sample field | ||
pub field: i32, | ||
} | ||
|
||
/// This is a sample struct | ||
#[derive(Debug)] | ||
pub struct SampleStructWithDebug { | ||
/// This is a sample field | ||
pub field: i32, | ||
} | ||
} | ||
|
||
#[allow(dead_code)] | ||
static GLOBAL_FIELD1: i32 = 0; | ||
|
||
pub trait MyTrait { | ||
// Define some methods or associated functions here | ||
fn example_method(&self); | ||
} | ||
|
||
pub fn foo<T: MyTrait, V: MyTrait>(v: &T) { | ||
// function implementation | ||
todo!() | ||
} | ||
|
||
pub fn bar<T, V>(v: &T) | ||
where | ||
T: MyTrait, | ||
V: MyTrait, | ||
{ | ||
// function implementation | ||
todo!() | ||
} | ||
|
||
pub static GLOBAL_FIELD2: &(dyn MyTrait + Sync) = &DummyTrait; | ||
struct DummyTrait; | ||
|
||
unsafe impl Sync for DummyTrait {} | ||
|
||
impl MyTrait for DummyTrait { | ||
fn example_method(&self) { | ||
// method implementation | ||
} | ||
} | ||
|
||
// ...existing code... | ||
|
||
/// This is a sample struct that implements Clone | ||
#[derive(Debug, Clone)] | ||
pub struct SampleStructWithClone { | ||
/// This is a sample field | ||
pub field: i32, | ||
} | ||
|
||
impl MyTrait for SampleStructWithClone { | ||
fn example_method(&self) { | ||
// method implementation | ||
println!("Example method called on SampleStructWithClone with field: {}", self.field); | ||
} | ||
} | ||
|
||
// Example usage of the Clone implementation | ||
pub fn clone_example() { | ||
let original = SampleStructWithClone { field: 42 }; | ||
let cloned = original.clone(); | ||
println!("Original: {:?}", original); | ||
println!("Cloned: {:?}", cloned); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/// This is a sample module | ||
pub mod sample_module2 { | ||
/// This is a sample function | ||
pub fn sample_function2() { | ||
// function implementation | ||
} | ||
|
||
/// This is a sample struct | ||
pub struct SampleStruct2 { | ||
// Define the fields of the struct | ||
pub field1: String, | ||
pub field2: i32, | ||
} | ||
} | ||
|
||
// Example function that constructs and uses SampleStruct2 | ||
pub fn use_sample_struct2() { | ||
let instance = sample_module2::SampleStruct2 { | ||
field1: String::from("example"), | ||
field2: 42, | ||
}; | ||
|
||
// Use the instance in some way | ||
println!("SampleStruct2: field1 = {}, field2 = {}", instance.field1, instance.field2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
pub mod lease; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want this part of the main workspace. We should put this under
eng/tools
which can have a separate workspace, if even needed there.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now. This is for a "template" project. We could use what @hallipr wants as well, which I plan to basically be Key Vault Secrets anyway, which is what most other languages use for their "template" projects.