Skip to content

Commit bc9665e

Browse files
authored
Merge pull request #303 from volllly/nested-defaults
Allow nested defaults better repo config handling
2 parents 42572c5 + 70dbc48 commit bc9665e

14 files changed

Lines changed: 247 additions & 134 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [0.10.0] - 2023-12-10
10+
11+
### Added
12+
13+
- Default files `default.(yaml|toml|json)` can now be located in any folder of the dotfiles repo. The defaults will be applied to all `dot.(yaml|toml|json)` files in the same folder and all subfolders.
14+
15+
### Changed
16+
17+
- Repo level config file now don't need to specify `global`, `windows`, `linux` or `darwin` keys. If none is provided the `global` key will be used.
18+
919
## [0.9.5] - 2023-07-14
1020

1121
### Added
@@ -211,7 +221,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
211221
- Dotfile linking
212222
- Error handling
213223

214-
[Unreleased]: https://github.com/volllly/rotz/compare/v0.9.5...HEAD
224+
[Unreleased]: https://github.com/volllly/rotz/compare/v0.10.0...HEAD
225+
[0.10.0]: https://github.com/volllly/rotz/releases/tag/v0.10.0
215226
[0.9.5]: https://github.com/volllly/rotz/releases/tag/v0.9.5
216227
[0.9.4]: https://github.com/volllly/rotz/releases/tag/v0.9.4
217228
[0.9.3]: https://github.com/volllly/rotz/releases/tag/v0.9.3

Cargo.lock

Lines changed: 24 additions & 64 deletions
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,6 +1,6 @@
11
[package]
22
name = "rotz"
3-
version = "0.9.5"
3+
version = "0.10.0"
44
edition = "2021"
55
authors = ["Paul Volavsek <paul.volavsek@gmail.com>"]
66
license = "MIT"
@@ -55,7 +55,7 @@ tap = "1.0.1"
5555
tracing = { version = "0.1.40", optional = true }
5656
tracing-tracy = { version = "0.10.4", optional = true }
5757
tracing-subscriber = { version = "0.3.18", optional = true }
58-
rayon = "1.8.0"
58+
strum = { version = "0.25", features = ["derive"] }
5959

6060
[target.'cfg(windows)'.dependencies]
6161
junction = "1.0.0"

docs/docs/configuration/config.yaml.mdx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ These variables can be used in [templates](templating.md).
5858

5959
## Repo defaults
6060

61-
It is possible to put a config file in your repo conatining default values depending on the OS. These are overridden by the config file on the machine.
61+
It is possible to put a config file in your repo containing default values depending on the OS. These are overridden by the config file on the machine.
6262

