Skip to content

Commit

Permalink
Use XDG directories by default
Browse files Browse the repository at this point in the history
Fallback to the old directory and log a deprecation warning.
  • Loading branch information
rossmacarthur committed Oct 13, 2022
1 parent 708bd9e commit c3f87dd
Show file tree
Hide file tree
Showing 48 changed files with 239 additions and 185 deletions.
51 changes: 20 additions & 31 deletions README.md
Expand Up @@ -144,16 +144,17 @@ or
sheldon init --shell zsh
```

This will create `plugins.toml` under `~/.sheldon` or, if defined,
`$XDG_CONFIG_HOME/sheldon`. You can either edit this file directly or use the
provided command line interface to add or remove plugins.
This will create `plugins.toml` under `$XDG_CONFIG_HOME/sheldon`, on most
systems this will be `~/.config/sheldon/plugins.toml`. You can either edit this
file directly or use the provided command line interface to add or remove
plugins.

### Adding a plugin

To add your first plugin append the following to the Sheldon config file.

```toml
# ~/.sheldon/plugins.toml
# ~/.config/sheldon/plugins.toml

[plugins.base16]
github = "chriskempson/base16-shell"
Expand Down Expand Up @@ -217,10 +218,10 @@ sheldon init --shell zsh

### `lock`

The `lock` command installs the plugins sources and generates the lock file
(`~/.sheldon/plugins.lock`). Rerunning this command without any extra options
will not reinstall plugin sources, just verify that they are correctly
installed. It will always regenerate the lock file.
The `lock` command installs the plugins sources and generates the lock file.
Rerunning this command without any extra options will not reinstall plugin
sources, just verify that they are correctly installed. It will always
regenerate the lock file.

```sh
sheldon lock
Expand Down Expand Up @@ -324,20 +325,15 @@ be required if you are using an obscure operating system.

*Environment variable:* `SHELDON_CONFIG_DIR`

Set the config directory where config will store the configuration file. If
Sheldon detects an XDG directory structure ([as described
below](#xdg-directory-structure)) then this will default to
`XDG_CONFIG_HOME/sheldon` otherwise it will default to `<home>/.sheldon` where
`<home>` is the users home directory.
Set the config directory where the configuration file will be stored. This
defaults to `$XDG_CONFIG_HOME/sheldon` or `~/.config/sheldon`.

##### `--data-dir <path>`

*Environment variable:* `SHELDON_DATA_DIR`

Set the data directory where plugins will be downloaded to. If Sheldon detects
an XDG directory structure ([as described below](#xdg-directory-structure)) then
this will default to `XDG_DATA_HOME/sheldon` otherwise it will default to
`<home>/.sheldon` where `<home>` is the users home directory.
Set the data directory where plugins will be downloaded to. This defaults to
`$XDG_DATA_HOME/sheldon` or `~/.local/share/sheldon`.

##### `--config-file <path>`

Expand Down Expand Up @@ -400,7 +396,7 @@ location of the source. There are three types of sources, each kind is described
in this section. A plugin may only specify *one* source type.

```toml
# ~/.sheldon/plugins.toml
# ~/.config/sheldon/plugins.toml

# ┌─ Unique name for the plugin
# ┌──┴─┐
Expand Down Expand Up @@ -588,11 +584,10 @@ plugins.

#### `profiles`

