Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Commit 593ebe3

Browse files
author
Hendrik van Antwerpen
committed
Provide common license options and generate license info in project
1 parent ebda937 commit 593ebe3

File tree

3 files changed

+455
-22
lines changed

3 files changed

+455
-22
lines changed

tree-sitter-stack-graphs/Cargo.toml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,22 @@ name = "tree-sitter-stack-graphs"
2222
required-features = ["cli"]
2323

2424
[features]
25-
cli = ["clap", "colored", "dialoguer", "env_logger", "indoc", "pathdiff", "stack-graphs/json", "tree-sitter-config", "walkdir"]
25+
cli = [
26+
"chrono",
27+
"clap",
28+
"colored",
29+
"dialoguer",
30+
"env_logger",
31+
"indoc",
32+
"pathdiff",
33+
"stack-graphs/json",
34+
"tree-sitter-config",
35+
"walkdir"
36+
]
2637

2738
[dependencies]
2839
anyhow = "1.0"
40+
chrono = { version = "0.4", optional = true }
2941
clap = { version = "3", optional = true, features=["derive"] }
3042
colored = { version = "2.0", optional = true }
3143
controlled-option = ">=0.4"

tree-sitter-stack-graphs/src/cli/init.rs

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// ------------------------------------------------------------------------------------------------
77

88
use anyhow::anyhow;
9+
use chrono::Datelike;
910
use clap::Args;
1011
use clap::ValueHint;
1112
use dialoguer::Input;
@@ -21,9 +22,14 @@ use std::io::Write;
2122
use std::path::Path;
2223
use std::path::PathBuf;
2324

24-
const TSSG_VERSION: &str = env!("CARGO_PKG_VERSION");
25+
use self::license::lookup_license;
26+
use self::license::DEFAULT_LICENSES;
27+
use self::license::NO_LICENSE;
28+
use self::license::OTHER_LICENSE;
29+
30+
mod license;
2531

26-
const DEFAULT_LICENSES: &[&str] = &["APACHE-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", "MIT"];
32+
const TSSG_VERSION: &str = env!("CARGO_PKG_VERSION");
2733