6363
<TabedCodeBlock title=".dotfiles/config.{{ format }}"
6464
data={{
65-
default: Section({
65+
global: Section({
6666
link_type: '<globalDefault>'
6767
}),
6868
windows: Section({
@@ -74,4 +74,10 @@ It is possible to put a config file in your repo conatining default values depen
7474
darwin: Section({
7575
dotfiles: '<macosDefault>'
7676
})
77-
}} />
77+
}} />
78+
79+
> If no `global`, `windows`, `linux` or `darwin` key is provided the `global` key will be assumed.
80+
> <TabedCodeBlock title=".dotfiles/config.{{ format }}"
81+
> data={{
82+
> link_type: '<globalDefault>'
83+
> }} />

docs/docs/configuration/defaults.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ title: Defaults
55
import TabedCodeBlock from '@site/src/components/TabedCodeBlock';
66
import { Section } from '@ltd/j-toml';
77

8-
The repo can also contain a default file `dots.yaml` in the root folder of the repo.
8+
The repo can also contain default files `defaults.yaml` in any folder of the repo.
99

10-
This file contains defaults which are automatically used for empty keys in the `dot.yaml` files.
10+
These files contain defaults which are automatically used in sub directories for empty keys in the `dot.yaml` files.
1111

1212
You can use template strings `{{ name }}` to substitute the name of the application (the name of the folder the `dot.yaml` file is located in). See [templating](templating.md) for advanced templating.
1313

src/commands/install.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use std::{
66
use crossterm::style::{Attribute, Stylize};
77
use indexmap::IndexSet;
88
use miette::{Diagnostic, Report, Result};
9-
use rayon::prelude::*;
109
use tap::Pipe;
1110
#[cfg(feature = "profiling")]
1211
use tracing::instrument;
@@ -174,7 +173,7 @@ impl Command for Install<'_> {
174173
#[cfg_attr(feature = "profiling", instrument)]
175174
fn execute(&self, (globals, install_command): Self::Args) -> Self::Result {
176175
let dots = crate::dot::read_dots(&self.config.dotfiles, &["/**".to_owned()], &self.config, &self.engine)?
177-
.into_par_iter()
176+
.into_iter()
178177
.filter(|d| d.1.installs.is_some() || d.1.depends.is_some())
179178
.map(|d| (d.0, (d.1.installs, d.1.depends)))
180179
.collect::<HashMap<String, InstallsDots>>();

src/dot/defaults.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use std::{collections::HashMap, fs, path::Path};
2+
3+
use miette::Report;
4+
use tap::Pipe;
5+
#[cfg(feature = "profiling")]
6+
use tracing::instrument;
7+
use walkdir::WalkDir;
8+
use wax::Pattern;
9+
10+
use super::Error;
11+
use crate::{helpers, FileFormat, FILE_EXTENSIONS_GLOB};
12+
13+
#[derive(Debug)]
14+
pub struct Defaults(HashMap<String, (String, FileFormat)>);
15+
16+
impl Defaults {
17+
pub fn for_path(&self, path: impl AsRef<str>) -> Option<&(String, FileFormat)> {
18+
for path in Path::new(path.as_ref()).ancestors() {
19+
if let Some(defaults) = self.0.get(helpers::absolutize_virtually(path).unwrap().as_str()) {
20+
return Some(defaults);
21+
}
22+
}
23+
24+
None
25+
}
26+
27+
#[cfg_attr(feature = "profiling", instrument)]
28+
pub fn from_path(dotfiles_path: &Path) -> Result<Defaults, Box<Error>> {
29+
let defaults = helpers::glob_from_vec(&["**".to_owned()], format!("/{{dots,defaults}}.{FILE_EXTENSIONS_GLOB}").as_str().pipe(Some)).unwrap();
30+
31+
let paths = WalkDir::new(dotfiles_path)
32+
.into_iter()
33+
.collect::<Result<Vec<_>, _>>()
34+
.map_err(Error::WalkingDotfiles)
35+
.map_err(Box::new)?;
36+
37+
let absolutized = paths
38+
.into_iter()
39+
.filter(|e| !e.file_type().is_dir())
40+
.map(|d| {
41+
let path = d.path().strip_prefix(dotfiles_path).map(Path::to_path_buf).map_err(Error::PathStrip)?;
42+
let absolutized = helpers::absolutize_virtually(&path).map_err(|e| Error::ParseName(path.to_string_lossy().to_string(), e))?;
43+
let absolutized_dir = helpers::absolutize_virtually(path.parent().unwrap()).map_err(|e| Error::ParseName(path.to_string_lossy().to_string(), e))?;
44+
Ok::<_, Error>((absolutized, absolutized_dir, path))
45+
})
46+
.collect::<Result<Vec<_>, _>>()
47+
.map_err(Box::new)?;
48+
49+
absolutized
50+
.into_iter()
51+
.filter(|e| defaults.is_match(e.0.as_str()))
52+
.map(|e| (e.1, e.2))
53+
.map(|e| {
54+
if e.1.file_name().unwrap().to_string_lossy().starts_with("dots.") {
55+
let path = e.1.to_string_lossy().to_string();
56+
println!(
57+
"Warning: {:?}",
58+
Report::new(Error::DotsDeprecated(
59+
e.1.extension().unwrap().to_string_lossy().to_string(),
60+
(path.rfind("dots").unwrap(), "dots".len()).into(),
61+
path
62+
))
63+
);
64+
}
65+
66+
(
67+
e.0,
68+
(
69+
fs::read_to_string(dotfiles_path.join(&e.1)).map_err(|err| Error::ReadingDot(e.1.clone(), err))?,
70+
FileFormat::try_from(e.1.as_path()).unwrap(),
71+
),
72+
)
73+
.pipe(Ok)
74+
})
75+
.collect::<Result<HashMap<_, _>, _>>()
76+
.map(Defaults)
77+
.map_err(Box::new)
78+
}
79+
}

0 commit comments

Comments
 (0)