Skip to content

Commit d85e662

Browse files
authored
fix missing EOF newlines in gen'd files (#10)
* fix missing newline on gend files * fix missing newline on gend files * fix missing newline on gend files * fix missing newline on gend files * clean * fix missing newline on gend files * refactor file rendering to common method * clean * clean * debug * clean * clean * clean * clean * clean
1 parent aae651d commit d85e662

8 files changed

Lines changed: 64 additions & 81 deletions

File tree

.pre-commit-config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ repos:
1818
- id: check-symlinks # Detects broken symlinks.
1919
- id: trailing-whitespace # Removes any trailing whitespace at the end of lines.
2020
- id: end-of-file-fixer # Ensures files end with a single newline or are empty.
21+
exclude: templates/
2122

2223
#############################################################################
2324
# JSON, TOML
@@ -71,6 +72,7 @@ repos:
7172
- pyproject.toml
7273
types:
7374
- python
75+
exclude: templates/
7476

7577
- repo: https://github.com/pycqa/flake8
7678
rev: 6.1.0
@@ -80,6 +82,7 @@ repos:
8082
- --config=.cpa/flake8.cfg
8183
types:
8284
- python
85+
exclude: templates/
8386

8487
# - repo: https://github.com/astral-sh/ruff-pre-commit
8588
# rev: v0.1.4

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "cpa"
3-
version = "0.0.7"
4-
edition = "2018"
3+
version = "0.0.9"
4+
edition = "2021"
55

66
[dependencies]
77
askama = "0.12.1"

askama.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[general]
2+
# Directories to search for templates, relative to the crate root.
3+
dirs = ["templates"]
4+
# Unless you add a `-` in a block, whitespace characters won't be trimmed.
5+
whitespace = "preserve"

src/main.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
mod python;
22

3+
use std::process;
4+
35
use clap::Parser;
46
use python::setup_preset;
7+
use regex::Regex;
58

69
#[derive(Parser)]
710
#[clap(
@@ -34,20 +37,30 @@ struct UpdateArgs {
3437
preset: String,
3538
}
3639

40+
fn check_pyver(preset: &str) {
41+
let re = Regex::new(r"python(3\.\d+|4\.\d+)").unwrap();
42+
if re.captures(preset).is_none() {
43+
eprintln!("Python version not recognized in --preset, invalid input. Expected format: 'python3.xx'");
44+
process::exit(1);
45+
};
46+
}
47+
3748
fn main() {
3849
match Cli::parse() {
3950
Cli::Create(args) => {
4051
println!("Creating project with name: {}", args.name);
4152
println!("Using preset: {:?} ", args.preset);
4253
if args.preset.starts_with("python") {
43-
setup_preset(args.preset, args.name, true);
54+
check_pyver(&args.preset);
55+
setup_preset(&args.preset, args.name, true);
4456
} else {
4557
eprintln!("Preset: {:?} not supported", args.preset);
4658
}
4759
}
4860
Cli::Update(args) => {
4961
println!("Updating project with preset: {:?}", args.preset);
50-
setup_preset(args.preset, "".to_string(), false);
62+
check_pyver(&args.preset);
63+
setup_preset(&args.preset, "".to_string(), false);
5164
}
5265
}
5366
}

src/python.rs

