settingspec 0.1.0__tar.gz → 0.1.2__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.1.0 → settingspec-0.1.2}/Cargo.lock +1 -1
- {settingspec-0.1.0 → settingspec-0.1.2}/Cargo.toml +1 -1
- settingspec-0.1.2/PKG-INFO +182 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/README.md +9 -1
- {settingspec-0.1.0 → settingspec-0.1.2}/pyproject.toml +11 -1
- {settingspec-0.1.0 → settingspec-0.1.2}/src/cli.rs +8 -8
- {settingspec-0.1.0 → settingspec-0.1.2}/src/model.rs +10 -8
- settingspec-0.1.0/PKG-INFO +0 -9
- {settingspec-0.1.0 → settingspec-0.1.2}/LICENSE-APACHE +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/LICENSE-MIT +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/envfile.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/error.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/filter.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/common.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/env.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/javascript.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/json.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/lua.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/mod.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/python.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/toml.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/tree.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/typescript.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/generator/yaml.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/lib.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/main.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/parser.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/profile.rs +0 -0
- {settingspec-0.1.0 → settingspec-0.1.2}/src/resolver.rs +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: settingspec
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
|
+
License-File: LICENSE-APACHE
|
|
8
|
+
License-File: LICENSE-MIT
|
|
9
|
+
Summary: One file for all environments, all languages, all submodules.
|
|
10
|
+
Keywords: configuration,settings,secrets,cli,command-line
|
|
11
|
+
Author: Arijit Basu <settingspec@arijitbasu.in>
|
|
12
|
+
Author-email: Arijit Basu <settingspec@arijitbasu.in>
|
|
13
|
+
License: MIT OR Apache-2.0
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
16
|
+
Project-URL: Source Code, https://github.com/sayanarijit/settingspec
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<picture>
|
|
20
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://s15.gifyu.com/images/buXVO.png">
|
|
21
|
+
<source media="(prefers-color-scheme: light)" srcset="https://s15.gifyu.com/images/buXZJ.png">
|
|
22
|
+
<img alt="The settingspec cover" width="600" src="https://s15.gifyu.com/images/buXZJ.png">
|
|
23
|
+
</picture>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
[](https://github.com/sayanarijit/settingspec/actions/workflows/settingspec-check.yml)
|
|
27
|
+
[](https://crates.io/crates/settingspec)
|
|
28
|
+
[](https://pypi.org/project/settingspec)
|
|
29
|
+
[](https://www.npmjs.com/package/@sayanarijit/settingspec)
|
|
30
|
+
|
|
31
|
+
1. [Concepts](#concepts)
|
|
32
|
+
1. [Single file convenience](#single-file-convenience)
|
|
33
|
+
2. [Declarative profiles / environments](#declarative-profiles-/-environments)
|
|
34
|
+
3. [Language independent](#language-independent)
|
|
35
|
+
4. [Easy secrets](#easy-secrets)
|
|
36
|
+
1. [SecretSpec](#secretspec)
|
|
37
|
+
2. [Dotenv](#dotenv)
|
|
38
|
+
2. [Learn more](#learn-more)
|
|
39
|
+
|
|
40
|
+
## Concepts
|
|
41
|
+
|
|
42
|
+
### Single file convenience
|
|
43
|
+
|
|
44
|
+
With a single source of truth, i.e., `settingspec.toml`, you don't need to mentally merge settings from multiple files, say `common.toml`, `dev.toml`, `prod.toml`, etc. No surprise overwrites. One file for all environments, all languages, all submodules.
|
|
45
|
+
|
|
46
|
+
### Declarative profiles / environments
|
|
47
|
+
|
|
48
|
+
```toml
|
|
49
|
+
[spec] # Optional: Declare the specification here
|
|
50
|
+
profile.key = "SETTINGSPEC_PROFILE" # Default: Environment variable name to switch between profiles
|
|
51
|
+
profile.options = [ # Optional: Enables strict checking of per-profile declarations
|
|
52
|
+
"dev",
|
|
53
|
+
"stage",
|
|
54
|
+
"prod",
|
|
55
|
+
]
|
|
56
|
+
profile.default = "dev" # Optional: Default profile when the switch is not set
|
|
57
|
+
|
|
58
|
+
[settings] # Declare the settings here with syntax: `<key>.<profile>.<directive> = <value>`
|
|
59
|
+
key1.default.val = "val1" # Default value for all profiles
|
|
60
|
+
key1.prod.val = "prod1" # Override the default value when SETTINGSPEC_PROFILE=prod
|
|
61
|
+
|
|
62
|
+
# Strictly define different values for different profiles
|
|
63
|
+
key2.dev.val = "dev2" # When SETTINGSPEC_PROFILE=dev, key2=dev2
|
|
64
|
+
key2.stage.val = "stage2"
|
|
65
|
+
key2.prod.val = "prod2"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Overrides are intentional and kept in plain sight (see `key1`).
|
|
69
|
+
|
|
70
|
+
By not defining a default value, you can ensure that you never miss adding a value for a specific profile (e.g. this file will refuse to load if `key2.prod` declaration is missing).
|
|
71
|
+
|
|
72
|
+
### Language independent
|
|
73
|
+
|
|
74
|
+
The command-line tool `settingspec` can export the final settings into well-known formats such as `toml`, `json`, `yaml`, etc., or hard-coded modules such as `.py`, `.js`, `.lua`, etc., write them to disk, print, or pipe them via stdin or even export as environment variables, allowing you to use a single `settingspec.toml` without worrying about the target language.
|
|
75
|
+
|
|
76
|
+
```toml
|
|
77
|
+
[spec]
|
|
78
|
+
export.file = true # Default: Export all settings into settings.toml (or specify fine-grained file map)
|
|
79
|
+
# export.file = { # Optional: Fine-grained control over what to export
|
|
80
|
+
# "settings.json" = true,
|
|
81
|
+
# "settings.yaml" = {
|
|
82
|
+
# key1 = true,
|
|
83
|
+
# group1 = true,
|
|
84
|
+
# group2.subgroup = true,
|
|
85
|
+
# group3.subgroup.key1 = false,
|
|
86
|
+
# "#tag1" = true,
|
|
87
|
+
# },
|
|
88
|
+
# }
|
|
89
|
+
export.skip_gitignore = false # Default: Auto-append exported files to .gitignore if inside a git repo
|
|
90
|
+
export.mode = 0x600 # Default: File permission mode for the exported files
|
|
91
|
+
export.keep = false # Default: Cleanup the exported files after the program exits
|
|
92
|
+
export.stdout = "toml" # Optional: Print in toml format
|
|
93
|
+
export.env = "PREFIX_" # Optional: Export as environment variables prefixed with this string
|
|
94
|
+
export.stdin = "toml" # Optional: Pass settings to program stdin in specified format
|
|
95
|
+
|
|
96
|
+
[settings]
|
|
97
|
+
key1.default.val = "val1"
|
|
98
|
+
group1.key1.default.val = "group1val1"
|
|
99
|
+
group2.subgroup.key1.default.val = "group2val1"
|
|
100
|
+
group3.subgroup.key1.default.val = "group3val1"
|
|
101
|
+
group3.subgroup.key1.default.tags = ["tag1", "tag2"]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Now export the final settings as declared.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
settingspec export
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Or directly run the program with exported settings.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
settingspec run -- [your program]...
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If no export option is specified, the default behavior is to export all settings into `settings.toml`.
|
|
117
|
+
|
|
118
|
+
> [!NOTE]
|
|
119
|
+
> If the target programming language supports null values, you can declare it as `key.default.null = true` in the settings section.
|
|
120
|
+
|
|
121
|
+
### Easy secrets
|
|
122
|
+
|
|
123
|
+
Unlike regular settings, secrets aren't supposed to be easily visible. So, they are best declared inside hidden/encrypted files and passed via environment variables or via stdin.
|
|
124
|
+
|
|
125
|
+
However, with SettingSpec, we can ensure that they are actually set and also include them in the final exported settings.
|
|
126
|
+
|
|
127
|
+
#### SecretSpec
|
|
128
|
+
|
|
129
|
+
You can pair up SettingSpec with a declarative secrets manager such as [SecretSpec](https://secretspec.dev).
|
|
130
|
+
|
|
131
|
+
secretspec.toml
|
|
132
|
+
|
|
133
|
+
```toml
|
|
134
|
+
[project]
|
|
135
|
+
name = "my-app"
|
|
136
|
+
revision = "1.0"
|
|
137
|
+
|
|
138
|
+
[profiles.default]
|
|
139
|
+
SECRET1 = { description = "Secret One", required = true }
|
|
140
|
+
SECRET2 = { description = "Secret Two", required = false }
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
settingspec.toml
|
|
144
|
+
|
|
145
|
+
```toml
|
|
146
|
+
[spec]
|
|
147
|
+
profile.options = ["dev", "stage", "prod"]
|
|
148
|
+
|
|
149
|
+
[settings]
|
|
150
|
+
secret1.default.env = "SECRET1" # Load value from $SECRET1
|
|
151
|
+
|
|
152
|
+
# Override the default value from environment variables
|
|
153
|
+
secret2.default.val = "defaultvalue" # Default value if $SECRET2 is not set
|
|
154
|
+
secret2.default.env = "SECRET2" # Load value from $SECRET2 if set
|
|
155
|
+
secret2.prod.env = "PRODSECRET" # Load value from $PRODSECRET if SETTINGSPEC_PROFILE=prod
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
With these set up, run:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
secretspec run -- settingspec run -- [your program]...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Dotenv
|
|
165
|
+
|
|
166
|
+
Or keep things simple with [Dotenv](https://www.dotenv.org).
|
|
167
|
+
|
|
168
|
+
```toml
|
|
169
|
+
[spec]
|
|
170
|
+
profile.options = ["dev", "stage", "prod"]
|
|
171
|
+
|
|
172
|
+
envfile.default = ".env" # Load environment variables from this file for all profiles
|
|
173
|
+
envfile.prod = "-" # Load environment variables from stdin when SETTINGSPEC_PROFILE=prod
|
|
174
|
+
|
|
175
|
+
[settings]
|
|
176
|
+
secret1.default.env = "SECRET1" # Load value from $SECRET1
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Learn more
|
|
180
|
+
|
|
181
|
+
Check out the [settingspec.toml](./settingspec.toml) example file and [full specification](./SPECIFICATION.md) for more details.
|
|
182
|
+
|
|
@@ -10,7 +10,15 @@
|
|
|
10
10
|
[](https://crates.io/crates/settingspec)
|
|
11
11
|
[](https://pypi.org/project/settingspec)
|
|
12
12
|
[](https://www.npmjs.com/package/@sayanarijit/settingspec)
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
1. [Concepts](#concepts)
|
|
15
|
+
1. [Single file convenience](#single-file-convenience)
|
|
16
|
+
2. [Declarative profiles / environments](#declarative-profiles-/-environments)
|
|
17
|
+
3. [Language independent](#language-independent)
|
|
18
|
+
4. [Easy secrets](#easy-secrets)
|
|
19
|
+
1. [SecretSpec](#secretspec)
|
|
20
|
+
2. [Dotenv](#dotenv)
|
|
21
|
+
2. [Learn more](#learn-more)
|
|
14
22
|
|
|
15
23
|
## Concepts
|
|
16
24
|
|
|
@@ -10,4 +10,14 @@ classifiers = [
|
|
|
10
10
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
11
11
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
12
12
|
]
|
|
13
|
-
dynamic = [
|
|
13
|
+
dynamic = [
|
|
14
|
+
"version",
|
|
15
|
+
"description",
|
|
16
|
+
"readme",
|
|
17
|
+
"license",
|
|
18
|
+
"authors",
|
|
19
|
+
"keywords",
|
|
20
|
+
"urls",
|
|
21
|
+
]
|
|
22
|
+
[tool.maturin]
|
|
23
|
+
bindings = "bin"
|
|
@@ -224,7 +224,7 @@ fn execute_run(ctx: &ExecutionContext, command_args: &[String]) -> Result<()> {
|
|
|
224
224
|
Ok(())
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
pub fn write_export_file(path: &Path, content: &str,
|
|
227
|
+
pub fn write_export_file(path: &Path, content: &str, _mode: u32) -> Result<()> {
|
|
228
228
|
if let Some(parent) = path.parent()
|
|
229
229
|
&& !parent.as_os_str().is_empty()
|
|
230
230
|
{
|
|
@@ -236,7 +236,7 @@ pub fn write_export_file(path: &Path, content: &str, mode: u32) -> Result<()> {
|
|
|
236
236
|
#[cfg(unix)]
|
|
237
237
|
{
|
|
238
238
|
use std::os::unix::fs::PermissionsExt;
|
|
239
|
-
let perms = std::fs::Permissions::from_mode(
|
|
239
|
+
let perms = std::fs::Permissions::from_mode(_mode);
|
|
240
240
|
let _ = std::fs::set_permissions(path, perms);
|
|
241
241
|
}
|
|
242
242
|
|
|
@@ -296,12 +296,12 @@ fn is_entry_in_gitignore(existing_content: &str, entry: &str) -> bool {
|
|
|
296
296
|
}
|
|
297
297
|
// In git, a pattern without '/' matches anywhere in the repository:
|
|
298
298
|
// E.g. if .gitignore has "settings.toml", it matches "subdir/settings.toml".
|
|
299
|
-
if !trimmed.starts_with('/')
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
299
|
+
if !trimmed.starts_with('/')
|
|
300
|
+
&& !norm_line.contains('/')
|
|
301
|
+
&& let Some((_, file_name)) = norm_entry.rsplit_once('/')
|
|
302
|
+
&& file_name == norm_line
|
|
303
|
+
{
|
|
304
|
+
return true;
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
false
|
|
@@ -155,14 +155,16 @@ where
|
|
|
155
155
|
D: Deserializer<'de>,
|
|
156
156
|
{
|
|
157
157
|
let val = i64::deserialize(deserializer)?;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
if (0..=0o777).contains(&val) {
|
|
159
|
+
return Ok(val as u32);
|
|
160
|
+
}
|
|
161
|
+
let hex = format!("{:x}", val);
|
|
162
|
+
if let Ok(octal) = u32::from_str_radix(&hex, 8)
|
|
163
|
+
&& (0..=0o7777).contains(&octal)
|
|
164
|
+
{
|
|
165
|
+
return Ok(octal);
|
|
166
|
+
}
|
|
167
|
+
Ok(0o600)
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
/// A field that accepts either a boolean toggle or a string value in TOML.
|
settingspec-0.1.0/PKG-INFO
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: settingspec
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Classifier: Programming Language :: Rust
|
|
5
|
-
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
-
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
|
-
License-File: LICENSE-APACHE
|
|
8
|
-
License-File: LICENSE-MIT
|
|
9
|
-
Requires-Python: >=3.8
|
|
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
|