Skip to content

Commit c6214d8

Browse files
committed
feat: add example and test suites
1 parent 5151c7b commit c6214d8

11 files changed

Lines changed: 1097 additions & 1 deletion

Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,19 @@ panic = "abort"
4242
[profile.dev]
4343
opt-level = 0
4444
debug = true
45+
46+
[[example]]
47+
name = "basic_analysis"
48+
path = "examples/basic_analysis.rs"
49+
50+
[[example]]
51+
name = "github_token_analysis"
52+
path = "examples/github_token_analysis.rs"
53+
54+
[[example]]
55+
name = "compare_repositories"
56+
path = "examples/compare_repositories.rs"
57+
58+
[[example]]
59+
name = "custom_analysis"
60+
path = "examples/custom_analysis.rs"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A fast code analysis tool for remote repositories with multi-platform support.
99

1010
## Features
1111

12-
- **Asynchronous Repository Processing**: Non-blocking HTTP client with concurrent stream processing for efficient remote repository fetching and decompression
12+
- **Asynchronous Repository Processing**: Non-blocking HTTP client with async streaming request processing for efficient remote repository fetching and decompression, optimized for **low memory usage** and **serverless environments**
1313
- **Multi-Platform URL Resolution**: Features intelligent URL parsing engine that normalizes different Git hosting platform APIs (GitHub, GitLab, Bitbucket, Codeberg) into unified archive endpoints with branch/commit resolution
1414
- **Streaming Archive Analysis**: Processes tar.gz archives directly in memory using streaming decompression without temporary file extraction, reducing I/O overhead and memory footprint
1515
- **Language Detection Engine**: Implements rule-based file extension and content analysis system supporting 150+ programming languages with configurable pattern matching and statistical computation (use tokei [languages map](https://github.com/XAMPPRocky/tokei/blob/master/languages.json))

examples/README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Examples
2+
3+
This directory contains examples demonstrating how to use the bytes-radar library.
4+
5+
## Available Examples
6+
7+
### 1. Basic Analysis (`basic_analysis.rs`)
8+
9+
Demonstrates basic usage of the RemoteAnalyzer to analyze a public repository.
10+
11+
```bash
12+
cargo run --example basic_analysis
13+
```
14+
15+
This example analyzes the bytes-radar repository itself and displays:
16+
- Project summary statistics
17+
- Language breakdown
18+
- Total lines, files, and size information
19+
20+
### 2. GitHub Token Analysis (`github_token_analysis.rs`)
21+
22+
Shows how to use GitHub authentication for private repositories.
23+
24+
```bash
25+
export GITHUB_TOKEN=your_github_token_here
26+
cargo run --example github_token_analysis
27+
```
28+
29+
Make sure to:
30+
1. Set the `GITHUB_TOKEN` environment variable
31+
2. Update the repository URL in the example to point to your private repo
32+
3. Ensure your token has access to the repository
33+
34+
### 3. Compare Repositories (`compare_repositories.rs`)
35+
36+
Compares multiple repositories and ranks them by various metrics.
37+
38+
```bash
39+
cargo run --example compare_repositories
40+
```
41+
42+
This example:
43+
- Analyzes multiple popular repositories
44+
- Compares them side by side
45+
- Ranks by complexity and documentation ratios
46+
- Demonstrates batch processing
47+
48+
### 4. Custom Analysis (`custom_analysis.rs`)
49+
50+
Demonstrates manual construction of project analysis without remote fetching.
51+
52+
```bash
53+
cargo run --example custom_analysis
54+
```
55+
56+
This example shows how to:
57+
- Create FileMetrics manually
58+
- Build a ProjectAnalysis step by step
59+
- Use different file categories
60+
- Display detailed file-by-file information
61+
62+
## Running All Examples
63+
64+
To run all examples in sequence:
65+
66+
```bash
67+
cargo run --example basic_analysis
68+
cargo run --example custom_analysis
69+
cargo run --example compare_repositories
70+
71+
# For github_token_analysis, set your token first:
72+
export GITHUB_TOKEN=your_token
73+
cargo run --example github_token_analysis
74+
```
75+
76+
## Notes
77+
78+
- Examples that analyze remote repositories require an internet connection
79+
- GitHub token examples require valid authentication
80+
- Some examples may take time to complete due to network requests
81+
- Adjust timeout values if you experience connection issues
82+
83+
## Customizing Examples
84+
85+
Feel free to modify these examples:
86+
- Change repository URLs to analyze your own projects
87+
- Adjust timeout values for slower connections
88+
- Add error handling for production use
89+
- Experiment with different output formats in the CLI

examples/basic_analysis.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use bytes_radar::{RemoteAnalyzer, Result};
2+
3+
#[tokio::main]
4+
async fn main() -> Result<()> {
5+
let mut analyzer = RemoteAnalyzer::new();
6+
7+
analyzer.set_timeout(60);
8+
9+
let url = "https://github.com/zmh-program/bytes-radar";
10+
11+
println!("Analyzing repository: {}", url);
12+
13+
let project_analysis = analyzer.analyze_url(url).await?;
14+
15+
let summary = project_analysis.get_summary();
16+
17+
println!("\nProject Analysis Summary:");
18+
println!("Project Name: {}", summary.project_name);
19+
println!("Total Files: {}", summary.total_files);
20+
println!("Total Lines: {}", summary.total_lines);
21+
println!("Code Lines: {}", summary.total_code_lines);
22+
println!("Comment Lines: {}", summary.total_comment_lines);
23+
println!("Blank Lines: {}", summary.total_blank_lines);
24+
println!("Total Size: {} bytes", summary.total_size_bytes);
25+
println!("Language Count: {}", summary.language_count);
26+
if let Some(primary_lang) = &summary.primary_language {
27+
println!("Primary Language: {}", primary_lang);
28+
}
29+
println!(
30+
"Complexity Ratio: {:.2}%",
31+
summary.overall_complexity_ratio * 100.0
32+
);
33+
println!(
34+
"Documentation Ratio: {:.2}%",
35+
summary.overall_documentation_ratio * 100.0
36+
);
37+
38+
println!("\nLanguage Breakdown:");
39+
let language_stats = project_analysis.get_language_statistics();
40+
for stats in language_stats {
41+
println!(
42+
" {}: {} files, {} lines",
43+
stats.language_name, stats.file_count, stats.total_lines
44+
);
45+
}
46+
47+
Ok(())
48+
}

examples/compare_repositories.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use bytes_radar::{RemoteAnalyzer, Result};
2+
use std::collections::HashMap;
3+
4+
#[tokio::main]
5+
async fn main() -> Result<()> {
6+
let repositories = vec![
7+
"https://github.com/rust-lang/rust",
8+
"https://github.com/microsoft/vscode",
9+
"https://github.com/facebook/react",
10+
"https://github.com/golang/go",
11+
];
12+
13+
let mut analyzer = RemoteAnalyzer::new();
14+
analyzer.set_timeout(180);
15+
16+
println!("Comparing {} repositories...\n", repositories.len());
17+
18+
let mut results = HashMap::new();
19+
20+
for repo in &repositories {
21+
println!("Analyzing: {}", repo);
22+
23+
match analyzer.analyze_url(repo).await {
24+
Ok(analysis) => {
25+
let summary = analysis.get_summary();
26+
results.insert(repo.to_string(), summary);
27+
println!("✓ Completed: {}", repo);
28+
}
29+
Err(e) => {
30+
eprintln!("✗ Failed {}: {}", repo, e);
31+
}
32+
}
33+
println!();
34+
}
35+
36+
if results.is_empty() {
37+
println!("No repositories were successfully analyzed.");
38+
return Ok(());
39+
}
40+
41+
println!("=== Repository Comparison ===\n");
42+
43+
println!(
44+
"{:<20} {:>10} {:>12} {:>12} {:>15}",
45+
"Repository", "Files", "Total Lines", "Code Lines", "Primary Lang"
46+
);
47+
println!("{}", "-".repeat(75));
48+
49+
for (repo, summary) in &results {
50+
let repo_name = repo.split('/').last().unwrap_or(repo);
51+
let primary_lang = summary.primary_language.as_deref().unwrap_or("Unknown");
52+
53+
println!(
54+
"{:<20} {:>10} {:>12} {:>12} {:>15}",
55+
repo_name,
56+
summary.total_files,
57+
summary.total_lines,
58+
summary.total_code_lines,
59+
primary_lang
60+
);
61+
}
62+
63+
println!("\n=== Complexity Analysis ===\n");
64+
65+
let mut complexity_ranking: Vec<_> = results.iter().collect();
66+
complexity_ranking.sort_by(|a, b| {
67+
b.1.overall_complexity_ratio
68+
.partial_cmp(&a.1.overall_complexity_ratio)
69+
.unwrap()
70+
});
71+
72+
for (i, (repo, summary)) in complexity_ranking.iter().enumerate() {
73+
let repo_name = repo.split('/').last().unwrap_or(repo);
74+
println!(
75+
"{}. {}: {:.1}% code ratio",
76+
i + 1,
77+
repo_name,
78+
summary.overall_complexity_ratio * 100.0
79+
);
80+
}
81+
82+
println!("\n=== Documentation Analysis ===\n");
83+
84+
let mut doc_ranking: Vec<_> = results.iter().collect();
85+
doc_ranking.sort_by(|a, b| {
86+
b.1.overall_documentation_ratio
87+
.partial_cmp(&a.1.overall_documentation_ratio)
88+
.unwrap()
89+
});
90+
91+
for (i, (repo, summary)) in doc_ranking.iter().enumerate() {
92+
let repo_name = repo.split('/').last().unwrap_or(repo);
93+
println!(
94+
"{}. {}: {:.1}% documentation ratio",
95+
i + 1,
96+
repo_name,
97+
summary.overall_documentation_ratio * 100.0
98+
);
99+
}
100+
101+
Ok(())
102+
}

examples/custom_analysis.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use bytes_radar::{FileCategory, FileMetrics, ProjectAnalysis, Result};
2+
3+
fn main() -> Result<()> {
4+
let mut project = ProjectAnalysis::new("my-rust-project");
5+
6+
let main_rs = FileMetrics::new("src/main.rs", "Rust".to_string(), 50, 35, 10, 5)?
7+
.with_category(FileCategory::Source)
8+
.with_size_bytes(1200);
9+
10+
let lib_rs = FileMetrics::new("src/lib.rs", "Rust".to_string(), 80, 60, 15, 5)?
11+
.with_category(FileCategory::Source)
12+
.with_size_bytes(2000);
13+
14+
let test_rs = FileMetrics::new(
15+
"tests/integration_test.rs",
16+
"Rust".to_string(),
17+
45,
18+
35,
19+
5,
20+
5,
21+
)?
22+
.with_category(FileCategory::Test)
23+
.with_size_bytes(950);
24+
25+
let readme_md = FileMetrics::new("README.md", "Markdown".to_string(), 25, 20, 0, 5)?
26+
.with_category(FileCategory::Documentation)
27+
.with_size_bytes(600);
28+
29+
let cargo_toml = FileMetrics::new("Cargo.toml", "TOML".to_string(), 15, 12, 2, 1)?
30+
.with_category(FileCategory::Configuration)
31+
.with_size_bytes(400);
32+
33+
project.add_file_metrics(main_rs)?;
34+
project.add_file_metrics(lib_rs)?;
35+
project.add_file_metrics(test_rs)?;
36+
project.add_file_metrics(readme_md)?;
37+
project.add_file_metrics(cargo_toml)?;
38+
39+
let summary = project.get_summary();
40+
41+
println!("=== Custom Project Analysis ===\n");
42+
println!("Project: {}", summary.project_name);
43+
println!("Total Files: {}", summary.total_files);
44+
println!("Total Lines: {}", summary.total_lines);
45+
println!("Code Lines: {}", summary.total_code_lines);
46+
println!("Comment Lines: {}", summary.total_comment_lines);
47+
println!("Blank Lines: {}", summary.total_blank_lines);
48+
println!("Total Size: {} bytes", summary.total_size_bytes);
49+
50+
println!("\n=== Language Breakdown ===");
51+
for stats in project.get_language_statistics() {
52+
println!("{}:", stats.language_name);
53+
println!(" Files: {}", stats.file_count);
54+
println!(" Lines: {}", stats.total_lines);
55+
println!(" Code: {}", stats.code_lines);
56+
println!(" Comments: {}", stats.comment_lines);
57+
println!(" Complexity: {:.1}%", stats.complexity_ratio * 100.0);
58+
println!(" Documentation: {:.1}%", stats.documentation_ratio * 100.0);
59+
println!();
60+
}
61+
62+
println!("=== File Details ===");
63+
for (lang_name, lang_analysis) in &project.language_analyses {
64+
println!("{}:", lang_name);
65+
for file in &lang_analysis.file_metrics {
66+
println!(
67+
" {} ({:?}): {} lines, {} bytes",
68+
file.file_path, file.category, file.total_lines, file.size_bytes
69+
);
70+
}
71+
println!();
72+
}
73+
74+
Ok(())
75+
}

examples/github_token_analysis.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use bytes_radar::{RemoteAnalyzer, Result};
2+
use std::env;
3+
4+
#[tokio::main]
5+
async fn main() -> Result<()> {
6+
let github_token =
7+
env::var("GITHUB_TOKEN").expect("Please set GITHUB_TOKEN environment variable");
8+
9+
let mut analyzer = RemoteAnalyzer::new();
10+
analyzer.set_github_token(&github_token);
11+
analyzer.set_timeout(120);
12+
13+
let url = "https://github.com/your-username/your-repo";
14+
15+
println!("Analyzing private repository: {}", url);
16+
println!("Using GitHub token for authentication...");
17+
18+
match analyzer.analyze_url(url).await {
19+
Ok(project_analysis) => {
20+
let summary = project_analysis.get_summary();
21+
22+
println!("\nPrivate Repository Analysis:");
23+
println!("Project: {}", summary.project_name);
24+
println!("Files: {}", summary.total_files);
25+
println!("Lines of Code: {}", summary.total_code_lines);
26+
27+
println!("\nTop 5 Languages by Line Count:");
28+
let mut language_stats = project_analysis.get_language_statistics();
29+
language_stats.sort_by(|a, b| b.total_lines.cmp(&a.total_lines));
30+
31+
for (i, stats) in language_stats.iter().take(5).enumerate() {
32+
println!(
33+
" {}. {}: {} lines ({} files)",
34+
i + 1,
35+
stats.language_name,
36+
stats.total_lines,
37+
stats.file_count
38+
);
39+
}
40+
}
41+
Err(e) => {
42+
eprintln!("Failed to analyze repository: {}", e);
43+
eprintln!("Make sure:");
44+
eprintln!("1. GITHUB_TOKEN is set and valid");
45+
eprintln!("2. Token has access to the repository");
46+
eprintln!("3. Repository URL is correct");
47+
}
48+
}
49+
50+
Ok(())
51+
}

0 commit comments

Comments
 (0)