2834
lazy_static! {
2935
static ref VALID_CRATE_NAME: Regex = Regex::new(r"^[a-zA-Z_-][a-zA-Z0-9_-]*$").unwrap();
@@ -210,41 +216,29 @@ impl ProjectSettings {
210216
license identifiers.
211217
"#
212218
};
213-
let other_index = DEFAULT_LICENSES.len();
214-
let none_index = other_index + 1;
215-
let selected = DEFAULT_LICENSES
216-
.iter()
217-
.position(|l| l == &self.license)
218-
.unwrap_or_else(|| {
219-
if self.license.is_empty() {
220-
none_index
221-
} else {
222-
other_index
223-
}
224-
});
225-
let (other, other_default) = if selected == other_index {
219+
let selected = lookup_license(&self.license);
220+
let (other, other_default) = if selected == OTHER_LICENSE {
226221
(format!("Other ({})", self.license), self.license.as_ref())
227222
} else {
228223
("Other".to_string(), "")
229224
};
230-
let mut selector = Select::new();
231-
let selected = selector
225+
let selected = Select::new()
232226
.with_prompt("License")
233-
.items(DEFAULT_LICENSES)
227+
.items(&DEFAULT_LICENSES.iter().map(|l| l.0).collect::<Vec<_>>())
234228
.item(&other)
235229
.item("None")
236230
.default(selected)
237231
.interact()?;
238-
self.license = if selected == none_index {
232+
self.license = if selected == NO_LICENSE {
239233
"".to_string()
240-
} else if selected == other_index {
234+
} else if selected == OTHER_LICENSE {
241235
Input::new()
242236
.with_prompt("Other license")
243237
.with_initial_text(other_default)
244238
.allow_empty(true)
245239
.interact_text()?
246240
} else {
247-
DEFAULT_LICENSES[selected].to_string()
241+
DEFAULT_LICENSES[selected].0.to_string()
248242
};
249243

250244
printdoc! {r#"
@@ -288,13 +282,22 @@ impl ProjectSettings {
288282
self.grammar_crate_name.replace("-", "_")
289283
}
290284

285+
fn license_author(&self) -> String {
286+
if self.author.is_empty() {
287+
format!("the {} authors", self.crate_name)
288+
} else {
289+
self.author.clone()
290+
}
291+
}
292+
291293
fn generate_files_into(&self, project_path: &Path) -> anyhow::Result<()> {
292294
fs::create_dir_all(project_path)?;
293295
fs::create_dir_all(project_path.join("rust"))?;
294296
fs::create_dir_all(project_path.join("src"))?;
295297
fs::create_dir_all(project_path.join("test"))?;
296298
self.generate_readme(project_path)?;
297299
self.generate_changelog(project_path)?;
300+
self.generate_license(project_path)?;
298301
self.generate_cargo_toml(project_path)?;
299302
self.generate_rust_bin(project_path)?;
300303
self.generate_rust_lib(project_path)?;
@@ -437,6 +440,31 @@ impl ProjectSettings {
437440
Ok(())
438441
}
439442

443+
fn generate_license(&self, project_path: &Path) -> std::io::Result<()> {
444+
match lookup_license(&self.license) {
445+
NO_LICENSE | OTHER_LICENSE => {}
446+
selected => {
447+
let mut file = File::create(project_path.join("LICENSE"))?;
448+
let year = chrono::Utc::now().year();
449+
let author = self.license_author();
450+
(DEFAULT_LICENSES[selected].2)(&mut file, year, &author)?;
451+
}
452+
};
453+
Ok(())
454+
}
455+
456+
fn write_license_header(&self, file: &mut File, prefix: &str) -> std::io::Result<()> {
457+
match lookup_license(&self.license) {
458+
NO_LICENSE | OTHER_LICENSE => {}
459+
selected => {
460+
let year = chrono::Utc::now().year();
461+
let author = self.license_author();
462+
(DEFAULT_LICENSES[selected].1)(file, year, &author, prefix)?;
463+
}
464+
};
465+
Ok(())
466+
}
467+
440468
fn generate_cargo_toml(&self, project_path: &Path) -> anyhow::Result<()> {
441469
let mut file = File::create(project_path.join("Cargo.toml"))?;
442470
writedoc! {file, r#"
@@ -496,6 +524,7 @@ impl ProjectSettings {
496524

497525
fn generate_rust_bin(&self, project_path: &Path) -> anyhow::Result<()> {
498526
let mut file = File::create(project_path.join("rust/bin.rs"))?;
527+
self.write_license_header(&mut file, "// ")?;
499528
writedoc! {file, r#"
500529
use clap::Parser;
501530
use tree_sitter_stack_graphs::cli::provided_languages::Subcommands;
@@ -522,6 +551,7 @@ impl ProjectSettings {
522551

523552
fn generate_rust_lib(&self, project_path: &Path) -> anyhow::Result<()> {
524553
let mut file = File::create(project_path.join("rust/lib.rs"))?;
554+
self.write_license_header(&mut file, "// ")?;
525555
writedoc! {file, r#"
526556
use tree_sitter_stack_graphs::loader::FileAnalyzers;
527557
use tree_sitter_stack_graphs::loader::LanguageConfiguration;
@@ -563,6 +593,7 @@ impl ProjectSettings {
563593

564594
fn generate_rust_test(&self, project_path: &Path) -> anyhow::Result<()> {
565595
let mut file = File::create(project_path.join("rust/test.rs"))?;
596+
self.write_license_header(&mut file, "// ")?;
566597
writedoc! {file, r#"
567598
use std::path::PathBuf;
568599
use tree_sitter_stack_graphs::ci::Tester;
@@ -586,6 +617,7 @@ impl ProjectSettings {
586617

587618
fn generate_stack_graphs_tsg(&self, project_path: &Path) -> anyhow::Result<()> {
588619
let mut file = File::create(project_path.join("src/stack-graphs.tsg"))?;
620+
self.write_license_header(&mut file, ";; ")?;
589621
writedoc! {file, r#"
590622
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
591623
;; Stack graphs definition for {}

0 commit comments

Comments
 (0)