A list of profiles this plugin should be used in. If this field is not given
the plugin will be used regardless of the profile. Otherwise, the plugin is
only used if the specified
[profile](https://sheldon.cli.rs/Command-line-interface.html#--profile-profile) is included in the
configured list of profiles.
A list of profiles this plugin should be used in. If this field is not given the
plugin will be used regardless of the profile. Otherwise, the plugin is only
used if the specified [profile](https://sheldon.cli.rs/Command-line-interface.html#--profile-profile) is
included in the configured list of profiles.

### Inline plugins

Expand Down Expand Up @@ -643,10 +638,6 @@ github = "owner/repo"
apply = ["PATH", "fpath"]
```

The `each` value, as used in the `source` template above, specifies that the
template should be applied to each matched file for the plugin. This defaults to
`false`.

#### Custom templates

It is possible to create your own custom templates, and you can even override
Expand All @@ -664,10 +655,8 @@ Plugins all have the following information that can be used in templates.

* **One or more files.** These are the matched files in the plugin directory
either discovered using the the global `match` field or specified as a plugin
option with `use`. These can be used in templates using `{{ file }}`. This
information only makes sense in templates with `each` set to `true`.

* **The Sheldon data directory.** This directory can be used as `{{ data_dir }}`.
option with `use`. These can be used in templates by iterating over the files.
For example: `{% for file in files %} ... {{ file }} ... {% endfor %}`.

To add or update a template add a new key to the `[templates]` table in the
config file. Take a look at the [examples](https://sheldon.cli.rs/Examples.html) for some interesting
Expand Down
21 changes: 8 additions & 13 deletions docs/src/Command-line-interface.md
Expand Up @@ -33,10 +33,10 @@ sheldon init --shell zsh

## `lock`

The `lock` command installs the plugins sources and generates the lock file
(`~/.sheldon/plugins.lock`). Rerunning this command without any extra options
will not reinstall plugin sources, just verify that they are correctly
installed. It will always regenerate the lock file.
The `lock` command installs the plugins sources and generates the lock file.
Rerunning this command without any extra options will not reinstall plugin
sources, just verify that they are correctly installed. It will always
regenerate the lock file.

```sh
sheldon lock
Expand Down Expand Up @@ -140,20 +140,15 @@ be required if you are using an obscure operating system.

*Environment variable:* `SHELDON_CONFIG_DIR`

Set the config directory where config will store the configuration file. If
Sheldon detects an XDG directory structure ([as described
below](#xdg-directory-structure)) then this will default to
`XDG_CONFIG_HOME/sheldon` otherwise it will default to `<home>/.sheldon` where
`<home>` is the users home directory.
Set the config directory where the configuration file will be stored. This
defaults to `$XDG_CONFIG_HOME/sheldon` or `~/.config/sheldon`.

#### `--data-dir <path>`

*Environment variable:* `SHELDON_DATA_DIR`

Set the data directory where plugins will be downloaded to. If Sheldon detects
an XDG directory structure ([as described below](#xdg-directory-structure)) then
this will default to `XDG_DATA_HOME/sheldon` otherwise it will default to
`<home>/.sheldon` where `<home>` is the users home directory.
Set the data directory where plugins will be downloaded to. This defaults to
`$XDG_DATA_HOME/sheldon` or `~/.local/share/sheldon`.

#### `--config-file <path>`

Expand Down
21 changes: 7 additions & 14 deletions docs/src/Configuration.md
Expand Up @@ -9,7 +9,7 @@ location of the source. There are three types of sources, each kind is described
in this section. A plugin may only specify *one* source type.

```toml
# ~/.sheldon/plugins.toml
# ~/.config/sheldon/plugins.toml

# ┌─ Unique name for the plugin
# ┌──┴─┐
Expand Down Expand Up @@ -197,11 +197,10 @@ plugins.

### `profiles`

A list of profiles this plugin should be used in. If this field is not given
the plugin will be used regardless of the profile. Otherwise, the plugin is
only used if the specified
[profile](Command-line-interface.md#--profile-profile) is included in the
configured list of profiles.
A list of profiles this plugin should be used in. If this field is not given the
plugin will be used regardless of the profile. Otherwise, the plugin is only
used if the specified [profile](Command-line-interface.md#--profile-profile) is
included in the configured list of profiles.

## Inline plugins

Expand Down Expand Up @@ -252,10 +251,6 @@ github = "owner/repo"
apply = ["PATH", "fpath"]
```

The `each` value, as used in the `source` template above, specifies that the
template should be applied to each matched file for the plugin. This defaults to
`false`.

### Custom templates

It is possible to create your own custom templates, and you can even override
Expand All @@ -273,10 +268,8 @@ Plugins all have the following information that can be used in templates.

* **One or more files.** These are the matched files in the plugin directory
either discovered using the the global `match` field or specified as a plugin
option with `use`. These can be used in templates using `{{ file }}`. This
information only makes sense in templates with `each` set to `true`.

* **The Sheldon data directory.** This directory can be used as `{{ data_dir }}`.
option with `use`. These can be used in templates by iterating over the files.
For example: `{% for file in files %} ... {{ file }} ... {% endfor %}`.

To add or update a template add a new key to the `[templates]` table in the
config file. Take a look at the [examples](Examples.md) for some interesting
Expand Down
2 changes: 1 addition & 1 deletion docs/src/Examples.md
Expand Up @@ -82,7 +82,7 @@ Add the following to your `~/.zshrc` file.
```sh
# ~/.zshrc

export ZSH="$HOME/.sheldon/repos/github.com/ohmyzsh/ohmyzsh"
export ZSH="$HOME/.local/share/sheldon/repos/github.com/ohmyzsh/ohmyzsh"

# Oh My Zsh settings here

Expand Down
9 changes: 5 additions & 4 deletions docs/src/Getting-started.md
Expand Up @@ -16,16 +16,17 @@ or
sheldon init --shell zsh
```

This will create `plugins.toml` under `~/.sheldon` or, if defined,
`$XDG_CONFIG_HOME/sheldon`. You can either edit this file directly or use the
provided command line interface to add or remove plugins.
This will create `plugins.toml` under `$XDG_CONFIG_HOME/sheldon`, on most
systems this will be `~/.config/sheldon/plugins.toml`. You can either edit this
file directly or use the provided command line interface to add or remove
plugins.

## Adding a plugin

To add your first plugin append the following to the Sheldon config file.

```toml
# ~/.sheldon/plugins.toml
# ~/.config/sheldon/plugins.toml

[plugins.base16]
github = "chriskempson/base16-shell"
Expand Down
91 changes: 61 additions & 30 deletions src/cli/mod.rs
Expand Up @@ -8,7 +8,7 @@ mod tests;

use std::env;
use std::io;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process;

use anyhow::anyhow;
Expand Down Expand Up @@ -135,35 +135,7 @@ impl Opt {
}
};

let xdg_config_user = env::var_os("XDG_CONFIG_HOME").map(PathBuf::from);
let xdg_data_user = env::var_os("XDG_DATA_HOME").map(PathBuf::from);

// Note: `XDG_RUNTIME_DIR` is not checked as it can be set by the system rather
// than the user, and cannot be relied upon to indicate a preference for XDG
// directory layout.
let using_xdg = any!(
xdg_data_user,
xdg_config_user,
env::var_os("XDG_CACHE_HOME"),
env::var_os("XDG_DATA_DIRS"),
env::var_os("XDG_CONFIG_DIRS")
);

let (config_pre, data_pre) = if using_xdg {
(
xdg_config_user
.unwrap_or_else(|| home.join(".config"))
.join("sheldon"),
xdg_data_user
.unwrap_or_else(|| home.join(".local/share"))
.join("sheldon"),
)
} else {
(home.join(".sheldon"), home.join(".sheldon"))
};

let config_dir = config_dir.unwrap_or(config_pre);
let data_dir = data_dir.unwrap_or(data_pre);
let (config_dir, data_dir) = resolve_dirs(&home, config_dir, data_dir, output.no_color);
let config_file = config_file.unwrap_or_else(|| config_dir.join("plugins.toml"));
let lock_file = match profile.as_deref() {
Some("") | None => data_dir.join("plugins.lock"),
Expand Down Expand Up @@ -260,3 +232,62 @@ impl LockMode {
}
}
}

fn resolve_dirs(
home: &Path,
config_dir: Option<PathBuf>,
data_dir: Option<PathBuf>,
no_color: bool,
) -> (PathBuf, PathBuf) {
// TODO: Remove this warning in a later release and stop falling back to
// the old directory.
let err = anyhow!(
r#"using deprecated config file location ~/.sheldon/plugins.toml.
To use the new location move the config file to
~/.config/sheldon/plugins.toml ($XDG_CONFIG_HOME/sheldon/plugins.toml),
~/.sheldon can then be safely deleted.
Or to instead preserve the old behaviour set the following environment variables:
SHELDON_CONFIG_DIR="$HOME/.sheldon"
SHELDON_DATA_DIR="$HOME/.sheldon"
See the release notes at https://github.com/rossmacarthur/sheldon for more information.
"#,
);
let mut using_old = false;
let config_dir = config_dir.unwrap_or_else(|| {
let default = default_config_dir(home);
let old = home.join(".sheldon");
if old.exists() && !default.exists() {
log_error(no_color, Color::Yellow, "warning", &err);
using_old = true;
return old;
}
default
});
let data_dir = data_dir.unwrap_or_else(|| {
let default = default_data_dir(home);
if using_old && !default.exists() {
return config_dir.clone();
}
default
});
(config_dir, data_dir)
}

fn default_config_dir(home: &Path) -> PathBuf {
let mut p = env::var_os("XDG_CONFIG_HOME")
.map(PathBuf::from)
.unwrap_or_else(|| home.join(".config"));
p.push("sheldon");
p
}

fn default_data_dir(home: &Path) -> PathBuf {
let mut p = env::var_os("XDG_DATA_HOME")
.map(PathBuf::from)
.unwrap_or_else(|| home.join(".local/share"));
p.push("sheldon");
p
}
6 changes: 0 additions & 6 deletions src/macros.rs
Expand Up @@ -5,12 +5,6 @@ macro_rules! s {
($fmt:expr, $($arg:tt)+) => (|| format!($fmt, $($arg)+))
}

/// Evaluates a sequence of Options to see if any is a `Some`.
macro_rules! any {
($opt:expr) => { $opt.is_some() };
($opt:expr, $($rest:expr),+) => { $opt.is_some() || { any!($($rest),+) }};
}

/// Call .into() on each element in a vec! initialization.
macro_rules! vec_into {
($($i:expr),*) => (vec![$($i.into()),*]);
Expand Down
4 changes: 0 additions & 4 deletions tests/helpers/dirs.rs
Expand Up @@ -22,10 +22,6 @@ impl TestDirs {
}

pub fn default() -> io::Result<Self> {
Self::new(".sheldon", ".sheldon")
}

pub fn default_xdg() -> io::Result<Self> {
Self::new(".config/sheldon", ".local/share/sheldon")
}

Expand Down
8 changes: 8 additions & 0 deletions tests/helpers/process.rs
Expand Up @@ -88,6 +88,14 @@ impl TestCommand {
self
}

pub fn env_remove<K>(mut self, key: K) -> Self
where
K: AsRef<OsStr>,
{
self.command.env_remove(key);
self
}

pub fn envs<I, K, V>(mut self, vars: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
Expand Down

0 comments on commit c3f87dd

Please sign in to comment.