1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
use {
super::ShellInstall,
crate::{
cli,
conf,
errors::*,
},
std::{
fs,
path::PathBuf,
},
};
/// must be incremented when the architecture changes or one of the shell
/// specific scripts is upgraded to a new version
const CURRENT_VERSION: usize = 4;
const REFUSED_FILE_CONTENT: &str = r#"
This file tells broot you refused the installation of the companion shell function.
If you want to install it run
broot -- install
"#;
const INSTALLED_FILE_CONTENT: &str = r#"
This file tells broot the installation of the br function was done.
If there's a problem and you want to install it again run
broot -- install
"#;
#[derive(Debug, Clone, Copy, clap::ValueEnum)]
pub enum ShellInstallState {
NotInstalled, // before any install, this is the initial state
Refused, // user doesn't want anything to be installed
Obsolete,
UpToDate,
}
impl From<cli::CliShellInstallState> for ShellInstallState {
fn from(cs: cli::CliShellInstallState) -> Self {
match cs {
cli::CliShellInstallState::Undefined => Self::NotInstalled,
cli::CliShellInstallState::Refused => Self::Refused,
cli::CliShellInstallState::Installed => Self::UpToDate,
}
}
}
impl ShellInstallState {
pub fn get_refused_path() -> PathBuf {
conf::dir().join("launcher").join("refused")
}
pub fn get_installed_path(version: usize) -> PathBuf {
conf::dir().join("launcher").join(format!("installed-v{version}"))
}
pub fn detect() -> Self {
let current = Self::get_installed_path(CURRENT_VERSION);
if current.exists() {
return Self::UpToDate;
}
if Self::get_refused_path().exists() {
return Self::Refused;
}
for version in 0..CURRENT_VERSION {
let installed = Self::get_installed_path(version);
if installed.exists() {
return Self::Obsolete;
}
}
Self::NotInstalled
}
pub fn remove(si: &ShellInstall) -> Result<(), ShellInstallError> {
si.remove(&Self::get_refused_path())?;
for version in 0..=CURRENT_VERSION {
let installed = Self::get_installed_path(version);
si.remove(&installed)?;
}
Ok(())
}
/// write either the "installed" or the "refused" file, or remove
/// those files.
///
/// This is useful in installation
/// or test scripts when we don't want the user to be prompted
/// to install the function, or in case something doesn't properly
/// work in shell detections
pub fn write(self, si: &ShellInstall) -> Result<(), ShellInstallError> {
Self::remove(si)?;
match self {
ShellInstallState::Refused => {
let refused_path = Self::get_refused_path();
fs::create_dir_all(refused_path.parent().unwrap())
.context(&|| format!("creating parents of {refused_path:?}"))?;
fs::write(&refused_path, REFUSED_FILE_CONTENT)
.context(&|| format!("writing in {refused_path:?}"))?;
}
ShellInstallState::UpToDate => {
let installed_path = Self::get_installed_path(CURRENT_VERSION);
fs::create_dir_all(installed_path.parent().unwrap())
.context(&|| format!("creating parents of {installed_path:?}"))?;
fs::write(&installed_path, INSTALLED_FILE_CONTENT)
.context(&|| format!("writing in {installed_path:?}"))?;
}
_ => {
warn!("not writing state {self:?}");
}
}
Ok(())
}
}
|