settingspec 0.5.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {settingspec-0.5.0 → settingspec-0.6.0}/Cargo.lock +67 -1
- {settingspec-0.5.0 → settingspec-0.6.0}/Cargo.toml +2 -1
- {settingspec-0.5.0 → settingspec-0.6.0}/PKG-INFO +27 -9
- {settingspec-0.5.0 → settingspec-0.6.0}/README.md +26 -8
- {settingspec-0.5.0 → settingspec-0.6.0}/src/cli.rs +89 -44
- {settingspec-0.5.0 → settingspec-0.6.0}/LICENSE-APACHE +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/LICENSE-MIT +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/pyproject.toml +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/envfile.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/error.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/filter.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/common.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/env.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/javascript.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/json.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/lua.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/mod.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/python.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/toml.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/tree.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/typescript.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/generator/yaml.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/lib.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/main.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/model.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/parser.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/profile.rs +0 -0
- {settingspec-0.5.0 → settingspec-0.6.0}/src/resolver.rs +0 -0
|
@@ -282,6 +282,15 @@ dependencies = [
|
|
|
282
282
|
"generic-array",
|
|
283
283
|
]
|
|
284
284
|
|
|
285
|
+
[[package]]
|
|
286
|
+
name = "block2"
|
|
287
|
+
version = "0.6.2"
|
|
288
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
289
|
+
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
|
|
290
|
+
dependencies = [
|
|
291
|
+
"objc2",
|
|
292
|
+
]
|
|
293
|
+
|
|
285
294
|
[[package]]
|
|
286
295
|
name = "blowfish"
|
|
287
296
|
version = "0.9.1"
|
|
@@ -324,6 +333,12 @@ version = "1.0.5"
|
|
|
324
333
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
325
334
|
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
|
326
335
|
|
|
336
|
+
[[package]]
|
|
337
|
+
name = "cfg_aliases"
|
|
338
|
+
version = "0.2.2"
|
|
339
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
340
|
+
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
|
|
341
|
+
|
|
327
342
|
[[package]]
|
|
328
343
|
name = "chacha20"
|
|
329
344
|
version = "0.9.1"
|
|
@@ -519,6 +534,17 @@ dependencies = [
|
|
|
519
534
|
"cipher",
|
|
520
535
|
]
|
|
521
536
|
|
|
537
|
+
[[package]]
|
|
538
|
+
name = "ctrlc"
|
|
539
|
+
version = "3.5.2"
|
|
540
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
541
|
+
checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162"
|
|
542
|
+
dependencies = [
|
|
543
|
+
"dispatch2",
|
|
544
|
+
"nix",
|
|
545
|
+
"windows-sys",
|
|
546
|
+
]
|
|
547
|
+
|
|
522
548
|
[[package]]
|
|
523
549
|
name = "curve25519-dalek"
|
|
524
550
|
version = "4.1.3"
|
|
@@ -584,6 +610,18 @@ dependencies = [
|
|
|
584
610
|
"crypto-common 0.2.2",
|
|
585
611
|
]
|
|
586
612
|
|
|
613
|
+
[[package]]
|
|
614
|
+
name = "dispatch2"
|
|
615
|
+
version = "0.3.1"
|
|
616
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
617
|
+
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
|
618
|
+
dependencies = [
|
|
619
|
+
"bitflags",
|
|
620
|
+
"block2",
|
|
621
|
+
"libc",
|
|
622
|
+
"objc2",
|
|
623
|
+
]
|
|
624
|
+
|
|
587
625
|
[[package]]
|
|
588
626
|
name = "displaydoc"
|
|
589
627
|
version = "0.2.7"
|
|
@@ -1180,6 +1218,18 @@ dependencies = [
|
|
|
1180
1218
|
"sha3",
|
|
1181
1219
|
]
|
|
1182
1220
|
|
|
1221
|
+
[[package]]
|
|
1222
|
+
name = "nix"
|
|
1223
|
+
version = "0.31.3"
|
|
1224
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1225
|
+
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
|
|
1226
|
+
dependencies = [
|
|
1227
|
+
"bitflags",
|
|
1228
|
+
"cfg-if",
|
|
1229
|
+
"cfg_aliases",
|
|
1230
|
+
"libc",
|
|
1231
|
+
]
|
|
1232
|
+
|
|
1183
1233
|
[[package]]
|
|
1184
1234
|
name = "nom"
|
|
1185
1235
|
version = "8.0.0"
|
|
@@ -1240,6 +1290,21 @@ dependencies = [
|
|
|
1240
1290
|
"libm",
|
|
1241
1291
|
]
|
|
1242
1292
|
|
|
1293
|
+
[[package]]
|
|
1294
|
+
name = "objc2"
|
|
1295
|
+
version = "0.6.4"
|
|
1296
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1297
|
+
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
|
|
1298
|
+
dependencies = [
|
|
1299
|
+
"objc2-encode",
|
|
1300
|
+
]
|
|
1301
|
+
|
|
1302
|
+
[[package]]
|
|
1303
|
+
name = "objc2-encode"
|
|
1304
|
+
version = "4.1.0"
|
|
1305
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1306
|
+
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
|
1307
|
+
|
|
1243
1308
|
[[package]]
|
|
1244
1309
|
name = "once_cell"
|
|
1245
1310
|
version = "1.21.4"
|
|
@@ -1758,7 +1823,7 @@ dependencies = [
|
|
|
1758
1823
|
|
|
1759
1824
|
[[package]]
|
|
1760
1825
|
name = "settingspec"
|
|
1761
|
-
version = "0.
|
|
1826
|
+
version = "0.6.0"
|
|
1762
1827
|
dependencies = [
|
|
1763
1828
|
"age",
|
|
1764
1829
|
"anyhow",
|
|
@@ -1766,6 +1831,7 @@ dependencies = [
|
|
|
1766
1831
|
"assert_fs",
|
|
1767
1832
|
"clap",
|
|
1768
1833
|
"clap_complete",
|
|
1834
|
+
"ctrlc",
|
|
1769
1835
|
"dotenvy",
|
|
1770
1836
|
"indexmap",
|
|
1771
1837
|
"predicates",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "settingspec"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.0"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
description = "One file for all environments, all languages, all submodules."
|
|
6
6
|
readme = "README.md"
|
|
@@ -40,6 +40,7 @@ serde_yaml = "0.9"
|
|
|
40
40
|
indexmap = { version = "2", features = ["serde"] }
|
|
41
41
|
dotenvy = "0.15.7"
|
|
42
42
|
age = { version = "0.12.1", features = ["armor", "ssh"] }
|
|
43
|
+
ctrlc = "3.5.2"
|
|
43
44
|
|
|
44
45
|
[dev-dependencies]
|
|
45
46
|
assert_fs = "1.1.4"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: settingspec
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -30,14 +30,15 @@ Project-URL: Source Code, https://github.com/sayanarijit/settingspec
|
|
|
30
30
|
|
|
31
31
|
# SettingSpec
|
|
32
32
|
|
|
33
|
-
1.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
1. [Concepts](#concepts)
|
|
34
|
+
1. [Single file convenience](#single-file-convenience)
|
|
35
|
+
2. [Declarative profiles as environments](#declarative-profiles-as-environments)
|
|
36
|
+
3. [Language independent](#language-independent)
|
|
37
|
+
4. [Easy secrets](#easy-secrets)
|
|
38
|
+
1. [SecretSpec](#secretspec)
|
|
39
|
+
2. [Dotenv](#dotenv)
|
|
40
|
+
3. [Cottage or agebox](#cottage-or-agebox)
|
|
41
|
+
2. [Learn more](#learn-more)
|
|
41
42
|
|
|
42
43
|
## Concepts
|
|
43
44
|
|
|
@@ -188,6 +189,23 @@ envfile.prod = "-" # Read from stdin, encrypted or not
|
|
|
188
189
|
secret1.default.env = "SECRET1" # Load value from $SECRET1
|
|
189
190
|
```
|
|
190
191
|
|
|
192
|
+
#### Cottage or agebox
|
|
193
|
+
|
|
194
|
+
Too simple? Use [Cottage](https://cottage-cli.pages.dev) or [agebox](https://github.com/slok/agebox).
|
|
195
|
+
|
|
196
|
+
```toml
|
|
197
|
+
[spec]
|
|
198
|
+
envfile.default = ".env.cott.age"
|
|
199
|
+
# envfile.default = ".env.agebox"
|
|
200
|
+
|
|
201
|
+
decryption.key.path = "~/.config/cottage/identity:~/.ssh"
|
|
202
|
+
decryption.key.env = "COTTAGE_IDENTITY"
|
|
203
|
+
# decryption.key.env = "AGEBOX_PRIVATE_KEYS"
|
|
204
|
+
|
|
205
|
+
[settings]
|
|
206
|
+
secret.default.env = "SECRET"
|
|
207
|
+
```
|
|
208
|
+
|
|
191
209
|
## Learn more
|
|
192
210
|
|
|
193
211
|
Check out the [settingspec.toml](./settingspec.toml) example file and [full specification](./SPECIFICATION.md) for more details.
|
|
@@ -13,14 +13,15 @@
|
|
|
13
13
|
|
|
14
14
|
# SettingSpec
|
|
15
15
|
|
|
16
|
-
1.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
1. [Concepts](#concepts)
|
|
17
|
+
1. [Single file convenience](#single-file-convenience)
|
|
18
|
+
2. [Declarative profiles as environments](#declarative-profiles-as-environments)
|
|
19
|
+
3. [Language independent](#language-independent)
|
|
20
|
+
4. [Easy secrets](#easy-secrets)
|
|
21
|
+
1. [SecretSpec](#secretspec)
|
|
22
|
+
2. [Dotenv](#dotenv)
|
|
23
|
+
3. [Cottage or agebox](#cottage-or-agebox)
|
|
24
|
+
2. [Learn more](#learn-more)
|
|
24
25
|
|
|
25
26
|
## Concepts
|
|
26
27
|
|
|
@@ -171,6 +172,23 @@ envfile.prod = "-" # Read from stdin, encrypted or not
|
|
|
171
172
|
secret1.default.env = "SECRET1" # Load value from $SECRET1
|
|
172
173
|
```
|
|
173
174
|
|
|
175
|
+
#### Cottage or agebox
|
|
176
|
+
|
|
177
|
+
Too simple? Use [Cottage](https://cottage-cli.pages.dev) or [agebox](https://github.com/slok/agebox).
|
|
178
|
+
|
|
179
|
+
```toml
|
|
180
|
+
[spec]
|
|
181
|
+
envfile.default = ".env.cott.age"
|
|
182
|
+
# envfile.default = ".env.agebox"
|
|
183
|
+
|
|
184
|
+
decryption.key.path = "~/.config/cottage/identity:~/.ssh"
|
|
185
|
+
decryption.key.env = "COTTAGE_IDENTITY"
|
|
186
|
+
# decryption.key.env = "AGEBOX_PRIVATE_KEYS"
|
|
187
|
+
|
|
188
|
+
[settings]
|
|
189
|
+
secret.default.env = "SECRET"
|
|
190
|
+
```
|
|
191
|
+
|
|
174
192
|
## Learn more
|
|
175
193
|
|
|
176
194
|
Check out the [settingspec.toml](./settingspec.toml) example file and [full specification](./SPECIFICATION.md) for more details.
|
|
@@ -7,12 +7,30 @@ use crate::parser::parse_config_str;
|
|
|
7
7
|
use crate::profile::resolve_active_profile;
|
|
8
8
|
use crate::resolver::resolve_settings;
|
|
9
9
|
use clap::{Parser, Subcommand};
|
|
10
|
-
use std::collections::HashMap;
|
|
10
|
+
use std::collections::{HashMap, HashSet};
|
|
11
11
|
use std::io::Write;
|
|
12
12
|
use std::path::{Path, PathBuf};
|
|
13
13
|
use std::sync::mpsc;
|
|
14
14
|
use std::time::Duration;
|
|
15
15
|
|
|
16
|
+
#[derive(Default)]
|
|
17
|
+
struct CleanupGuard {
|
|
18
|
+
keep: bool,
|
|
19
|
+
paths: HashSet<PathBuf>,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
impl Drop for CleanupGuard {
|
|
23
|
+
fn drop(&mut self) {
|
|
24
|
+
if !self.keep {
|
|
25
|
+
self.paths.iter().for_each(|path| {
|
|
26
|
+
if std::fs::exists(path).unwrap_or(false) {
|
|
27
|
+
let _ = std::fs::remove_file(path);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
16
34
|
#[derive(Parser, Debug)]
|
|
17
35
|
#[command(
|
|
18
36
|
name = "settingspec",
|
|
@@ -39,6 +57,9 @@ pub enum Commands {
|
|
|
39
57
|
},
|
|
40
58
|
/// Watches settingspec.toml and regenerates exports whenever it changes
|
|
41
59
|
Watch,
|
|
60
|
+
|
|
61
|
+
/// Deletes all generated export files
|
|
62
|
+
Clean,
|
|
42
63
|
}
|
|
43
64
|
|
|
44
65
|
pub const INIT_CONFIG: &str = r#"[spec]
|
|
@@ -151,40 +172,72 @@ pub fn run_cli() -> Result<()> {
|
|
|
151
172
|
execute_run(&ctx, &command)
|
|
152
173
|
}
|
|
153
174
|
Commands::Watch => run_watch(),
|
|
175
|
+
Commands::Clean => clean_exported_files(),
|
|
154
176
|
}
|
|
155
177
|
}
|
|
156
178
|
|
|
157
179
|
fn run_watch() -> Result<()> {
|
|
158
180
|
let ctx = load_and_resolve()?;
|
|
159
|
-
perform_export(&ctx)?;
|
|
160
|
-
|
|
161
181
|
let config_path = ctx.project_root.join("settingspec.toml");
|
|
182
|
+
let mut guard = CleanupGuard::default();
|
|
162
183
|
|
|
163
184
|
let (tx, rx) = mpsc::channel();
|
|
185
|
+
let (txsig, rxsig) = mpsc::channel();
|
|
186
|
+
|
|
187
|
+
ctrlc::set_handler(move || txsig.send(()).expect("Could not send signal on channel."))
|
|
188
|
+
.expect("Error setting Ctrl-C handler");
|
|
164
189
|
|
|
165
190
|
std::thread::spawn(move || {
|
|
191
|
+
let _ = tx.send(true); // Trigger initial export
|
|
192
|
+
|
|
166
193
|
let mut modified = std::fs::metadata(&config_path)
|
|
167
194
|
.ok()
|
|
168
195
|
.and_then(|m| m.modified().ok());
|
|
196
|
+
|
|
169
197
|
loop {
|
|
170
198
|
std::thread::sleep(Duration::from_secs(1));
|
|
171
|
-
|
|
172
|
-
.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
199
|
+
if rxsig.try_recv().is_ok() {
|
|
200
|
+
let _ = tx.send(false);
|
|
201
|
+
break;
|
|
202
|
+
} else {
|
|
203
|
+
let new_modified = std::fs::metadata(&config_path)
|
|
204
|
+
.ok()
|
|
205
|
+
.and_then(|m| m.modified().ok());
|
|
206
|
+
if new_modified != modified {
|
|
207
|
+
modified = new_modified;
|
|
208
|
+
let _ = tx.send(true);
|
|
209
|
+
}
|
|
177
210
|
}
|
|
178
211
|
}
|
|
179
212
|
});
|
|
180
213
|
|
|
181
|
-
while rx.recv().
|
|
182
|
-
println!("Detected change in settingspec.toml, reloading...");
|
|
214
|
+
while rx.recv().unwrap_or(false) {
|
|
183
215
|
match load_and_resolve() {
|
|
184
|
-
Ok(ctx) => {
|
|
216
|
+
Ok(mut ctx) => {
|
|
217
|
+
guard.keep = ctx.doc.spec.export.keep;
|
|
218
|
+
if ctx.doc.spec.export.file.is_empty() {
|
|
219
|
+
eprintln!("No export files configured, skipping export.");
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
ctx.doc.spec.export.stdout = None;
|
|
223
|
+
ctx.doc.spec.export.stdin = None;
|
|
224
|
+
ctx.doc.spec.export.env = None;
|
|
225
|
+
|
|
226
|
+
eprintln!("Exporting files...");
|
|
185
227
|
if let Err(e) = perform_export(&ctx) {
|
|
186
228
|
eprintln!("Error during export: {}", e);
|
|
187
229
|
}
|
|
230
|
+
ctx.doc
|
|
231
|
+
.spec
|
|
232
|
+
.export
|
|
233
|
+
.file
|
|
234
|
+
.iter()
|
|
235
|
+
.for_each(|(file_path_str, filter)| {
|
|
236
|
+
if !matches!(filter, ExportFilter::Disabled) {
|
|
237
|
+
guard.paths.insert(PathBuf::from(file_path_str));
|
|
238
|
+
println!("{file_path_str}");
|
|
239
|
+
}
|
|
240
|
+
});
|
|
188
241
|
}
|
|
189
242
|
Err(e) => {
|
|
190
243
|
eprintln!("Error loading configuration: {}", e);
|
|
@@ -192,6 +245,7 @@ fn run_watch() -> Result<()> {
|
|
|
192
245
|
}
|
|
193
246
|
}
|
|
194
247
|
|
|
248
|
+
eprintln!("Exiting watch mode.");
|
|
195
249
|
Ok(())
|
|
196
250
|
}
|
|
197
251
|
|
|
@@ -228,6 +282,17 @@ fn perform_export(ctx: &ExecutionContext) -> Result<Vec<PathBuf>> {
|
|
|
228
282
|
Ok(generated_files)
|
|
229
283
|
}
|
|
230
284
|
|
|
285
|
+
fn clean_exported_files() -> Result<()> {
|
|
286
|
+
let ctx = load_and_resolve()?;
|
|
287
|
+
|
|
288
|
+
let _guard = CleanupGuard {
|
|
289
|
+
keep: false,
|
|
290
|
+
paths: ctx.doc.spec.export.file.keys().map(PathBuf::from).collect(),
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
Ok(())
|
|
294
|
+
}
|
|
295
|
+
|
|
231
296
|
fn execute_run(ctx: &ExecutionContext, command_args: &[String]) -> Result<()> {
|
|
232
297
|
if command_args.is_empty() {
|
|
233
298
|
return Err(SettingSpecError::InvalidToml(
|
|
@@ -236,28 +301,10 @@ fn execute_run(ctx: &ExecutionContext, command_args: &[String]) -> Result<()> {
|
|
|
236
301
|
}
|
|
237
302
|
|
|
238
303
|
// Export all files
|
|
239
|
-
let
|
|
240
|
-
|
|
241
|
-
// Setup cleanup guard
|
|
242
|
-
struct CleanupGuard {
|
|
243
|
-
files: Vec<PathBuf>,
|
|
244
|
-
keep: bool,
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
impl Drop for CleanupGuard {
|
|
248
|
-
fn drop(&mut self) {
|
|
249
|
-
if !self.keep {
|
|
250
|
-
for f in &self.files {
|
|
251
|
-
let _ = std::fs::remove_file(f);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
let _guard = CleanupGuard {
|
|
258
|
-
files: generated_files,
|
|
304
|
+
let _guard = perform_export(ctx).map(|files| CleanupGuard {
|
|
259
305
|
keep: ctx.doc.spec.export.keep,
|
|
260
|
-
|
|
306
|
+
paths: files.into_iter().collect(),
|
|
307
|
+
})?;
|
|
261
308
|
|
|
262
309
|
let stdin_payload = if let Some(ref stdin_fmt) = ctx.doc.spec.export.stdin {
|
|
263
310
|
Some(generate_by_format(stdin_fmt, &ctx.resolved_settings)?)
|
|
@@ -418,16 +465,14 @@ pub fn auto_append_gitignore(ctx: &ExecutionContext) -> Result<()> {
|
|
|
418
465
|
return Ok(());
|
|
419
466
|
}
|
|
420
467
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
None => return Ok(()),
|
|
425
|
-
};
|
|
468
|
+
if find_git_root(&ctx.project_root).is_none() {
|
|
469
|
+
return Ok(());
|
|
470
|
+
}
|
|
426
471
|
|
|
427
|
-
let
|
|
428
|
-
let
|
|
472
|
+
let project_root = &ctx.project_root;
|
|
473
|
+
let project_root_canon = project_root
|
|
429
474
|
.canonicalize()
|
|
430
|
-
.unwrap_or_else(|_|
|
|
475
|
+
.unwrap_or_else(|_| project_root.clone());
|
|
431
476
|
|
|
432
477
|
let mut entries_to_add = Vec::new();
|
|
433
478
|
|
|
@@ -438,13 +483,13 @@ pub fn auto_append_gitignore(ctx: &ExecutionContext) -> Result<()> {
|
|
|
438
483
|
|
|
439
484
|
let target_path = Path::new(file_path_str);
|
|
440
485
|
let full_target = if target_path.is_relative() {
|
|
441
|
-
|
|
486
|
+
project_root_canon.join(target_path)
|
|
442
487
|
} else {
|
|
443
488
|
target_path.to_path_buf()
|
|
444
489
|
};
|
|
445
490
|
|
|
446
491
|
let normalized = normalize_path(&full_target);
|
|
447
|
-
let rel_path = match normalized.strip_prefix(&
|
|
492
|
+
let rel_path = match normalized.strip_prefix(&project_root_canon) {
|
|
448
493
|
Ok(rel) => rel,
|
|
449
494
|
Err(_) => continue,
|
|
450
495
|
};
|
|
@@ -468,7 +513,7 @@ pub fn auto_append_gitignore(ctx: &ExecutionContext) -> Result<()> {
|
|
|
468
513
|
return Ok(());
|
|
469
514
|
}
|
|
470
515
|
|
|
471
|
-
let gitignore_path =
|
|
516
|
+
let gitignore_path = project_root.join(".gitignore");
|
|
472
517
|
let existing_content = if gitignore_path.exists() {
|
|
473
518
|
std::fs::read_to_string(&gitignore_path)?
|
|
474
519
|
} else {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|