feat: add info command line subcommand (#1330)
* feat: add `info` command line subcommand Adding an info command allows the documentation to refer to it when mentioning platform specific information. This gives users a nicer experience since they don't need to think about how `ncspot` will behave on their system, but can run `ncspot info` to get that information. * fix: info command don't create runtime directory * fix: don't print runtime path on Windows Windows doesn't use the runtime path so it shouldn't be printed there. * fix: make `info` command easier to parse * docs: add back the default configuration directory
This commit is contained in:
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- Special color for unavailable items
|
- Special color for unavailable items
|
||||||
- Changelog with all the relevant user-facing changes to the project
|
- Changelog with all the relevant user-facing changes to the project
|
||||||
|
- `info` command line subcommand to show platform specific information
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ ncspot is available on macOS (Homebrew), Windows (Scoop), Linux (native package
|
|||||||
BSD's. Detailed installation instructions for each platform can be found [here](/doc/users.md).
|
BSD's. Detailed installation instructions for each platform can be found [here](/doc/users.md).
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
A configuration file can be provided at `$XDG_CONFIG_HOME/ncspot/config.toml`. Detailed
|
A configuration file can be provided. The default location is `~/.config/ncspot`. Detailed
|
||||||
configuration information can be found [here](/doc/users.md#configuration).
|
configuration information can be found [here](/doc/users.md#configuration).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ and attach a debugger. On Linux this can be achieved with `gdb` or `lldb`. It is
|
|||||||
work. To disable it, execute `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`. This will allow
|
work. To disable it, execute `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`. This will allow
|
||||||
any process to inspect the memory of another process. It is automatically re-enabled after a reboot.
|
any process to inspect the memory of another process. It is automatically re-enabled after a reboot.
|
||||||
|
|
||||||
If ncspot has crashed you can find the latest backtrace at `~/.cache/ncspot/backtrace.log`.
|
If ncspot has crashed you can find the latest backtrace at `$NCSPOT_CACHE_DIRECTORY/backtrace.log`.
|
||||||
|
The cache directory can be shown by running `ncspot info`.
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
Compile and install the latest release with `cargo-install`:
|
Compile and install the latest release with `cargo-install`:
|
||||||
|
|||||||
26
doc/users.md
26
doc/users.md
@@ -181,14 +181,12 @@ Note: \<FOO\> - mandatory arg; [BAR] - optional arg
|
|||||||
|
|
||||||
## Remote control (IPC)
|
## Remote control (IPC)
|
||||||
Apart from MPRIS, ncspot will also create a domain socket on UNIX platforms (Linux, macOS, *BSD).
|
Apart from MPRIS, ncspot will also create a domain socket on UNIX platforms (Linux, macOS, *BSD).
|
||||||
The socket will be created in the platform's runtime directory. If XDG_RUNTIME_DIR is set, it will
|
The socket will be created in the platform's runtime directory. Run `ncspot info` to show the
|
||||||
be created under `$XDG_RUNTIME_DIR/ncspot`. If XDG_RUNTIME_DIR isn't set, it will be created under
|
location of this directory on your platform. Applications or scripts can connect to this socket to
|
||||||
`/run/user/<uid>` for Linux if it exists. In all other cases, it will be created under
|
send commands or be notified of the currently playing track, i.e. with `netcat`:
|
||||||
`/tmp/ncspot-<uid>`. Applications or scripts can connect to this socket to send commands or be
|
|
||||||
notified of the currently playing track, i.e. with `netcat`:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
% nc -U ~/.cache/ncspot/ncspot.sock
|
% nc -U $NCSPOT_CACHE_DIRECTORY/ncspot.sock
|
||||||
play
|
play
|
||||||
{"mode":{"Playing":{"secs_since_epoch":1672249086,"nanos_since_epoch":547517730}},"playable":{"type":"Track","id":"2wcrQZ7ZJolYEfIaPP9yL4","uri":"spotify:track:2wcrQZ7ZJolYEfIaPP9yL4","title":"Hit Me Where It Hurts","track_number":4,"disc_number":1,"duration":184132,"artists":["Caroline Polachek"],"artist_ids":["4Ge8xMJNwt6EEXOzVXju9a"],"album":"Pang","album_id":"4ClyeVlAKJJViIyfVW0yQD","album_artists":["Caroline Polachek"],"cover_url":"https://i.scdn.co/image/ab67616d0000b2737d983e7bf67c2806218c2759","url":"https://open.spotify.com/track/2wcrQZ7ZJolYEfIaPP9yL4","added_at":"2022-12-19T22:41:05Z","list_index":0}}
|
{"mode":{"Playing":{"secs_since_epoch":1672249086,"nanos_since_epoch":547517730}},"playable":{"type":"Track","id":"2wcrQZ7ZJolYEfIaPP9yL4","uri":"spotify:track:2wcrQZ7ZJolYEfIaPP9yL4","title":"Hit Me Where It Hurts","track_number":4,"disc_number":1,"duration":184132,"artists":["Caroline Polachek"],"artist_ids":["4Ge8xMJNwt6EEXOzVXju9a"],"album":"Pang","album_id":"4ClyeVlAKJJViIyfVW0yQD","album_artists":["Caroline Polachek"],"cover_url":"https://i.scdn.co/image/ab67616d0000b2737d983e7bf67c2806218c2759","url":"https://open.spotify.com/track/2wcrQZ7ZJolYEfIaPP9yL4","added_at":"2022-12-19T22:41:05Z","list_index":0}}
|
||||||
playpause
|
playpause
|
||||||
@@ -212,7 +210,7 @@ as they typically tend to keep the connection to the socket open. OpenBSD's
|
|||||||
specific number of packets have been received.
|
specific number of packets have been received.
|
||||||
|
|
||||||
```
|
```
|
||||||
% nc -W 1 -U ~/.cache/ncspot/ncspot.sock
|
% nc -W 1 -U $NCSPOT_CACHE_DIRECTORY/ncspot.sock
|
||||||
{"mode":{"Playing":{"secs_since_epoch":1675188934,"nanos_since_epoch":50913345}},"playable":{"type":"Track","id":"5Cp6a1h2VnuOtsh1Nqxfv6","uri":"spotify:track:5Cp6a1h2VnuOtsh1Nqxfv6","title":"New Track","track_number":1,"disc_number":1,"duration":498358,"artists":["Francis Bebey"],"artist_ids":["0mdmrbu5UZ32uRcRp2z6mr"],"album":"African Electronic Music (1975-1982)","album_id":"7w99Aae1tYSTSb1OiDnxYY","album_artists":["Francis Bebey"],"cover_url":"https://i.scdn.co/image/ab67616d0000b2736ab57cedf27177fae1eaed87","url":"https://open.spotify.com/track/5Cp6a1h2VnuOtsh1Nqxfv6","added_at":"2020-12-22T09:57:17Z","list_index":0}}
|
{"mode":{"Playing":{"secs_since_epoch":1675188934,"nanos_since_epoch":50913345}},"playable":{"type":"Track","id":"5Cp6a1h2VnuOtsh1Nqxfv6","uri":"spotify:track:5Cp6a1h2VnuOtsh1Nqxfv6","title":"New Track","track_number":1,"disc_number":1,"duration":498358,"artists":["Francis Bebey"],"artist_ids":["0mdmrbu5UZ32uRcRp2z6mr"],"album":"African Electronic Music (1975-1982)","album_id":"7w99Aae1tYSTSb1OiDnxYY","album_artists":["Francis Bebey"],"cover_url":"https://i.scdn.co/image/ab67616d0000b2736ab57cedf27177fae1eaed87","url":"https://open.spotify.com/track/5Cp6a1h2VnuOtsh1Nqxfv6","added_at":"2020-12-22T09:57:17Z","list_index":0}}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -221,17 +219,17 @@ For example, you can get the currently playing artist and title in your
|
|||||||
terminal as follows:
|
terminal as follows:
|
||||||
|
|
||||||
```
|
```
|
||||||
% nc -W 1 -U ~/.cache/ncspot/ncspot.sock | jq '.playable.title'
|
% nc -W 1 -U $NCSPOT_CACHE_DIRECTORY/ncspot.sock | jq '.playable.title'
|
||||||
"PUMPIN' JUMPIN'"
|
"PUMPIN' JUMPIN'"
|
||||||
|
|
||||||
% nc -W 1 -U ~/.cache/ncspot/ncspot.sock | jq '.playable.artists[0]'
|
% nc -W 1 -U $NCSPOT_CACHE_DIRECTORY/ncspot.sock | jq '.playable.artists[0]'
|
||||||
"Hideki Naganuma"
|
"Hideki Naganuma"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
Configuration is saved to `~/.config/ncspot/config.toml` (or
|
Configuration is saved to the `config.toml` file in the platform's standard configuration directory.
|
||||||
`%AppData%\ncspot\config.toml` on Windows). To reload the configuration during
|
Run `ncspot info` to show the location of this directory on your platform. To reload the
|
||||||
runtime use the `reload` command.
|
configuration during runtime use the `reload` command.
|
||||||
|
|
||||||
Possible configuration values are:
|
Possible configuration values are:
|
||||||
|
|
||||||
@@ -448,8 +446,8 @@ cover_max_scale = 2
|
|||||||
`ncspot` prompts for a Spotify username and password on first launch, uses this
|
`ncspot` prompts for a Spotify username and password on first launch, uses this
|
||||||
to generate an OAuth token, and stores it to disk.
|
to generate an OAuth token, and stores it to disk.
|
||||||
|
|
||||||
The credentials are stored in `~/.cache/ncspot/librespot/credentials.json`
|
The credentials are stored in `librespot/credentials.json` in the user's cache directory. Run
|
||||||
(unless the base path has been changed with the `--basepath` option).
|
`ncspot info` to show the location of this directory.
|
||||||
|
|
||||||
The `logout` command can be used to remove cached credentials. See
|
The `logout` command can be used to remove cached credentials. See
|
||||||
[Vim-Like Commands](#vim-like-commands).
|
[Vim-Like Commands](#vim-like-commands).
|
||||||
|
|||||||
35
src/cli.rs
Normal file
35
src/cli.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use crate::config::{user_cache_directory, user_configuration_directory};
|
||||||
|
|
||||||
|
/// Print platform info like which platform directories will be used.
|
||||||
|
pub fn info() -> Result<(), String> {
|
||||||
|
let user_configuration_directory = user_configuration_directory();
|
||||||
|
let user_cache_directory = user_cache_directory();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"USER_CONFIGURATION_PATH {}",
|
||||||
|
user_configuration_directory
|
||||||
|
.map(|path| path.to_string_lossy().to_string())
|
||||||
|
.unwrap_or("not found".into())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"USER_CACHE_PATH {}",
|
||||||
|
user_cache_directory
|
||||||
|
.map(|path| path.to_string_lossy().to_string())
|
||||||
|
.unwrap_or("not found".into())
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use crate::utils::user_runtime_directory;
|
||||||
|
|
||||||
|
let user_runtime_directory = user_runtime_directory();
|
||||||
|
println!(
|
||||||
|
"USER_RUNTIME_PATH {}",
|
||||||
|
user_runtime_directory
|
||||||
|
.map(|path| path.to_string_lossy().to_string())
|
||||||
|
.unwrap_or("not found".into())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use std::{fs, process};
|
|||||||
|
|
||||||
use cursive::theme::Theme;
|
use cursive::theme::Theme;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
|
use ncspot::CONFIGURATION_FILE_NAME;
|
||||||
use platform_dirs::AppDirs;
|
use platform_dirs::AppDirs;
|
||||||
|
|
||||||
use crate::command::{SortDirection, SortKey};
|
use crate::command::{SortDirection, SortKey};
|
||||||
@@ -192,7 +193,7 @@ impl Config {
|
|||||||
/// Generate the configuration from the user configuration file and the runtime state file.
|
/// Generate the configuration from the user configuration file and the runtime state file.
|
||||||
/// `filename` can be used to look for a differently named configuration file.
|
/// `filename` can be used to look for a differently named configuration file.
|
||||||
pub fn new(filename: Option<String>) -> Self {
|
pub fn new(filename: Option<String>) -> Self {
|
||||||
let filename = filename.unwrap_or("config.toml".to_owned());
|
let filename = filename.unwrap_or(CONFIGURATION_FILE_NAME.to_owned());
|
||||||
let values = load(&filename).unwrap_or_else(|e| {
|
let values = load(&filename).unwrap_or_else(|e| {
|
||||||
eprintln!("could not load config: {e}");
|
eprintln!("could not load config: {e}");
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
@@ -268,16 +269,6 @@ fn load(filename: &str) -> Result<ConfigValues, String> {
|
|||||||
TOML.load_or_generate_default(path, || Ok(ConfigValues::default()), false)
|
TOML.load_or_generate_default(path, || Ok(ConfigValues::default()), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the platform app directories for ncspot.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// This panics if the project directories could not be determined. Use `try_proj_dirs` for a
|
|
||||||
/// non-panicking version.
|
|
||||||
fn proj_dirs() -> AppDirs {
|
|
||||||
try_proj_dirs().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the plaform app directories for ncspot if they could be determined,
|
/// Returns the plaform app directories for ncspot if they could be determined,
|
||||||
/// or an error otherwise.
|
/// or an error otherwise.
|
||||||
pub fn try_proj_dirs() -> Result<AppDirs, String> {
|
pub fn try_proj_dirs() -> Result<AppDirs, String> {
|
||||||
@@ -296,19 +287,32 @@ pub fn try_proj_dirs() -> Result<AppDirs, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the path to the current user's configuration directory, or None if it couldn't be found.
|
||||||
|
/// This function does not guarantee correct permissions or ownership of the directory!
|
||||||
|
pub fn user_configuration_directory() -> Option<PathBuf> {
|
||||||
|
let project_directories = try_proj_dirs().ok()?;
|
||||||
|
Some(project_directories.config_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the path to the current user's cache directory, or None if one couldn't be found. This
|
||||||
|
/// function does not guarantee correct permissions or ownership of the directory!
|
||||||
|
pub fn user_cache_directory() -> Option<PathBuf> {
|
||||||
|
let project_directories = try_proj_dirs().ok()?;
|
||||||
|
Some(project_directories.cache_dir)
|
||||||
|
}
|
||||||
|
|
||||||
/// Force create the configuration directory at the default project location, removing anything that
|
/// Force create the configuration directory at the default project location, removing anything that
|
||||||
/// isn't a directory but has the same name. Return the path to the configuration file inside the
|
/// isn't a directory but has the same name. Return the path to the configuration file inside the
|
||||||
/// directory.
|
/// directory.
|
||||||
///
|
///
|
||||||
/// This doesn't create the file, only the containing directory.
|
/// This doesn't create the file, only the containing directory.
|
||||||
pub fn config_path(file: &str) -> PathBuf {
|
pub fn config_path(file: &str) -> PathBuf {
|
||||||
let proj_dirs = proj_dirs();
|
let cfg_dir = user_configuration_directory().unwrap();
|
||||||
let cfg_dir = &proj_dirs.config_dir;
|
|
||||||
if cfg_dir.exists() && !cfg_dir.is_dir() {
|
if cfg_dir.exists() && !cfg_dir.is_dir() {
|
||||||
fs::remove_file(cfg_dir).expect("unable to remove old config file");
|
fs::remove_file(&cfg_dir).expect("unable to remove old config file");
|
||||||
}
|
}
|
||||||
if !cfg_dir.exists() {
|
if !cfg_dir.exists() {
|
||||||
fs::create_dir_all(cfg_dir).expect("can't create config folder");
|
fs::create_dir_all(&cfg_dir).expect("can't create config folder");
|
||||||
}
|
}
|
||||||
let mut cfg = cfg_dir.to_path_buf();
|
let mut cfg = cfg_dir.to_path_buf();
|
||||||
cfg.push(file);
|
cfg.push(file);
|
||||||
@@ -320,10 +324,9 @@ pub fn config_path(file: &str) -> PathBuf {
|
|||||||
///
|
///
|
||||||
/// This doesn't create the file, only the containing directory.
|
/// This doesn't create the file, only the containing directory.
|
||||||
pub fn cache_path(file: &str) -> PathBuf {
|
pub fn cache_path(file: &str) -> PathBuf {
|
||||||
let proj_dirs = proj_dirs();
|
let cache_dir = user_cache_directory().unwrap();
|
||||||
let cache_dir = &proj_dirs.cache_dir;
|
|
||||||
if !cache_dir.exists() {
|
if !cache_dir.exists() {
|
||||||
fs::create_dir_all(cache_dir).expect("can't create cache folder");
|
fs::create_dir_all(&cache_dir).expect("can't create cache folder");
|
||||||
}
|
}
|
||||||
let mut pb = cache_dir.to_path_buf();
|
let mut pb = cache_dir.to_path_buf();
|
||||||
pb.push(file);
|
pb.push(file);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use librespot_playback::audio_backend;
|
|||||||
|
|
||||||
pub const AUTHOR: &str = "Henrik Friedrichsen <henrik@affekt.org> and contributors";
|
pub const AUTHOR: &str = "Henrik Friedrichsen <henrik@affekt.org> and contributors";
|
||||||
pub const BIN_NAME: &str = "ncspot";
|
pub const BIN_NAME: &str = "ncspot";
|
||||||
|
pub const CONFIGURATION_FILE_NAME: &str = "config.toml";
|
||||||
|
|
||||||
/// Return the [Command](clap::Command) that models the program's command line arguments. The
|
/// Return the [Command](clap::Command) that models the program's command line arguments. The
|
||||||
/// command can be used to parse the actual arguments passed to the program, or to automatically
|
/// command can be used to parse the actual arguments passed to the program, or to automatically
|
||||||
@@ -40,6 +41,7 @@ pub fn program_arguments() -> clap::Command {
|
|||||||
.long("config")
|
.long("config")
|
||||||
.value_name("FILE")
|
.value_name("FILE")
|
||||||
.help("Filename of config file in basepath")
|
.help("Filename of config file in basepath")
|
||||||
.default_value("config.toml"),
|
.default_value(CONFIGURATION_FILE_NAME),
|
||||||
)
|
)
|
||||||
|
.subcommands([clap::Command::new("info").about("Print platform information like paths")])
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/main.rs
15
src/main.rs
@@ -13,6 +13,7 @@ use ncspot::program_arguments;
|
|||||||
|
|
||||||
mod application;
|
mod application;
|
||||||
mod authentication;
|
mod authentication;
|
||||||
|
mod cli;
|
||||||
mod command;
|
mod command;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod config;
|
mod config;
|
||||||
@@ -56,9 +57,15 @@ fn main() -> Result<(), String> {
|
|||||||
// path.
|
// path.
|
||||||
set_configuration_base_path(matches.get_one::<PathBuf>("basepath").cloned());
|
set_configuration_base_path(matches.get_one::<PathBuf>("basepath").cloned());
|
||||||
|
|
||||||
// Create the application.
|
match matches.subcommand() {
|
||||||
let mut application = Application::new(matches.get_one::<String>("config").cloned())?;
|
Some(("info", _subcommand_matches)) => cli::info(),
|
||||||
|
Some((_, _)) => unreachable!(),
|
||||||
|
None => {
|
||||||
|
// Create the application.
|
||||||
|
let mut application = Application::new(matches.get_one::<String>("config").cloned())?;
|
||||||
|
|
||||||
// Start the application event loop.
|
// Start the application event loop.
|
||||||
application.run()
|
application.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use cursive::utils::markup::StyledString;
|
|||||||
use cursive::view::ViewWrapper;
|
use cursive::view::ViewWrapper;
|
||||||
use cursive::views::{ScrollView, TextView};
|
use cursive::views::{ScrollView, TextView};
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use ncspot::CONFIGURATION_FILE_NAME;
|
||||||
|
|
||||||
use crate::command::{Command, MoveAmount, MoveMode};
|
use crate::command::{Command, MoveAmount, MoveMode};
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
@@ -22,7 +23,9 @@ impl HelpView {
|
|||||||
|
|
||||||
let note = format!(
|
let note = format!(
|
||||||
"Custom bindings can be set in {} within the [keybindings] section.\n\n",
|
"Custom bindings can be set in {} within the [keybindings] section.\n\n",
|
||||||
config_path("config.toml").to_str().unwrap_or_default()
|
config_path(CONFIGURATION_FILE_NAME)
|
||||||
|
.to_str()
|
||||||
|
.unwrap_or_default()
|
||||||
);
|
);
|
||||||
text.append(StyledString::styled(note, Effect::Italic));
|
text.append(StyledString::styled(note, Effect::Italic));
|
||||||
|
|
||||||
|
|||||||
34
src/utils.rs
34
src/utils.rs
@@ -72,20 +72,7 @@ pub fn create_runtime_directory() -> Result<PathBuf, Box<dyn std::error::Error>>
|
|||||||
os::unix::prelude::PermissionsExt,
|
os::unix::prelude::PermissionsExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
let linux_runtime_directory =
|
let user_runtime_directory = user_runtime_directory().ok_or("no runtime directory found")?;
|
||||||
PathBuf::from(format!("/run/user/{}/", unsafe { libc::getuid() }));
|
|
||||||
let unix_runtime_directory = PathBuf::from("/tmp/");
|
|
||||||
|
|
||||||
let user_runtime_directory = if let Some(xdg_runtime_directory) = xdg_runtime_directory() {
|
|
||||||
Some(xdg_runtime_directory.join("ncspot"))
|
|
||||||
} else if cfg!(linux) && linux_runtime_directory.exists() {
|
|
||||||
Some(linux_runtime_directory.join("ncspot"))
|
|
||||||
} else if unix_runtime_directory.exists() {
|
|
||||||
Some(unix_runtime_directory.join(format!("ncspot-{}", unsafe { libc::getuid() })))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
.ok_or("no runtime directory found")?;
|
|
||||||
|
|
||||||
let creation_result = fs::create_dir(&user_runtime_directory);
|
let creation_result = fs::create_dir(&user_runtime_directory);
|
||||||
|
|
||||||
@@ -106,6 +93,25 @@ pub fn create_runtime_directory() -> Result<PathBuf, Box<dyn std::error::Error>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the path to the current user's runtime directory, or None if it couldn't be found.
|
||||||
|
/// This function does not guarantee correct ownership or permissions of the directory.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn user_runtime_directory() -> Option<PathBuf> {
|
||||||
|
let linux_runtime_directory =
|
||||||
|
PathBuf::from(format!("/run/user/{}/", unsafe { libc::getuid() }));
|
||||||
|
let unix_runtime_directory = PathBuf::from("/tmp/");
|
||||||
|
|
||||||
|
if let Some(xdg_runtime_directory) = xdg_runtime_directory() {
|
||||||
|
Some(xdg_runtime_directory.join("ncspot"))
|
||||||
|
} else if cfg!(linux) && linux_runtime_directory.exists() {
|
||||||
|
Some(linux_runtime_directory.join("ncspot"))
|
||||||
|
} else if unix_runtime_directory.exists() {
|
||||||
|
Some(unix_runtime_directory.join(format!("ncspot-{}", unsafe { libc::getuid() })))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn xdg_runtime_directory() -> Option<PathBuf> {
|
fn xdg_runtime_directory() -> Option<PathBuf> {
|
||||||
std::env::var("XDG_RUNTIME_DIR").ok().map(Into::into)
|
std::env::var("XDG_RUNTIME_DIR").ok().map(Into::into)
|
||||||
|
|||||||
Reference in New Issue
Block a user