settingspec 0.4.0__tar.gz → 0.5.1__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.4.0 → settingspec-0.5.1}/Cargo.lock +67 -1
- {settingspec-0.4.0 → settingspec-0.5.1}/Cargo.toml +2 -1
- {settingspec-0.4.0 → settingspec-0.5.1}/PKG-INFO +34 -11
- {settingspec-0.4.0 → settingspec-0.5.1}/README.md +33 -10
- {settingspec-0.4.0 → settingspec-0.5.1}/src/cli.rs +110 -35
- {settingspec-0.4.0 → settingspec-0.5.1}/LICENSE-APACHE +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/LICENSE-MIT +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/pyproject.toml +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/envfile.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/error.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/filter.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/common.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/env.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/javascript.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/json.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/lua.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/mod.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/python.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/toml.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/tree.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/typescript.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/generator/yaml.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/lib.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/main.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/model.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/parser.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/src/profile.rs +0 -0
- {settingspec-0.4.0 → settingspec-0.5.1}/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.5.1"
|
|
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.5.1"
|
|
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.5.1
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -19,7 +19,7 @@ Project-URL: Source Code, https://github.com/sayanarijit/settingspec
|
|
|
19
19
|
<picture>
|
|
20
20
|
<source media="(prefers-color-scheme: dark)" srcset="https://s15.gifyu.com/images/buXVO.png">
|
|
21
21
|
<source media="(prefers-color-scheme: light)" srcset="https://s15.gifyu.com/images/buXZJ.png">
|
|
22
|
-
<img alt="The settingspec cover" width="
|
|
22
|
+
<img alt="The settingspec cover" width="100%" src="https://s15.gifyu.com/images/buXZJ.png">
|
|
23
23
|
</picture>
|
|
24
24
|
</p>
|
|
25
25
|
|
|
@@ -28,16 +28,17 @@ Project-URL: Source Code, https://github.com/sayanarijit/settingspec
|
|
|
28
28
|
[](https://pypi.org/project/settingspec)
|
|
29
29
|
[](https://www.npmjs.com/package/@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
|
|
|
@@ -109,6 +110,12 @@ Now export the final settings as declared.
|
|
|
109
110
|
settingspec export
|
|
110
111
|
```
|
|
111
112
|
|
|
113
|
+
Or keep watching to export when `settingspec.toml` changes.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
settingspec watch
|
|
117
|
+
```
|
|
118
|
+
|
|
112
119
|
Or directly run the program with exported settings.
|
|
113
120
|
|
|
114
121
|
```bash
|
|
@@ -182,6 +189,22 @@ envfile.prod = "-" # Read from stdin, encrypted or not
|
|
|
182
189
|
secret1.default.env = "SECRET1" # Load value from $SECRET1
|
|
183
190
|
```
|
|
184
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
|
+
|
|
200
|
+
# decryption.key.env = "AGEBOX_PRIVATE_KEYS"
|
|
201
|
+
# decryption.key.env = "COTTAGE_IDENTITY"
|
|
202
|
+
decryption.key.path = "~/.config/cottage/identity:~/.ssh"
|
|
203
|
+
|
|
204
|
+
[settings]
|
|
205
|
+
secret.default.env = "SECRET"
|
|
206
|
+
```
|
|
207
|
+
|
|
185
208
|
## Learn more
|
|
186
209
|
|
|
187
210
|
Check out the [settingspec.toml](./settingspec.toml) example file and [full specification](./SPECIFICATION.md) for more details.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<picture>
|
|
3
3
|
<source media="(prefers-color-scheme: dark)" srcset="https://s15.gifyu.com/images/buXVO.png">
|
|
4
4
|
<source media="(prefers-color-scheme: light)" srcset="https://s15.gifyu.com/images/buXZJ.png">
|
|
5
|
-
<img alt="The settingspec cover" width="
|
|
5
|
+
<img alt="The settingspec cover" width="100%" src="https://s15.gifyu.com/images/buXZJ.png">
|
|
6
6
|
</picture>
|
|
7
7
|
</p>
|
|
8
8
|
|
|
@@ -11,16 +11,17 @@
|
|
|
11
11
|
[](https://pypi.org/project/settingspec)
|
|
12
12
|
[](https://www.npmjs.com/package/@sayanarijit/settingspec)
|
|
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
|
|
|
@@ -92,6 +93,12 @@ Now export the final settings as declared.
|
|
|
92
93
|
settingspec export
|
|
93
94
|
```
|
|
94
95
|
|
|
96
|
+
Or keep watching to export when `settingspec.toml` changes.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
settingspec watch
|
|
100
|
+
```
|
|
101
|
+
|
|
95
102
|
Or directly run the program with exported settings.
|
|
96
103
|
|
|
97
104
|
```bash
|
|
@@ -165,6 +172,22 @@ envfile.prod = "-" # Read from stdin, encrypted or not
|
|
|
165
172
|
secret1.default.env = "SECRET1" # Load value from $SECRET1
|
|
166
173
|
```
|
|
167
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
|
+
|
|
183
|
+
# decryption.key.env = "AGEBOX_PRIVATE_KEYS"
|
|
184
|
+
# decryption.key.env = "COTTAGE_IDENTITY"
|
|
185
|
+
decryption.key.path = "~/.config/cottage/identity:~/.ssh"
|
|
186
|
+
|
|
187
|
+
[settings]
|
|
188
|
+
secret.default.env = "SECRET"
|
|
189
|
+
```
|
|
190
|
+
|
|
168
191
|
## Learn more
|
|
169
192
|
|
|
170
193
|
Check out the [settingspec.toml](./settingspec.toml) example file and [full specification](./SPECIFICATION.md) for more details.
|
|
@@ -7,8 +7,29 @@ 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
|
+
use std::io::Write;
|
|
11
12
|
use std::path::{Path, PathBuf};
|
|
13
|
+
use std::sync::mpsc;
|
|
14
|
+
use std::time::Duration;
|
|
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
|
+
}
|
|
12
33
|
|
|
13
34
|
#[derive(Parser, Debug)]
|
|
14
35
|
#[command(
|
|
@@ -34,6 +55,8 @@ pub enum Commands {
|
|
|
34
55
|
#[arg(last = true, required = true)]
|
|
35
56
|
command: Vec<String>,
|
|
36
57
|
},
|
|
58
|
+
/// Watches settingspec.toml and regenerates exports whenever it changes
|
|
59
|
+
Watch,
|
|
37
60
|
}
|
|
38
61
|
|
|
39
62
|
pub const INIT_CONFIG: &str = r#"[spec]
|
|
@@ -145,9 +168,83 @@ pub fn run_cli() -> Result<()> {
|
|
|
145
168
|
let ctx = load_and_resolve()?;
|
|
146
169
|
execute_run(&ctx, &command)
|
|
147
170
|
}
|
|
171
|
+
Commands::Watch => run_watch(),
|
|
148
172
|
}
|
|
149
173
|
}
|
|
150
174
|
|
|
175
|
+
fn run_watch() -> Result<()> {
|
|
176
|
+
let ctx = load_and_resolve()?;
|
|
177
|
+
let config_path = ctx.project_root.join("settingspec.toml");
|
|
178
|
+
let mut guard = CleanupGuard::default();
|
|
179
|
+
|
|
180
|
+
let (tx, rx) = mpsc::channel();
|
|
181
|
+
let (txsig, rxsig) = mpsc::channel();
|
|
182
|
+
|
|
183
|
+
ctrlc::set_handler(move || txsig.send(()).expect("Could not send signal on channel."))
|
|
184
|
+
.expect("Error setting Ctrl-C handler");
|
|
185
|
+
|
|
186
|
+
std::thread::spawn(move || {
|
|
187
|
+
let _ = tx.send(true); // Trigger initial export
|
|
188
|
+
|
|
189
|
+
let mut modified = std::fs::metadata(&config_path)
|
|
190
|
+
.ok()
|
|
191
|
+
.and_then(|m| m.modified().ok());
|
|
192
|
+
|
|
193
|
+
loop {
|
|
194
|
+
std::thread::sleep(Duration::from_secs(1));
|
|
195
|
+
if rxsig.try_recv().is_ok() {
|
|
196
|
+
let _ = tx.send(false);
|
|
197
|
+
break;
|
|
198
|
+
} else {
|
|
199
|
+
let new_modified = std::fs::metadata(&config_path)
|
|
200
|
+
.ok()
|
|
201
|
+
.and_then(|m| m.modified().ok());
|
|
202
|
+
if new_modified != modified {
|
|
203
|
+
modified = new_modified;
|
|
204
|
+
let _ = tx.send(true);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
while rx.recv().unwrap_or(false) {
|
|
211
|
+
match load_and_resolve() {
|
|
212
|
+
Ok(mut ctx) => {
|
|
213
|
+
guard.keep = ctx.doc.spec.export.keep;
|
|
214
|
+
if ctx.doc.spec.export.file.is_empty() {
|
|
215
|
+
eprintln!("No export files configured, skipping export.");
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
ctx.doc.spec.export.stdout = None;
|
|
219
|
+
ctx.doc.spec.export.stdin = None;
|
|
220
|
+
ctx.doc.spec.export.env = None;
|
|
221
|
+
|
|
222
|
+
eprintln!("Exporting files...");
|
|
223
|
+
if let Err(e) = perform_export(&ctx) {
|
|
224
|
+
eprintln!("Error during export: {}", e);
|
|
225
|
+
}
|
|
226
|
+
ctx.doc
|
|
227
|
+
.spec
|
|
228
|
+
.export
|
|
229
|
+
.file
|
|
230
|
+
.iter()
|
|
231
|
+
.for_each(|(file_path_str, filter)| {
|
|
232
|
+
if !matches!(filter, ExportFilter::Disabled) {
|
|
233
|
+
guard.paths.insert(PathBuf::from(file_path_str));
|
|
234
|
+
println!("{file_path_str}");
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
Err(e) => {
|
|
239
|
+
eprintln!("Error loading configuration: {}", e);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
eprintln!("Exiting watch mode.");
|
|
245
|
+
Ok(())
|
|
246
|
+
}
|
|
247
|
+
|
|
151
248
|
fn perform_export(ctx: &ExecutionContext) -> Result<Vec<PathBuf>> {
|
|
152
249
|
auto_append_gitignore(ctx)?;
|
|
153
250
|
|
|
@@ -189,28 +286,10 @@ fn execute_run(ctx: &ExecutionContext, command_args: &[String]) -> Result<()> {
|
|
|
189
286
|
}
|
|
190
287
|
|
|
191
288
|
// Export all files
|
|
192
|
-
let
|
|
193
|
-
|
|
194
|
-
// Setup cleanup guard
|
|
195
|
-
struct CleanupGuard {
|
|
196
|
-
files: Vec<PathBuf>,
|
|
197
|
-
keep: bool,
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
impl Drop for CleanupGuard {
|
|
201
|
-
fn drop(&mut self) {
|
|
202
|
-
if !self.keep {
|
|
203
|
-
for f in &self.files {
|
|
204
|
-
let _ = std::fs::remove_file(f);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
let _guard = CleanupGuard {
|
|
211
|
-
files: generated_files,
|
|
289
|
+
let _guard = perform_export(ctx).map(|files| CleanupGuard {
|
|
212
290
|
keep: ctx.doc.spec.export.keep,
|
|
213
|
-
|
|
291
|
+
paths: files.into_iter().collect(),
|
|
292
|
+
})?;
|
|
214
293
|
|
|
215
294
|
let stdin_payload = if let Some(ref stdin_fmt) = ctx.doc.spec.export.stdin {
|
|
216
295
|
Some(generate_by_format(stdin_fmt, &ctx.resolved_settings)?)
|
|
@@ -250,7 +329,6 @@ fn execute_run(ctx: &ExecutionContext, command_args: &[String]) -> Result<()> {
|
|
|
250
329
|
let child_stdin = child.stdin.take();
|
|
251
330
|
let writer = std::thread::spawn(move || {
|
|
252
331
|
if let Some(mut stdin) = child_stdin {
|
|
253
|
-
use std::io::Write;
|
|
254
332
|
let _ = stdin.write_all(payload.as_bytes());
|
|
255
333
|
}
|
|
256
334
|
});
|
|
@@ -372,16 +450,14 @@ pub fn auto_append_gitignore(ctx: &ExecutionContext) -> Result<()> {
|
|
|
372
450
|
return Ok(());
|
|
373
451
|
}
|
|
374
452
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
None => return Ok(()),
|
|
379
|
-
};
|
|
453
|
+
if find_git_root(&ctx.project_root).is_none() {
|
|
454
|
+
return Ok(());
|
|
455
|
+
}
|
|
380
456
|
|
|
381
|
-
let
|
|
382
|
-
let
|
|
457
|
+
let project_root = &ctx.project_root;
|
|
458
|
+
let project_root_canon = project_root
|
|
383
459
|
.canonicalize()
|
|
384
|
-
.unwrap_or_else(|_|
|
|
460
|
+
.unwrap_or_else(|_| project_root.clone());
|
|
385
461
|
|
|
386
462
|
let mut entries_to_add = Vec::new();
|
|
387
463
|
|
|
@@ -392,13 +468,13 @@ pub fn auto_append_gitignore(ctx: &ExecutionContext) -> Result<()> {
|
|
|
392
468
|
|
|
393
469
|
let target_path = Path::new(file_path_str);
|
|
394
470
|
let full_target = if target_path.is_relative() {
|
|
395
|
-
|
|
471
|
+
project_root_canon.join(target_path)
|
|
396
472
|
} else {
|
|
397
473
|
target_path.to_path_buf()
|
|
398
474
|
};
|
|
399
475
|
|
|
400
476
|
let normalized = normalize_path(&full_target);
|
|
401
|
-
let rel_path = match normalized.strip_prefix(&
|
|
477
|
+
let rel_path = match normalized.strip_prefix(&project_root_canon) {
|
|
402
478
|
Ok(rel) => rel,
|
|
403
479
|
Err(_) => continue,
|
|
404
480
|
};
|
|
@@ -422,7 +498,7 @@ pub fn auto_append_gitignore(ctx: &ExecutionContext) -> Result<()> {
|
|
|
422
498
|
return Ok(());
|
|
423
499
|
}
|
|
424
500
|
|
|
425
|
-
let gitignore_path =
|
|
501
|
+
let gitignore_path = project_root.join(".gitignore");
|
|
426
502
|
let existing_content = if gitignore_path.exists() {
|
|
427
503
|
std::fs::read_to_string(&gitignore_path)?
|
|
428
504
|
} else {
|
|
@@ -449,7 +525,6 @@ pub fn auto_append_gitignore(ctx: &ExecutionContext) -> Result<()> {
|
|
|
449
525
|
to_append.push('\n');
|
|
450
526
|
}
|
|
451
527
|
|
|
452
|
-
use std::io::Write;
|
|
453
528
|
let mut file = std::fs::OpenOptions::new()
|
|
454
529
|
.create(true)
|
|
455
530
|
.append(true)
|
|
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
|