+14
src/apply.rs
+14
src/apply.rs
···
6
6
use crate::{
7
7
command::{run_command, run_command_without_local_path},
8
8
config::SshConfig,
9
+
git::extract_version,
9
10
};
10
11
11
12
#[derive(Debug)]
···
419
420
repo.to_string()
420
421
};
421
422
423
+
let (repo, version) = extract_version(&repo);
424
+
422
425
let home = dirs::home_dir().ok_or_else(|| Error::msg("Failed to get home directory"))?;
423
426
424
427
if !Path::new(&home.join(".dotfiles")).exists() {
425
428
run_command("bash", &["-c", &format!("git clone {} ~/.dotfiles", repo)])
426
429
.context("Failed to clone dotfiles repository")?;
427
430
} else {
431
+
run_command("bash", &["-c", "git -C ~/.dotfiles pull"])
432
+
.context("Failed to update dotfiles repository")?;
433
+
}
434
+
435
+
if let Some(version) = version {
436
+
run_command("bash", &["-c", "git -C ~/.dotfiles fetch --all"])?;
437
+
run_command(
438
+
"bash",
439
+
&["-c", &format!("git -C ~/.dotfiles checkout {}", version)],
440
+
)
441
+
.context("Failed to checkout dotfiles version")?;
428
442
run_command("bash", &["-c", "git -C ~/.dotfiles pull"])
429
443
.context("Failed to update dotfiles repository")?;
430
444
}
+73
-45
src/cmd/setup.rs
+73
-45
src/cmd/setup.rs
···
2
2
3
3
use anyhow::{Context, Error};
4
4
use owo_colors::OwoColorize;
5
-
use url::Url;
6
5
7
6
use crate::{
8
-
command::run_command, config::Configuration, consts::CONFIG_FILE, diff::compare_configurations,
7
+
command::run_command,
8
+
config::Configuration,
9
+
consts::CONFIG_FILE,
10
+
diff::compare_configurations,
11
+
git::{extract_repo_name, extract_version},
9
12
};
10
13
11
14
pub fn setup(dry_run: bool, no_confirm: bool, config_path: &str) -> Result<(), Error> {
12
15
let mut cfg = Configuration::default();
13
16
14
17
let repo_url = parse_config_path(config_path)?;
18
+
let (repo_url, version) = match repo_url.starts_with("https://") {
19
+
true => extract_version(&repo_url),
20
+
false => (repo_url, None),
21
+
};
15
22
16
-
let toml_config = match clone_repo(&repo_url) {
23
+
let toml_config = match clone_repo(&repo_url, version) {
17
24
Ok(toml_config) => toml_config,
18
25
Err(err) => {
19
26
if !repo_url.starts_with("https://") {
···
92
99
fn parse_config_path(config_path: &str) -> Result<String, Error> {
93
100
if config_path.starts_with("github:") {
94
101
let repo = &config_path["github:".len()..];
95
-
return Ok(format!("https://github.com/{}.git", repo));
102
+
return Ok(format!("https://github.com/{}", repo));
96
103
}
97
104
98
105
if config_path.starts_with("tangled:") {
···
103
110
Ok(config_path.to_string())
104
111
}
105
112
106
-
fn clone_repo(repo_url: &str) -> Result<String, Error> {
113
+
fn clone_repo(repo_url: &str, version: Option<String>) -> Result<String, Error> {
107
114
if !repo_url.starts_with("https://") {
108
115
return Err(anyhow::anyhow!(
109
116
"Unsupported repository URL. Only HTTPS URLs are supported."
···
127
134
run_command("git", &["-C", dest.to_str().unwrap(), "pull"])?;
128
135
}
129
136
false => {
130
-
run_command(
131
-
"git",
132
-
&["clone", "--depth", "1", repo_url, dest.to_str().unwrap()],
133
-
)?;
137
+
run_command("git", &["clone", repo_url, dest.to_str().unwrap()])?;
134
138
}
135
139
}
136
140
141
+
if version.is_some() {
142
+
run_command("git", &["-C", dest.to_str().unwrap(), "fetch", "--all"])?;
143
+
run_command(
144
+
"git",
145
+
&[
146
+
"-C",
147
+
dest.to_str().unwrap(),
148
+
"checkout",
149
+
version.as_ref().unwrap(),
150
+
],
151
+
)?;
152
+
}
153
+
137
154
if !dest.join("oh-my-droid.toml").exists() {
138
155
return Err(anyhow::anyhow!(
139
156
"The repository does not contain an oh-my-droid.toml configuration file."
···
143
160
Ok(dest.join("oh-my-droid.toml").to_str().unwrap().to_string())
144
161
}
145
162
146
-
fn extract_repo_name(url: &str) -> Option<String> {
147
-
let parsed = Url::parse(url).ok()?;
148
-
let mut segments = parsed.path_segments()?;
149
-
let username = segments.next()?;
150
-
let mut repo = segments.next()?;
151
-
152
-
if let Some(stripped) = repo.strip_suffix(".git") {
153
-
repo = stripped;
154
-
}
155
-
156
-
Some(format!("{}-{}", username, repo))
157
-
}
158
-
159
163
#[cfg(test)]
160
164
mod tests {
165
+
use crate::git::extract_version;
166
+
161
167
use super::*;
162
168
163
169
#[test]
164
-
fn test_extract_repo_name() {
165
-
let url = "https://github.com/tsirysndr/pkgs.git";
166
-
let expected = Some("tsirysndr-pkgs".into());
167
-
let result = extract_repo_name(url);
170
+
fn test_parse_config_path_github() {
171
+
let path = "github:tsirysndr/pkgs";
172
+
let expected = Some("https://github.com/tsirysndr/pkgs".into());
173
+
let result = parse_config_path(path).ok();
168
174
assert_eq!(result, expected);
169
175
}
170
176
171
177
#[test]
172
-
fn test_extract_repo_name_no_git() {
173
-
let url = "https://github.com/tsirysndr/pkgs";
174
-
let expected = Some("tsirysndr-pkgs".into());
175
-
let result = extract_repo_name(url);
178
+
fn test_parse_config_path_tangled() {
179
+
let path = "tangled:@tsirysandratraina/pkgs";
180
+
let expected = Some("https://tangled.sh/@tsirysandratraina/pkgs".into());
181
+
let result = parse_config_path(path).ok();
182
+
assert_eq!(result, expected);
183
+
}
184
+
185
+
#[test]
186
+
fn test_parse_config_path_git_url() {
187
+
let path = "https://github.com/tsirysndr/pkgs@main";
188
+
let expected = Some("https://github.com/tsirysndr/pkgs@main".into());
189
+
let result = parse_config_path(path).ok();
176
190
assert_eq!(result, expected);
177
191
}
178
192
179
193
#[test]
180
-
fn test_extract_repo_name_invalid_url() {
181
-
let url = "invalid-url";
182
-
let expected = None;
183
-
let result = extract_repo_name(url);
194
+
fn test_extract_version() {
195
+
let url = "https://tangled.sh/@tsirysandratraina/pkgs@main";
196
+
let expected = (
197
+
"https://tangled.sh/@tsirysandratraina/pkgs".into(),
198
+
Some("main".into()),
199
+
);
200
+
let result = extract_version(url);
201
+
assert_eq!(result, expected);
202
+
}
203
+
204
+
#[test]
205
+
fn test_extract_version_2() {
206
+
let url = "https://tangled.sh/@tsirysandratraina/pkgs";
207
+
let expected = ("https://tangled.sh/@tsirysandratraina/pkgs".into(), None);
208
+
let result = extract_version(url);
184
209
assert_eq!(result, expected);
185
210
}
186
211
187
212
#[test]
188
-
fn test_parse_config_path_github() {
189
-
let path = "github:tsirysndr/pkgs";
190
-
let expected = Some("https://github.com/tsirysndr/pkgs.git".into());
191
-
let result = parse_config_path(path).ok();
213
+
fn test_extract_version_3() {
214
+
let url = "https://github.com/tsirysndr/pkgs";
215
+
let expected = ("https://github.com/tsirysndr/pkgs".into(), None);
216
+
let result = extract_version(url);
192
217
assert_eq!(result, expected);
193
218
}
194
219
195
220
#[test]
196
-
fn test_parse_config_path_tangled() {
197
-
let path = "tangled:@tsirysandratraina/pkgs";
198
-
let expected = Some("https://tangled.sh/@tsirysandratraina/pkgs".into());
199
-
let result = parse_config_path(path).ok();
221
+
fn test_extract_version_4() {
222
+
let url = "https://github.com/tsirysndr/pkgs@main";
223
+
let expected = (
224
+
"https://github.com/tsirysndr/pkgs".into(),
225
+
Some("main".into()),
226
+
);
227
+
let result = extract_version(url);
200
228
assert_eq!(result, expected);
201
229
}
202
230
203
231
#[test]
204
-
fn test_parse_config_path_git_url() {
205
-
let path = "https://github.com/tsirysndr/pkgs.git";
206
-
let expected = Some("https://github.com/tsirysndr/pkgs.git".into());
232
+
fn test_parse_config_path_github_with_branch() {
233
+
let path = "github:tsirysndr/pkgs@main";
234
+
let expected = Some("https://github.com/tsirysndr/pkgs@main".into());
207
235
let result = parse_config_path(path).ok();
208
236
assert_eq!(result, expected);
209
237
}
+59
src/git.rs
+59
src/git.rs
···
1
+
use url::Url;
2
+
3
+
pub fn extract_repo_name(url: &str) -> Option<String> {
4
+
let parsed = Url::parse(url).ok()?;
5
+
let mut segments = parsed.path_segments()?;
6
+
let username = segments.next()?;
7
+
let mut repo = segments.next()?;
8
+
9
+
if let Some(stripped) = repo.strip_suffix(".git") {
10
+
repo = stripped;
11
+
}
12
+
13
+
Some(format!("{}-{}", username, repo))
14
+
}
15
+
16
+
pub fn extract_version(url: &str) -> (String, Option<String>) {
17
+
let repo_name = url.replace("https://tangled.sh/", "").replace("@", "");
18
+
match url.rfind('@') {
19
+
Some(idx) => {
20
+
let (repo, version) = url.split_at(idx);
21
+
let version = &version[1..];
22
+
match version == repo_name {
23
+
true => (url.to_string(), None),
24
+
false => (repo.to_string(), Some(version.to_string())),
25
+
}
26
+
}
27
+
None => (url.to_string(), None),
28
+
}
29
+
}
30
+
31
+
#[cfg(test)]
32
+
mod tests {
33
+
34
+
use super::*;
35
+
36
+
#[test]
37
+
fn test_extract_repo_name() {
38
+
let url = "https://github.com/tsirysndr/pkgs.git";
39
+
let expected = Some("tsirysndr-pkgs".into());
40
+
let result = extract_repo_name(url);
41
+
assert_eq!(result, expected);
42
+
}
43
+
44
+
#[test]
45
+
fn test_extract_repo_name_no_git() {
46
+
let url = "https://github.com/tsirysndr/pkgs";
47
+
let expected = Some("tsirysndr-pkgs".into());
48
+
let result = extract_repo_name(url);
49
+
assert_eq!(result, expected);
50
+
}
51
+
52
+
#[test]
53
+
fn test_extract_repo_name_invalid_url() {
54
+
let url = "invalid-url";
55
+
let expected = None;
56
+
let result = extract_repo_name(url);
57
+
assert_eq!(result, expected);
58
+
}
59
+
}
+2
-1
src/main.rs
+2
-1
src/main.rs