Lines changed: 34 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@ use std::{
77
use askama::Template;
88
use regex::Regex;
99

10+
trait CPATemplate {
11+
fn write(&self, prefix: &str, path: &str);
12+
}
13+
14+
// Implement convenience trait for any type that implements `askama::Template`
15+
impl<T: Template> CPATemplate for T {
16+
fn write(&self, prefix: &str, path: &str) {
17+
let content = append_eof(self.render().expect("Failed to render file."));
18+
let mut f = File::create(format!("{}/{}", prefix, path)).expect("Could not create file");
19+
f.write_all(content.as_bytes()).expect("Could not write to file");
20+
}
21+
}
22+
23+
fn append_eof(mut s: String) -> String {
24+
s.push('\n');
25+
s
26+
}
27+
1028
#[derive(Template)]
1129
#[template(path = ".gitignore", escape = "none")]
1230
struct GitIgnore {}
@@ -57,9 +75,9 @@ struct Prettier {}
5775
#[template(path = ".github/workflows/ci.yaml", escape = "none")]
5876
struct GHWorkflowCI {}
5977

60-
pub fn setup_preset(mut preset: String, name: String, create: bool) {
78+
pub fn setup_preset(mut preset: &str, name: String, create: bool) {
6179
if preset == "python" {
62-
preset = "python3.10".to_string();
80+
preset = "python3.10";
6381
}
6482
let mut prefix: String = "./".to_string();
6583
if create {
@@ -71,77 +89,25 @@ pub fn setup_preset(mut preset: String, name: String, create: bool) {
7189
let _ = fs::create_dir_all(format!("{}/.vscode", prefix));
7290
let _ = fs::create_dir_all(format!("{}/.github/workflows", prefix));
7391

74-
// Render Github Actions CI
75-
File::create(format!("{}/.github/workflows/ci.yaml", prefix))
76-
.and_then(|mut file| file.write_all(GHWorkflowCI {}.render().expect("Render fail: ci.yaml").as_bytes()))
77-
.expect("Write fail: ci.yaml");
78-
79-
// Render .vscode/settings.json
80-
File::create(format!("{}/.vscode/settings.json", prefix))
81-
.and_then(|mut file| file.write_all(VSCodeSettings {}.render().expect("Render fail: .vscode/settings.json").as_bytes()))
82-
.expect("Write fail: .vscode/settings.json");
83-
84-
// Render .vscode/extensions.json
85-
File::create(format!("{}/.vscode/extensions.json", prefix))
86-
.and_then(|mut file| {
87-
file.write_all(
88-
VSCodeExtensions {}
89-
.render()
90-
.expect("Render fail: .vscode/extensions.json")
91-
.as_bytes(),
92-
)
93-
})
94-
.expect("Write fail: .vscode/extensions.json");
95-
96-
// Render .gitignore
97-
File::create(format!("{}/.gitignore", prefix))
98-
.and_then(|mut file| file.write_all(GitIgnore {}.render().expect("Render fail: .gitignore").as_bytes()))
99-
.expect("Write fail: .gitignore");
100-
101-
// Render Makefile
102-
File::create(format!("{}/Makefile", prefix))
103-
.and_then(|mut file| file.write_all(Makefile {}.render().expect("Render fail: Makefile").as_bytes()))
104-
.expect("Write fail: Makefile");
105-
106-
// Render Dockerfile
107-
File::create(format!("{}/Dockerfile", prefix))
108-
.and_then(|mut file| file.write_all(Dockerfile {}.render().expect("Render fail: Dockerfile").as_bytes()))
109-
.expect("Write fail: Dockerfile");
110-
111-
// Render main.py
112-
File::create(format!("{}/main.py", prefix))
113-
.and_then(|mut file| file.write_all(MainPy {}.render().expect("Render fail").as_bytes()))
114-
.expect("Render fail: main.py");
115-
116-
// Render pre-commit conf
117-
File::create(format!("{}/.pre-commit-config.yaml", prefix))
118-
.and_then(|mut file| {
119-
file.write_all(
120-
PreCommitConfig { python: true }
121-
.render()
122-
.expect("Render fail: .pre-commit-config.yaml")
123-
.as_bytes(),
124-
)
125-
})
126-
.expect("Write fail: .pre-commit-config.yaml");
127-
128-
// Render Flake8 conf
129-
File::create(format!("{}/.cpa/flake8.cfg", prefix))
130-
.and_then(|mut file| file.write_all(Flake8 {}.render().expect("Render fail: flake8.cfg").as_bytes()))
131-
.expect("Write fail: flake8.cfg");
132-
133-
// Render Prettier conf
134-
File::create(format!("{}/.cpa/prettier.json", prefix))
135-
.and_then(|mut file| file.write_all(Prettier {}.render().expect("Render fail: prettier.json").as_bytes()))
136-
.expect("Write fail: prettier.json");
92+
// Render files
93+
GHWorkflowCI {}.write(&prefix, ".github/workflows/ci.yaml");
94+
VSCodeSettings {}.write(&prefix, ".vscode/settings.json");
95+
VSCodeExtensions {}.write(&prefix, ".vscode/extensions.json");
96+
GitIgnore {}.write(&prefix, ".gitignore");
97+
Makefile {}.write(&prefix, "Makefile");
98+
Dockerfile {}.write(&prefix, "Dockerfile");
99+
MainPy {}.write(&prefix, "main.py");
100+
PreCommitConfig { python: true }.write(&prefix, ".pre-commit-config.yaml");
101+
Flake8 {}.write(&prefix, ".cpa/flake8.cfg");
102+
Prettier {}.write(&prefix, ".cpa/prettier.json");
137103

138104
// Render Poetry conf
139105
let re = Regex::new(r"python(3\.\d+|4\.\d+)").unwrap();
140-
let (python_ver, black_target_ver) = if let Some(caps) = re.captures(&preset) {
106+
let (python_ver, black_target_ver) = if let Some(caps) = re.captures(preset) {
141107
let ver = caps[1].to_string();
142108
(ver.clone(), format!("py{}", ver.replace('.', "")))
143109
} else {
144-
eprintln!("Python version not recognized in --preset, invalid input");
110+
eprintln!("Python version not recognized in --preset, invalid input. Expected format: 'python3.xx'");
145111
process::exit(1);
146112
};
147113

@@ -150,8 +116,6 @@ pub fn setup_preset(mut preset: String, name: String, create: bool) {
150116
python_ver,
151117
black_target_ver,
152118
};
153-
let out_pyproj: String = pyproj.render().expect("Failed to render");
154-
let mut f_pyproj = File::create(format!("{}/pyproject.toml", prefix)).expect("Could not create file");
155-
f_pyproj.write_all(out_pyproj.as_bytes()).expect("Could not write to file");
119+
pyproj.write(&prefix, "pyproject.toml");
156120
println!("Project created at: {}", prefix)
157121
}

templates/.github/workflows/ci.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% raw %}
1+
{% raw -%}
22
name: CI
33

44
on:
@@ -85,4 +85,4 @@ jobs:
8585
else
8686
pre-commit run --from-ref origin/$DEFAULT_BRANCH --to-ref $CUR_SHA
8787
fi
88-
{% endraw %}
88+
{%- endraw %}

templates/.pre-commit-config.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ repos:
4040
- id: shellcheck # Lints shell scripts to identify syntax and usage errors, with a specified severity of 'warning'.
4141
args:
4242
- --severity=warning
43-
44-
{% if python %}
43+
{% if python +%}
4544
#############################################################################
4645
# Python
4746
#############################################################################
@@ -92,8 +91,7 @@ repos:
9291
# hooks:
9392
# - id: poetry-check # Makes sure the poetry configuration does not get committed in a broken state.
9493
# - id: poetry-lock # Ensures the poetry.lock file is up-to-date with the pyproject.toml changes.
95-
96-
{% endif %}
94+
{%+ endif %}
9795
#############################################################################
9896
# CSS, Markdown, JavaScript, TypeScript, YAML style formatter
9997
#############################################################################

0 commit comments

Comments
 (0)